1use cairo_lang_debug::DebugWithDb;
2use cairo_lang_defs as defs;
3use cairo_lang_defs::ids::{
4 NamedLanguageElementId, TopLevelLanguageElementId, TraitFunctionId, UnstableSalsaId,
5};
6use cairo_lang_diagnostics::{DiagnosticAdded, DiagnosticNote, Maybe};
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, TypeId, TypeLongId};
14use cairo_lang_syntax::node::ast::ExprPtr;
15use cairo_lang_syntax::node::kind::SyntaxKind;
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::Location;
27use crate::db::LoweringGroup;
28use crate::ids::semantic::substitution::SemanticRewriter;
29use crate::specialization::SpecializationArg;
30
31#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::Update, 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<Signature<'db>> {
69 Ok(db.function_with_body_lowering(*self)?.signature.clone())
70 }
71 pub fn to_concrete(&self, db: &'db dyn Database) -> Maybe<ConcreteFunctionWithBodyId<'db>> {
72 Ok(self.long(db).to_concrete(db)?.intern(db))
73 }
74}
75pub trait SemanticFunctionWithBodyIdEx<'db> {
76 fn lowered(&self, db: &'db dyn Database) -> FunctionWithBodyId<'db>;
77}
78impl<'db> SemanticFunctionWithBodyIdEx<'db> for cairo_lang_defs::ids::FunctionWithBodyId<'db> {
79 fn lowered(&self, db: &'db dyn Database) -> FunctionWithBodyId<'db> {
80 FunctionWithBodyLongId::Semantic(*self).intern(db)
81 }
82}
83
84#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::Update, HeapSize)]
86pub enum ConcreteFunctionWithBodyLongId<'db> {
87 Semantic(semantic::ConcreteFunctionWithBodyId<'db>),
88 Generated(GeneratedFunction<'db>),
89 Specialized(SpecializedFunctionId<'db>),
90}
91define_short_id!(ConcreteFunctionWithBodyId, ConcreteFunctionWithBodyLongId<'db>);
92
93pub enum GenericOrSpecialized<'db> {
95 Generic(FunctionWithBodyId<'db>),
96 Specialized(SpecializedFunctionId<'db>),
97}
98
99impl<'db> ConcreteFunctionWithBodyId<'db> {
100 pub fn is_panic_destruct_fn(&self, db: &'db dyn Database) -> Maybe<bool> {
101 match self.long(db) {
102 ConcreteFunctionWithBodyLongId::Semantic(semantic_func) => {
103 semantic_func.is_panic_destruct_fn(db)
104 }
105 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction {
106 parent: _,
107 key: GeneratedFunctionKey::TraitFunc(function, _),
108 }) => Ok(function == &db.core_info().panic_destruct_fn),
109 _ => Ok(false),
110 }
111 }
112
113 pub fn generic_or_specialized(&self, db: &'db dyn Database) -> GenericOrSpecialized<'db> {
116 self.long(db).clone().generic_or_specialized(db)
117 }
118}
119
120impl<'db> UnstableSalsaId for ConcreteFunctionWithBodyId<'db> {
121 fn get_internal_id(&self) -> salsa::Id {
122 self.as_intern_id()
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 match self {
181 ConcreteFunctionWithBodyLongId::Semantic(semantic) => semantic.full_path(db),
182 ConcreteFunctionWithBodyLongId::Generated(generated) => generated.full_path(db),
183 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
184 specialized.long(db).full_path(db)
185 }
186 }
187 }
188}
189impl<'db> ConcreteFunctionWithBodyId<'db> {
190 pub fn from_semantic(
191 db: &'db dyn Database,
192 semantic: semantic::ConcreteFunctionWithBodyId<'db>,
193 ) -> Self {
194 ConcreteFunctionWithBodyLongId::Semantic(semantic).intern(db)
195 }
196 pub fn substitution(&self, db: &'db dyn Database) -> Maybe<GenericSubstitution<'db>> {
197 self.long(db).substitution(db)
198 }
199 pub fn function_id(&self, db: &'db dyn Database) -> Maybe<FunctionId<'db>> {
200 self.long(db).function_id(db)
201 }
202 pub fn full_path(&self, db: &dyn Database) -> String {
203 self.long(db).full_path(db)
204 }
205 pub fn signature(&self, db: &'db dyn Database) -> Maybe<Signature<'db>> {
206 match self.generic_or_specialized(db) {
207 GenericOrSpecialized::Generic(id) => {
208 let generic_signature = id.signature(db)?;
209 self.substitution(db)?.substitute(db, generic_signature)
210 }
211 GenericOrSpecialized::Specialized(specialized) => specialized.long(db).signature(db),
212 }
213 }
214 pub fn from_no_generics_free(
215 db: &'db dyn Database,
216 free_function_id: FreeFunctionId<'db>,
217 ) -> Option<Self> {
218 let semantic =
219 semantic::ConcreteFunctionWithBodyId::from_no_generics_free(db, free_function_id)?;
220 Some(ConcreteFunctionWithBodyLongId::Semantic(semantic).intern(db))
221 }
222 pub fn base_semantic_function(
223 &self,
224 db: &'db dyn Database,
225 ) -> semantic::ConcreteFunctionWithBodyId<'db> {
226 self.long(db).base_semantic_function(db)
227 }
228 pub fn stable_location(&self, db: &'db dyn Database) -> Maybe<StableLocation<'db>> {
229 Ok(match self.long(db) {
230 ConcreteFunctionWithBodyLongId::Semantic(id) => id.stable_location(db),
231 ConcreteFunctionWithBodyLongId::Generated(generated) => match generated.key {
232 GeneratedFunctionKey::Loop(stable_ptr) => StableLocation::new(stable_ptr.untyped()),
233 GeneratedFunctionKey::TraitFunc(_, stable_location) => stable_location,
234 },
235 ConcreteFunctionWithBodyLongId::Specialized(specialized_function) => {
236 specialized_function.long(db).base.stable_location(db)?
237 }
238 })
239 }
240}
241
242#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::Update, HeapSize)]
244pub enum FunctionLongId<'db> {
245 Semantic(semantic::FunctionId<'db>),
247 Generated(GeneratedFunction<'db>),
249 Specialized(SpecializedFunctionId<'db>),
251}
252define_short_id!(FunctionId, FunctionLongId<'db>);
253impl<'db> FunctionLongId<'db> {
254 pub fn body(&self, db: &'db dyn Database) -> Maybe<Option<ConcreteFunctionWithBodyId<'db>>> {
255 Ok(Some(match self {
256 FunctionLongId::Semantic(id) => {
257 let concrete_function = id.get_concrete(db);
258 if let GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }) =
259 concrete_function.generic_function
260 && let ImplLongId::GeneratedImpl(imp) = impl_id.long(db)
261 {
262 let concrete_trait = imp.concrete_trait(db);
263 let info = db.core_info();
264 assert!(
265 [info.destruct_fn, info.panic_destruct_fn, info.call_fn, info.call_once_fn]
266 .contains(&function)
267 );
268
269 let generic_args = concrete_trait.generic_args(db);
270 let Some(GenericArgumentId::Type(ty)) = generic_args.first() else {
271 unreachable!("Expected Generated Impl to have a type argument");
272 };
273 let TypeLongId::Closure(ty) = ty.long(db) else {
274 unreachable!("Expected Generated Impl to have a closure type argument");
275 };
276
277 let Some(parent) = ty.parent_function?.get_concrete(db).body(db)? else {
278 return Ok(None);
279 };
280 return Ok(Some(
281 GeneratedFunction {
282 parent,
283 key: GeneratedFunctionKey::TraitFunc(function, ty.params_location),
284 }
285 .body(db),
286 ));
287 }
288
289 let Some(body) = concrete_function.body(db)? else {
290 return Ok(None);
291 };
292 ConcreteFunctionWithBodyLongId::Semantic(body).intern(db)
293 }
294 FunctionLongId::Generated(generated) => generated.body(db),
295 FunctionLongId::Specialized(specialized) => {
296 ConcreteFunctionWithBodyLongId::Specialized(*specialized).intern(db)
297 }
298 }))
299 }
300 pub fn signature(&self, db: &'db dyn Database) -> Maybe<Signature<'db>> {
301 match self {
302 FunctionLongId::Semantic(semantic) => Ok(EnrichedSemanticSignature::from_semantic(
303 db,
304 db.concrete_function_signature(*semantic)?,
305 )
306 .into()),
307 FunctionLongId::Generated(generated) => generated.body(db).signature(db),
308 FunctionLongId::Specialized(specialized) => specialized.long(db).signature(db),
309 }
310 }
311 pub fn full_path(&self, db: &dyn Database) -> String {
312 format!("{:?}", self.debug(db))
313 }
314 pub fn semantic_full_path(&self, db: &dyn Database) -> String {
318 match self {
319 FunctionLongId::Semantic(id) => id.full_path(db),
320 FunctionLongId::Generated(generated) => generated.parent.full_path(db),
321 FunctionLongId::Specialized(specialized) => specialized.long(db).full_path(db),
322 }
323 }
324}
325impl<'db> FunctionId<'db> {
326 pub fn body(&self, db: &'db dyn Database) -> Maybe<Option<ConcreteFunctionWithBodyId<'db>>> {
327 self.long(db).body(db)
328 }
329 pub fn signature(&self, db: &'db dyn Database) -> Maybe<Signature<'db>> {
330 self.long(db).signature(db)
331 }
332 pub fn full_path(&self, db: &dyn Database) -> String {
333 self.long(db).full_path(db)
334 }
335 pub fn semantic_full_path(&self, db: &dyn Database) -> String {
336 self.long(db).semantic_full_path(db)
337 }
338 pub fn get_extern(
341 &self,
342 db: &'db dyn Database,
343 ) -> Option<(ExternFunctionId<'db>, Vec<GenericArgumentId<'db>>)> {
344 let semantic = try_extract_matches!(self.long(db), FunctionLongId::Semantic)?;
345 let concrete = semantic.get_concrete(db);
346 Some((
347 try_extract_matches!(concrete.generic_function, GenericFunctionId::Extern)?,
348 concrete.generic_args,
349 ))
350 }
351}
352pub trait SemanticFunctionIdEx<'db> {
353 fn lowered(&self, db: &'db dyn Database) -> FunctionId<'db>;
354}
355impl<'db> SemanticFunctionIdEx<'db> for semantic::FunctionId<'db> {
356 fn lowered(&self, db: &'db dyn Database) -> FunctionId<'db> {
357 let ret = FunctionLongId::Semantic(*self).intern(db);
358 if let Ok(Some(body)) = ret.body(db)
362 && let Ok(id) = body.function_id(db)
363 {
364 return id;
365 }
366 ret
367 }
368}
369impl<'a> DebugWithDb<'a> for FunctionLongId<'a> {
370 type Db = dyn Database;
371 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'a dyn Database) -> std::fmt::Result {
372 match self {
373 FunctionLongId::Semantic(semantic) => write!(f, "{:?}", semantic.debug(db)),
374 FunctionLongId::Generated(generated) => write!(f, "{:?}", generated.debug(db)),
375 FunctionLongId::Specialized(specialized) => write!(f, "{:?}", specialized.debug(db)),
376 }
377 }
378}
379
380#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HeapSize, salsa::Update)]
382pub enum GeneratedFunctionKey<'db> {
383 Loop(ExprPtr<'db>),
385 TraitFunc(TraitFunctionId<'db>, StableLocation<'db>),
386}
387
388#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, salsa::Update, HeapSize)]
390pub struct GeneratedFunction<'db> {
391 pub parent: semantic::ConcreteFunctionWithBodyId<'db>,
392 pub key: GeneratedFunctionKey<'db>,
393}
394impl<'db> GeneratedFunction<'db> {
395 pub fn body(&self, db: &'db dyn Database) -> ConcreteFunctionWithBodyId<'db> {
396 let long_id = ConcreteFunctionWithBodyLongId::Generated(*self);
397 long_id.intern(db)
398 }
399 pub fn full_path(&self, db: &dyn Database) -> String {
400 format!("{:?}", self.debug(db))
401 }
402}
403impl<'a> DebugWithDb<'a> for GeneratedFunction<'a> {
404 type Db = dyn Database;
405 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'a dyn Database) -> std::fmt::Result {
406 match self.key {
407 GeneratedFunctionKey::Loop(expr_ptr) => {
408 let mut func_ptr = expr_ptr.untyped();
409 while !matches!(
410 func_ptr.kind(db),
411 SyntaxKind::FunctionWithBody | SyntaxKind::TraitItemFunction
412 ) {
413 func_ptr = func_ptr.parent(db)
414 }
415
416 let span = expr_ptr.0.lookup(db).span(db);
417 let function_start = func_ptr.lookup(db).span(db).start.as_u32();
418 write!(
419 f,
420 "{:?}[{}-{}]",
421 self.parent.debug(db),
422 span.start.as_u32() - function_start,
423 span.end.as_u32() - function_start
424 )
425 }
426 GeneratedFunctionKey::TraitFunc(trait_func, loc) => {
427 let trait_id = trait_func.trait_id(db);
428 write!(
429 f,
430 "Generated `{}::{}` for {{closure@{:?}}}",
431 trait_id.full_path(db),
432 trait_func.name(db).long(db),
433 loc.debug(db),
434 )
435 }
436 }
437 }
438}
439
440#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::Update, HeapSize)]
448pub struct SpecializedFunction<'db> {
449 pub base: crate::ids::ConcreteFunctionWithBodyId<'db>,
451 pub args: Vec<SpecializationArg<'db>>,
453}
454define_short_id!(SpecializedFunctionId, SpecializedFunction<'db>);
455
456impl<'db> SpecializedFunction<'db> {
457 pub fn full_path(&self, db: &dyn Database) -> String {
458 format!("{:?}", self.debug(db))
459 }
460
461 pub fn signature(&self, db: &'db dyn Database) -> Maybe<Signature<'db>> {
462 let mut base_sign = self.base.signature(db)?;
463
464 let mut params = vec![];
465 let mut stack = vec![];
466 for (param, arg) in zip_eq(base_sign.params.iter().rev(), self.args.iter().rev()) {
467 stack.push((param.clone(), arg));
468 }
469
470 while let Some((param, arg)) = stack.pop() {
471 match arg {
472 SpecializationArg::Const { .. } => {}
473 SpecializationArg::Snapshot(inner) => {
474 let desnap_ty = *extract_matches!(param.ty.long(db), TypeLongId::Snapshot);
475 stack.push((
476 LoweredParam { ty: desnap_ty, stable_ptr: param.stable_ptr },
477 inner.as_ref(),
478 ));
479 }
480 SpecializationArg::Enum { variant, payload } => {
481 let lowered_param =
482 LoweredParam { ty: variant.ty, stable_ptr: param.stable_ptr };
483 stack.push((lowered_param, payload.as_ref()));
484 }
485 SpecializationArg::Array(ty, values) => {
486 for arg in values.iter().rev() {
487 let lowered_param = LoweredParam { ty: *ty, stable_ptr: param.stable_ptr };
488 stack.push((lowered_param, arg));
489 }
490 }
491 SpecializationArg::Struct(specialization_args) => {
492 let element_types: Vec<TypeId<'db>> = match param.ty.long(db) {
494 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct)) => {
495 let Ok(members) = db.concrete_struct_members(*concrete_struct) else {
496 continue;
497 };
498 members.values().map(|member| member.ty).collect()
499 }
500 TypeLongId::Tuple(element_types) => element_types.clone(),
501 TypeLongId::FixedSizeArray { type_id, .. } => {
502 vec![*type_id; specialization_args.len()]
503 }
504 _ => unreachable!("Expected a struct, tuple, or fixed-size array type"),
505 };
506 for (elem_ty, arg) in
507 zip_eq(element_types.iter().rev(), specialization_args.iter().rev())
508 {
509 let lowered_param =
510 LoweredParam { ty: *elem_ty, stable_ptr: param.stable_ptr };
511 stack.push((lowered_param, arg));
512 }
513 }
514 SpecializationArg::NotSpecialized => {
515 params.push(param.clone());
516 }
517 }
518 }
519
520 base_sign.params = params;
521
522 Ok(base_sign)
523 }
524}
525impl<'a> DebugWithDb<'a> for SpecializedFunction<'a> {
526 type Db = dyn Database;
527 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'a dyn Database) -> std::fmt::Result {
528 write!(f, "{}{{", self.base.full_path(db))?;
529 for arg in self.args.iter() {
530 write!(f, "{:?}, ", arg.debug(db))?;
531 }
532 write!(f, "}}")
533 }
534}
535
536#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::Update)]
538#[debug_db(dyn Database)]
539pub struct EnrichedSemanticSignature<'db> {
540 pub params: Vec<semantic::ExprVarMemberPath<'db>>,
542 pub extra_rets: Vec<semantic::ExprVarMemberPath<'db>>,
544 pub return_type: semantic::TypeId<'db>,
546 pub implicits: Vec<semantic::TypeId<'db>>,
548 #[dont_rewrite]
550 pub panicable: bool,
551 #[dont_rewrite]
553 #[hide_field_debug_with_db]
554 pub location: LocationId<'db>,
555}
556impl<'db> EnrichedSemanticSignature<'db> {
557 pub fn from_semantic(db: &'db dyn Database, value: &semantic::Signature<'db>) -> Self {
558 let semantic::Signature {
559 params,
560 return_type,
561 implicits,
562 panicable,
563 stable_ptr,
564 is_const: _,
565 } = value;
566 let ref_params = params
567 .iter()
568 .filter(|param| param.mutability == Mutability::Reference)
569 .map(|param| parameter_as_member_path(param.clone()))
570 .collect();
571 let params: Vec<semantic::ExprVarMemberPath<'_>> =
572 params.iter().cloned().map(parameter_as_member_path).collect();
573 Self {
574 params,
575 extra_rets: ref_params,
576 return_type: *return_type,
577 implicits: implicits.clone(),
578 panicable: *panicable,
579 location: LocationId::from_stable_location(
580 db,
581 StableLocation::new(stable_ptr.untyped()),
582 ),
583 }
584 }
585 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
586 self.params.iter().all(|param| param.ty().is_fully_concrete(db))
587 && self.extra_rets.iter().all(|param| param.ty().is_fully_concrete(db))
588 && self.return_type.is_fully_concrete(db)
589 && self.implicits.iter().all(|ty| ty.is_fully_concrete(db))
590 }
591}
592semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, EnrichedSemanticSignature<'a>);
593
594#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::Update)]
595#[debug_db(dyn Database)]
596pub struct LoweredParam<'db> {
598 pub ty: semantic::TypeId<'db>,
599 #[dont_rewrite]
600 pub stable_ptr: ast::ExprPtr<'db>,
601}
602semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, LoweredParam<'a>);
603
604#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::Update)]
606#[debug_db(dyn Database)]
607pub struct Signature<'db> {
608 pub params: Vec<LoweredParam<'db>>, pub extra_rets: Vec<semantic::ExprVarMemberPath<'db>>,
612 pub return_type: semantic::TypeId<'db>,
614 pub implicits: Vec<semantic::TypeId<'db>>,
616 #[dont_rewrite]
618 pub panicable: bool,
619 #[dont_rewrite]
621 #[hide_field_debug_with_db]
622 pub location: LocationId<'db>,
623}
624semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, Signature<'a>);
625
626impl<'db> From<EnrichedSemanticSignature<'db>> for Signature<'db> {
627 fn from(signature: EnrichedSemanticSignature<'db>) -> Self {
628 Signature {
629 params: signature
630 .params
631 .iter()
632 .map(|param| LoweredParam { ty: param.ty(), stable_ptr: param.stable_ptr() })
633 .collect(),
634 extra_rets: signature.extra_rets,
635 return_type: signature.return_type,
636 implicits: signature.implicits,
637 panicable: signature.panicable,
638 location: signature.location,
639 }
640 }
641}
642
643pub(crate) fn parameter_as_member_path<'db>(
645 param: semantic::Parameter<'db>,
646) -> semantic::ExprVarMemberPath<'db> {
647 let semantic::Parameter { id, ty, stable_ptr, .. } = param;
648 semantic::ExprVarMemberPath::Var(ExprVar {
649 var: semantic::VarId::Param(id),
650 ty,
651 stable_ptr: ast::ExprPtr(stable_ptr.0),
652 })
653}
654
655define_short_id!(LocationId, Location<'db>);
656impl<'db> LocationId<'db> {
657 pub fn from_stable_location(
658 db: &'db dyn Database,
659 stable_location: StableLocation<'db>,
660 ) -> LocationId<'db> {
661 Location::new(stable_location).intern(db)
662 }
663
664 pub fn with_note(&self, db: &'db dyn Database, note: DiagnosticNote<'db>) -> LocationId<'db> {
666 self.long(db).clone().with_note(note).intern(db)
667 }
668
669 pub fn with_auto_generation_note(
671 &self,
672 db: &'db dyn Database,
673 logic_name: &str,
674 ) -> LocationId<'db> {
675 self.with_note(
676 db,
677 DiagnosticNote::text_only(format!(
678 "this error originates in auto-generated {logic_name} logic."
679 )),
680 )
681 }
682}