1use std::iter::repeat;
2
3use cairo_lang_debug::DebugWithDb;
4use cairo_lang_defs as defs;
5use cairo_lang_defs::ids::{NamedLanguageElementId, TopLevelLanguageElementId, TraitFunctionId};
6use cairo_lang_diagnostics::{DiagnosticAdded, DiagnosticNote, Maybe, MaybeAsRef};
7use cairo_lang_proc_macros::{DebugWithDb, HeapSize, SemanticObject};
8use cairo_lang_semantic as semantic;
9use cairo_lang_semantic::corelib::CorelibSemantic;
10use cairo_lang_semantic::items::functions::{FunctionsSemantic, ImplGenericFunctionId};
11use cairo_lang_semantic::items::imp::ImplLongId;
12use cairo_lang_semantic::items::structure::StructSemantic;
13use cairo_lang_semantic::{ConcreteTypeId, GenericArgumentId, TypeLongId};
14use cairo_lang_syntax::node::ast::ExprPtr;
15use cairo_lang_syntax::node::helpers::generated_function_path;
16use cairo_lang_syntax::node::{TypedStablePtr, ast};
17use cairo_lang_utils::{Intern, define_short_id, extract_matches, try_extract_matches};
18use defs::diagnostic_utils::StableLocation;
19use defs::ids::{ExternFunctionId, FreeFunctionId};
20use itertools::zip_eq;
21use salsa::Database;
22use semantic::items::functions::GenericFunctionId;
23use semantic::substitution::{GenericSubstitution, SubstitutionRewriter};
24use semantic::{ExprVar, Mutability};
25
26use crate::db::LoweringGroup;
27use crate::ids::semantic::substitution::SemanticRewriter;
28use crate::specialization::SpecializationArg;
29use crate::{Location, LoweringStage};
30
31#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::SalsaValue, HeapSize)]
32pub enum FunctionWithBodyLongId<'db> {
33 Semantic(defs::ids::FunctionWithBodyId<'db>),
34 Generated { parent: defs::ids::FunctionWithBodyId<'db>, key: GeneratedFunctionKey<'db> },
35}
36define_short_id!(FunctionWithBodyId, FunctionWithBodyLongId<'db>);
37impl<'db> FunctionWithBodyLongId<'db> {
38 pub fn base_semantic_function(
39 &self,
40 _db: &'db dyn Database,
41 ) -> cairo_lang_defs::ids::FunctionWithBodyId<'db> {
42 match self {
43 FunctionWithBodyLongId::Semantic(id) => *id,
44 FunctionWithBodyLongId::Generated { parent, .. } => *parent,
45 }
46 }
47 pub fn to_concrete(&self, db: &'db dyn Database) -> Maybe<ConcreteFunctionWithBodyLongId<'db>> {
48 Ok(match self {
49 FunctionWithBodyLongId::Semantic(semantic) => ConcreteFunctionWithBodyLongId::Semantic(
50 semantic::ConcreteFunctionWithBodyId::from_generic(db, *semantic)?,
51 ),
52 FunctionWithBodyLongId::Generated { parent, key } => {
53 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction {
54 parent: semantic::ConcreteFunctionWithBodyId::from_generic(db, *parent)?,
55 key: *key,
56 })
57 }
58 })
59 }
60}
61impl<'db> FunctionWithBodyId<'db> {
62 pub fn base_semantic_function(
63 &self,
64 db: &'db dyn Database,
65 ) -> cairo_lang_defs::ids::FunctionWithBodyId<'db> {
66 self.long(db).base_semantic_function(db)
67 }
68 pub fn signature(&self, db: &'db dyn Database) -> Maybe<&'db Signature<'db>> {
74 Ok(&db.function_with_body_lowering(*self)?.signature)
75 }
76 pub fn to_concrete(&self, db: &'db dyn Database) -> Maybe<ConcreteFunctionWithBodyId<'db>> {
77 Ok(self.long(db).to_concrete(db)?.intern(db))
78 }
79}
80pub trait SemanticFunctionWithBodyIdEx<'db> {
81 fn lowered(&self, db: &'db dyn Database) -> FunctionWithBodyId<'db>;
82}
83impl<'db> SemanticFunctionWithBodyIdEx<'db> for cairo_lang_defs::ids::FunctionWithBodyId<'db> {
84 fn lowered(&self, db: &'db dyn Database) -> FunctionWithBodyId<'db> {
85 FunctionWithBodyLongId::Semantic(*self).intern(db)
86 }
87}
88
89#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::SalsaValue, HeapSize)]
91pub enum ConcreteFunctionWithBodyLongId<'db> {
92 Semantic(semantic::ConcreteFunctionWithBodyId<'db>),
93 Generated(GeneratedFunction<'db>),
94 Specialized(SpecializedFunctionId<'db>),
95}
96define_short_id!(ConcreteFunctionWithBodyId, ConcreteFunctionWithBodyLongId<'db>);
97
98pub enum GenericOrSpecialized<'db> {
100 Generic(FunctionWithBodyId<'db>),
101 Specialized(SpecializedFunctionId<'db>),
102}
103
104impl<'db> ConcreteFunctionWithBodyId<'db> {
105 pub fn is_panic_destruct_fn(&self, db: &'db dyn Database) -> Maybe<bool> {
106 match self.long(db) {
107 ConcreteFunctionWithBodyLongId::Semantic(semantic_func) => {
108 semantic_func.is_panic_destruct_fn(db)
109 }
110 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction {
111 parent: _,
112 key: GeneratedFunctionKey::TraitFunc(function, _),
113 }) => Ok(function == &db.core_info().panic_destruct_fn),
114 _ => Ok(false),
115 }
116 }
117
118 pub fn generic_or_specialized(&self, db: &'db dyn Database) -> GenericOrSpecialized<'db> {
121 self.long(db).clone().generic_or_specialized(db)
122 }
123}
124
125impl<'db> ConcreteFunctionWithBodyLongId<'db> {
126 pub fn generic_or_specialized(self, db: &'db dyn Database) -> GenericOrSpecialized<'db> {
129 let long_id = match self {
130 ConcreteFunctionWithBodyLongId::Semantic(id) => {
131 FunctionWithBodyLongId::Semantic(id.function_with_body_id(db))
132 }
133 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction { parent, key }) => {
134 FunctionWithBodyLongId::Generated { parent: parent.function_with_body_id(db), key }
135 }
136 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
137 return GenericOrSpecialized::Specialized(specialized);
138 }
139 };
140 GenericOrSpecialized::Generic(long_id.intern(db))
141 }
142 pub fn substitution(&self, db: &'db dyn Database) -> Maybe<GenericSubstitution<'db>> {
143 match self {
144 ConcreteFunctionWithBodyLongId::Semantic(id) => id.substitution(db),
145 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction { parent, .. }) => {
146 parent.substitution(db)
147 }
148 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
149 specialized.long(db).base.substitution(db)
150 }
151 }
152 }
153 pub fn function_id(&self, db: &'db dyn Database) -> Maybe<FunctionId<'db>> {
154 let long_id = match self {
155 ConcreteFunctionWithBodyLongId::Semantic(id) => {
156 FunctionLongId::Semantic(id.function_id(db)?)
157 }
158 ConcreteFunctionWithBodyLongId::Generated(generated) => {
159 FunctionLongId::Generated(*generated)
160 }
161 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
162 FunctionLongId::Specialized(*specialized)
163 }
164 };
165 Ok(long_id.intern(db))
166 }
167 pub fn base_semantic_function(
168 &self,
169 db: &'db dyn Database,
170 ) -> semantic::ConcreteFunctionWithBodyId<'db> {
171 match self {
172 ConcreteFunctionWithBodyLongId::Semantic(id) => *id,
173 ConcreteFunctionWithBodyLongId::Generated(generated) => generated.parent,
174 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
175 specialized.long(db).base.base_semantic_function(db)
176 }
177 }
178 }
179 pub fn full_path(&self, db: &dyn Database) -> String {
180 format!("{:?}", self.debug(db))
181 }
182}
183impl<'db> DebugWithDb<'db> for ConcreteFunctionWithBodyLongId<'db> {
184 type Db = dyn Database;
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
186 match self {
187 ConcreteFunctionWithBodyLongId::Semantic(semantic) => {
188 write!(f, "{:?}", semantic.debug(db))
189 }
190 ConcreteFunctionWithBodyLongId::Generated(generated) => {
191 write!(f, "{:?}", generated.debug(db))
192 }
193 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
194 write!(f, "{:?}", specialized.debug(db))
195 }
196 }
197 }
198}
199impl<'db> ConcreteFunctionWithBodyId<'db> {
200 pub fn from_semantic(
201 db: &'db dyn Database,
202 semantic: semantic::ConcreteFunctionWithBodyId<'db>,
203 ) -> Self {
204 ConcreteFunctionWithBodyLongId::Semantic(semantic).intern(db)
205 }
206 pub fn substitution(&self, db: &'db dyn Database) -> Maybe<GenericSubstitution<'db>> {
207 self.long(db).substitution(db)
208 }
209 pub fn function_id(&self, db: &'db dyn Database) -> Maybe<FunctionId<'db>> {
210 self.long(db).function_id(db)
211 }
212 pub fn full_path(&self, db: &dyn Database) -> String {
213 self.long(db).full_path(db)
214 }
215 pub fn signature(
217 &self,
218 db: &'db dyn Database,
219 stage: LoweringStage,
220 ) -> Maybe<&'db Signature<'db>> {
221 if stage != LoweringStage::Monomorphized {
222 return Ok(&db.lowered_body(*self, stage)?.signature);
223 }
224 monomorphized_signature(db, *self).maybe_as_ref()
226 }
227 pub fn generic(&self, db: &'db dyn Database) -> Option<FunctionWithBodyId<'db>> {
229 match self.generic_or_specialized(db) {
230 GenericOrSpecialized::Generic(id) => Some(id),
231 GenericOrSpecialized::Specialized(_) => None,
232 }
233 }
234 pub fn from_no_generics_free(
235 db: &'db dyn Database,
236 free_function_id: FreeFunctionId<'db>,
237 ) -> Option<Self> {
238 let semantic =
239 semantic::ConcreteFunctionWithBodyId::from_no_generics_free(db, free_function_id)?;
240 Some(ConcreteFunctionWithBodyLongId::Semantic(semantic).intern(db))
241 }
242 pub fn base_semantic_function(
243 &self,
244 db: &'db dyn Database,
245 ) -> semantic::ConcreteFunctionWithBodyId<'db> {
246 self.long(db).base_semantic_function(db)
247 }
248 pub fn stable_location(&self, db: &'db dyn Database) -> Maybe<StableLocation<'db>> {
249 Ok(match self.long(db) {
250 ConcreteFunctionWithBodyLongId::Semantic(id) => id.stable_location(db),
251 ConcreteFunctionWithBodyLongId::Generated(generated) => match generated.key {
252 GeneratedFunctionKey::Loop(stable_ptr) => StableLocation::new(stable_ptr.untyped()),
253 GeneratedFunctionKey::TraitFunc(_, stable_location) => stable_location,
254 },
255 ConcreteFunctionWithBodyLongId::Specialized(specialized_function) => {
256 specialized_function.long(db).base.stable_location(db)?
257 }
258 })
259 }
260}
261
262#[salsa::tracked(returns(ref))]
266fn monomorphized_signature<'db>(
267 db: &'db dyn Database,
268 function: ConcreteFunctionWithBodyId<'db>,
269) -> Maybe<Signature<'db>> {
270 match function.generic_or_specialized(db) {
271 GenericOrSpecialized::Generic(id) => {
272 let generic_signature = id.signature(db)?.clone();
273 function.substitution(db)?.substitute(db, generic_signature)
274 }
275 GenericOrSpecialized::Specialized(specialized) => {
276 let function = specialized.long(db);
277 let mut base_sign = function.base.signature(db, LoweringStage::Monomorphized)?.clone();
278
279 let mut params = vec![];
280 let mut stack: Vec<_> =
281 zip_eq(base_sign.params.into_iter().rev(), function.args.iter().rev()).collect();
282
283 while let Some((param_ty, arg)) = stack.pop() {
284 match arg {
285 SpecializationArg::Const { .. } => {}
286 SpecializationArg::Snapshot(inner) => {
287 let desnap_ty = *extract_matches!(param_ty.long(db), TypeLongId::Snapshot);
288 stack.push((desnap_ty, inner.as_ref()));
289 }
290 SpecializationArg::Enum { variant, payload } => {
291 stack.push((variant.ty, payload.as_ref()));
292 }
293 SpecializationArg::Array(ty, values) => {
294 stack.extend(repeat(*ty).zip(values.iter().rev()));
295 }
296 SpecializationArg::Struct(args) => match param_ty.long(db) {
297 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct)) => {
298 let Ok(members) = db.concrete_struct_members(*concrete_struct) else {
299 continue;
300 };
301 let tys = members.values().map(|m| m.ty);
302 stack.extend(zip_eq(tys.rev(), args.iter().rev()));
303 }
304 TypeLongId::Tuple(tys) => {
305 stack.extend(zip_eq(tys.iter().rev().copied(), args.iter().rev()));
306 }
307 TypeLongId::FixedSizeArray { type_id, .. } => {
308 stack.extend(repeat(*type_id).zip(args.iter().rev()));
309 }
310 _ => unreachable!("Expected a struct, tuple, or fixed-size array type"),
311 },
312 SpecializationArg::NotSpecialized => {
313 params.push(param_ty);
314 }
315 }
316 }
317
318 base_sign.params = params;
319
320 Ok(base_sign)
321 }
322 }
323}
324
325#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::SalsaValue, HeapSize)]
327pub enum FunctionLongId<'db> {
328 Semantic(semantic::FunctionId<'db>),
330 Generated(GeneratedFunction<'db>),
332 Specialized(SpecializedFunctionId<'db>),
334}
335define_short_id!(FunctionId, FunctionLongId<'db>);
336impl<'db> FunctionLongId<'db> {
337 pub fn body(&self, db: &'db dyn Database) -> Maybe<Option<ConcreteFunctionWithBodyId<'db>>> {
338 Ok(Some(match self {
339 FunctionLongId::Semantic(id) => {
340 let concrete_function = id.get_concrete(db);
341 if let GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }) =
342 concrete_function.generic_function
343 && let ImplLongId::GeneratedImpl(imp) = impl_id.long(db)
344 {
345 let concrete_trait = imp.concrete_trait(db);
346 let info = db.core_info();
347 assert!(
348 [info.destruct_fn, info.panic_destruct_fn, info.call_fn, info.call_once_fn]
349 .contains(&function)
350 );
351
352 let generic_args = concrete_trait.generic_args(db);
353 let Some(GenericArgumentId::Type(ty)) = generic_args.first() else {
354 unreachable!("Expected Generated Impl to have a type argument");
355 };
356 let TypeLongId::Closure(ty) = ty.long(db) else {
357 unreachable!("Expected Generated Impl to have a closure type argument");
358 };
359
360 let Some(parent) = ty.parent_function?.get_concrete(db).body(db)? else {
361 return Ok(None);
362 };
363 return Ok(Some(
364 GeneratedFunction {
365 parent,
366 key: GeneratedFunctionKey::TraitFunc(function, ty.params_location),
367 }
368 .body(db),
369 ));
370 }
371
372 let Some(body) = concrete_function.body(db)? else {
373 return Ok(None);
374 };
375 ConcreteFunctionWithBodyLongId::Semantic(body).intern(db)
376 }
377 FunctionLongId::Generated(generated) => generated.body(db),
378 FunctionLongId::Specialized(specialized) => {
379 ConcreteFunctionWithBodyLongId::Specialized(*specialized).intern(db)
380 }
381 }))
382 }
383 pub fn signature(
385 &self,
386 db: &'db dyn Database,
387 stage: LoweringStage,
388 ) -> Maybe<&'db Signature<'db>> {
389 if let Some(body) = self.body(db)? {
390 body.signature(db, stage)
391 } else if let FunctionLongId::Semantic(semantic) = self {
392 semantic_function_signature(db, *semantic).maybe_as_ref()
393 } else {
394 unreachable!(
395 "Generated and specialized functions always have a body: {}",
396 self.full_path(db)
397 );
398 }
399 }
400 pub fn full_path(&self, db: &dyn Database) -> String {
401 format!("{:?}", self.debug(db))
402 }
403 pub fn semantic_full_path(&self, db: &dyn Database) -> String {
407 match self {
408 FunctionLongId::Semantic(id) => id.full_path(db),
409 FunctionLongId::Generated(generated) => generated.parent.full_path(db),
410 FunctionLongId::Specialized(specialized) => specialized.long(db).full_path(db),
411 }
412 }
413}
414
415#[salsa::tracked(returns(ref))]
418fn semantic_function_signature<'db>(
419 db: &'db dyn Database,
420 function: semantic::FunctionId<'db>,
421) -> Maybe<Signature<'db>> {
422 Ok(EnrichedSemanticSignature::from_semantic(db, db.concrete_function_signature(function)?)
423 .into())
424}
425impl<'db> FunctionId<'db> {
426 pub fn body(&self, db: &'db dyn Database) -> Maybe<Option<ConcreteFunctionWithBodyId<'db>>> {
427 self.long(db).body(db)
428 }
429 pub fn signature(
430 &self,
431 db: &'db dyn Database,
432 stage: LoweringStage,
433 ) -> Maybe<&'db Signature<'db>> {
434 self.long(db).signature(db, stage)
435 }
436 pub fn full_path(&self, db: &dyn Database) -> String {
437 self.long(db).full_path(db)
438 }
439 pub fn semantic_full_path(&self, db: &dyn Database) -> String {
440 self.long(db).semantic_full_path(db)
441 }
442 pub fn get_extern(
445 &self,
446 db: &'db dyn Database,
447 ) -> Option<(ExternFunctionId<'db>, Vec<GenericArgumentId<'db>>)> {
448 let semantic = try_extract_matches!(self.long(db), FunctionLongId::Semantic)?;
449 let concrete = semantic.get_concrete(db);
450 Some((
451 try_extract_matches!(concrete.generic_function, GenericFunctionId::Extern)?,
452 concrete.generic_args,
453 ))
454 }
455}
456pub trait SemanticFunctionIdEx<'db> {
457 fn lowered(&self, db: &'db dyn Database) -> FunctionId<'db>;
458}
459impl<'db> SemanticFunctionIdEx<'db> for semantic::FunctionId<'db> {
460 fn lowered(&self, db: &'db dyn Database) -> FunctionId<'db> {
461 let ret = FunctionLongId::Semantic(*self).intern(db);
462 if let Ok(Some(body)) = ret.body(db)
466 && let Ok(id) = body.function_id(db)
467 {
468 return id;
469 }
470 ret
471 }
472}
473impl<'a> DebugWithDb<'a> for FunctionLongId<'a> {
474 type Db = dyn Database;
475 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'a dyn Database) -> std::fmt::Result {
476 match self {
477 FunctionLongId::Semantic(semantic) => write!(f, "{:?}", semantic.debug(db)),
478 FunctionLongId::Generated(generated) => write!(f, "{:?}", generated.debug(db)),
479 FunctionLongId::Specialized(specialized) => write!(f, "{:?}", specialized.debug(db)),
480 }
481 }
482}
483
484#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HeapSize, salsa::SalsaValue)]
486pub enum GeneratedFunctionKey<'db> {
487 Loop(ExprPtr<'db>),
489 TraitFunc(TraitFunctionId<'db>, StableLocation<'db>),
490}
491
492#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, salsa::SalsaValue, HeapSize)]
494pub struct GeneratedFunction<'db> {
495 pub parent: semantic::ConcreteFunctionWithBodyId<'db>,
496 pub key: GeneratedFunctionKey<'db>,
497}
498impl<'db> GeneratedFunction<'db> {
499 pub fn body(&self, db: &'db dyn Database) -> ConcreteFunctionWithBodyId<'db> {
500 let long_id = ConcreteFunctionWithBodyLongId::Generated(*self);
501 long_id.intern(db)
502 }
503 pub fn full_path(&self, db: &dyn Database) -> String {
504 format!("{:?}", self.debug(db))
505 }
506}
507impl<'a> DebugWithDb<'a> for GeneratedFunction<'a> {
508 type Db = dyn Database;
509 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'a dyn Database) -> std::fmt::Result {
510 match self.key {
511 GeneratedFunctionKey::Loop(expr_ptr) => {
512 write!(
513 f,
514 "{:?}::{}",
515 self.parent.debug(db),
516 generated_function_path(db, expr_ptr.0.lookup(db))
517 )
518 }
519 GeneratedFunctionKey::TraitFunc(trait_func, loc) => {
520 let trait_id = trait_func.trait_id(db);
521 write!(
522 f,
523 "Generated `{}::{}` for {:?}::{}",
524 trait_id.full_path(db),
525 trait_func.name(db).long(db),
526 self.parent.debug(db),
527 generated_function_path(db, loc.syntax_node(db)),
528 )
529 }
530 }
531 }
532}
533
534#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::SalsaValue, HeapSize)]
542pub struct SpecializedFunction<'db> {
543 pub base: crate::ids::ConcreteFunctionWithBodyId<'db>,
545 pub args: Vec<SpecializationArg<'db>>,
547}
548define_short_id!(SpecializedFunctionId, SpecializedFunction<'db>);
549
550impl<'db> SpecializedFunction<'db> {
551 pub fn full_path(&self, db: &dyn Database) -> String {
552 format!("{:?}", self.debug(db))
553 }
554}
555
556impl<'a> DebugWithDb<'a> for SpecializedFunction<'a> {
557 type Db = dyn Database;
558 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'a dyn Database) -> std::fmt::Result {
559 write!(f, "{}{{", self.base.full_path(db))?;
560 for arg in self.args.iter() {
561 write!(f, "{:?}, ", arg.debug(db))?;
562 }
563 write!(f, "}}")
564 }
565}
566
567#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::SalsaValue)]
569#[debug_db(dyn Database)]
570pub struct EnrichedSemanticSignature<'db> {
571 pub params: Vec<semantic::ExprVarMemberPath<'db>>,
573 pub extra_rets: Vec<semantic::ExprVarMemberPath<'db>>,
575 pub return_type: semantic::TypeId<'db>,
577 pub implicits: Vec<semantic::TypeId<'db>>,
579 #[dont_rewrite]
581 pub panicable: bool,
582 #[dont_rewrite]
584 #[hide_field_debug_with_db]
585 pub location: LocationId<'db>,
586}
587impl<'db> EnrichedSemanticSignature<'db> {
588 pub fn from_semantic(db: &'db dyn Database, value: &semantic::Signature<'db>) -> Self {
589 let semantic::Signature {
590 params,
591 return_type,
592 implicits,
593 panicable,
594 stable_ptr,
595 is_const: _,
596 } = value;
597 let ref_params = params
598 .iter()
599 .filter(|param| param.mutability == Mutability::Reference)
600 .map(|param| parameter_as_member_path(param.clone()))
601 .collect();
602 let params: Vec<semantic::ExprVarMemberPath<'_>> =
603 params.iter().cloned().map(parameter_as_member_path).collect();
604 Self {
605 params,
606 extra_rets: ref_params,
607 return_type: *return_type,
608 implicits: implicits.clone(),
609 panicable: *panicable,
610 location: LocationId::from_stable_location(
611 db,
612 StableLocation::new(stable_ptr.untyped()),
613 ),
614 }
615 }
616 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
617 self.params.iter().all(|param| param.ty().is_fully_concrete(db))
618 && self.extra_rets.iter().all(|param| param.ty().is_fully_concrete(db))
619 && self.return_type.is_fully_concrete(db)
620 && self.implicits.iter().all(|ty| ty.is_fully_concrete(db))
621 }
622}
623semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, EnrichedSemanticSignature<'a>);
624
625#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::SalsaValue)]
627#[debug_db(dyn Database)]
628pub struct Signature<'db> {
629 pub params: Vec<semantic::TypeId<'db>>,
631 pub extra_rets: Vec<semantic::TypeId<'db>>,
633 pub return_type: semantic::TypeId<'db>,
635 pub declared_implicits: Vec<semantic::TypeId<'db>>,
640 #[dont_rewrite]
642 pub panicable: bool,
643 #[dont_rewrite]
645 #[hide_field_debug_with_db]
646 pub location: LocationId<'db>,
647}
648semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, Signature<'a>);
649
650impl<'db> From<EnrichedSemanticSignature<'db>> for Signature<'db> {
651 fn from(signature: EnrichedSemanticSignature<'db>) -> Self {
652 Signature {
653 params: signature.params.iter().map(|param| param.ty()).collect(),
654 extra_rets: signature.extra_rets.iter().map(|param| param.ty()).collect(),
655 return_type: signature.return_type,
656 declared_implicits: signature.implicits,
657 panicable: signature.panicable,
658 location: signature.location,
659 }
660 }
661}
662
663pub(crate) fn parameter_as_member_path<'db>(
665 param: semantic::Parameter<'db>,
666) -> semantic::ExprVarMemberPath<'db> {
667 let semantic::Parameter { id, ty, stable_ptr, .. } = param;
668 semantic::ExprVarMemberPath::Var(ExprVar {
669 var: semantic::VarId::Param(id),
670 ty,
671 stable_ptr: ast::ExprPtr(stable_ptr.0),
672 })
673}
674
675define_short_id!(LocationId, Location<'db>);
676impl<'db> LocationId<'db> {
677 pub fn from_stable_location(
678 db: &'db dyn Database,
679 stable_location: StableLocation<'db>,
680 ) -> LocationId<'db> {
681 Location::new(stable_location).intern(db)
682 }
683
684 pub fn with_note(&self, db: &'db dyn Database, note: DiagnosticNote<'db>) -> LocationId<'db> {
686 self.long(db).clone().with_note(note).intern(db)
687 }
688
689 pub fn with_auto_generation_note(
691 &self,
692 db: &'db dyn Database,
693 logic_name: &str,
694 ) -> LocationId<'db> {
695 self.with_note(
696 db,
697 DiagnosticNote::text_only(format!(
698 "this error originates in auto-generated {logic_name} logic."
699 )),
700 )
701 }
702}