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