1use std::sync::Arc;
2
3use cairo_lang_debug::DebugWithDb;
4use cairo_lang_defs::ids::{
5 NamedLanguageElementId, TopLevelLanguageElementId, TraitFunctionId, UnstableSalsaId,
6};
7use cairo_lang_diagnostics::{DiagnosticAdded, DiagnosticNote, Maybe};
8use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
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::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};
25use {cairo_lang_defs as defs, cairo_lang_semantic as semantic};
26
27use crate::Location;
28use crate::db::LoweringGroup;
29use crate::ids::semantic::substitution::SemanticRewriter;
30use crate::specialization::SpecializationArg;
31
32#[derive(Clone, Debug, Hash, PartialEq, Eq)]
33pub enum FunctionWithBodyLongId<'db> {
34 Semantic(defs::ids::FunctionWithBodyId<'db>),
35 Generated { parent: defs::ids::FunctionWithBodyId<'db>, key: GeneratedFunctionKey<'db> },
36}
37define_short_id!(FunctionWithBodyId, FunctionWithBodyLongId<'db>);
38impl<'db> FunctionWithBodyLongId<'db> {
39 pub fn base_semantic_function(
40 &self,
41 _db: &'db dyn Database,
42 ) -> cairo_lang_defs::ids::FunctionWithBodyId<'db> {
43 match self {
44 FunctionWithBodyLongId::Semantic(id) => *id,
45 FunctionWithBodyLongId::Generated { parent, .. } => *parent,
46 }
47 }
48 pub fn to_concrete(&self, db: &'db dyn Database) -> Maybe<ConcreteFunctionWithBodyLongId<'db>> {
49 Ok(match self {
50 FunctionWithBodyLongId::Semantic(semantic) => ConcreteFunctionWithBodyLongId::Semantic(
51 semantic::ConcreteFunctionWithBodyId::from_generic(db, *semantic)?,
52 ),
53 FunctionWithBodyLongId::Generated { parent, key } => {
54 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction {
55 parent: semantic::ConcreteFunctionWithBodyId::from_generic(db, *parent)?,
56 key: *key,
57 })
58 }
59 })
60 }
61}
62impl<'db> FunctionWithBodyId<'db> {
63 pub fn base_semantic_function(
64 &self,
65 db: &'db dyn Database,
66 ) -> cairo_lang_defs::ids::FunctionWithBodyId<'db> {
67 self.long(db).base_semantic_function(db)
68 }
69 pub fn signature(&self, db: &'db dyn Database) -> Maybe<Signature<'db>> {
70 Ok(db.function_with_body_lowering(*self)?.signature.clone())
71 }
72 pub fn to_concrete(&self, db: &'db dyn Database) -> Maybe<ConcreteFunctionWithBodyId<'db>> {
73 Ok(self.long(db).to_concrete(db)?.intern(db))
74 }
75}
76pub trait SemanticFunctionWithBodyIdEx<'db> {
77 fn lowered(&self, db: &'db dyn Database) -> FunctionWithBodyId<'db>;
78}
79impl<'db> SemanticFunctionWithBodyIdEx<'db> for cairo_lang_defs::ids::FunctionWithBodyId<'db> {
80 fn lowered(&self, db: &'db dyn Database) -> FunctionWithBodyId<'db> {
81 FunctionWithBodyLongId::Semantic(*self).intern(db)
82 }
83}
84
85#[derive(Clone, Debug, Hash, PartialEq, Eq)]
87pub enum ConcreteFunctionWithBodyLongId<'db> {
88 Semantic(semantic::ConcreteFunctionWithBodyId<'db>),
89 Generated(GeneratedFunction<'db>),
90 Specialized(SpecializedFunction<'db>),
91}
92define_short_id!(ConcreteFunctionWithBodyId, ConcreteFunctionWithBodyLongId<'db>);
93
94pub enum GenericOrSpecialized<'db> {
96 Generic(FunctionWithBodyId<'db>),
97 Specialized(SpecializedFunction<'db>),
98}
99
100impl<'db> ConcreteFunctionWithBodyId<'db> {
101 pub fn is_panic_destruct_fn(&self, db: &'db dyn Database) -> Maybe<bool> {
102 match self.long(db) {
103 ConcreteFunctionWithBodyLongId::Semantic(semantic_func) => {
104 semantic_func.is_panic_destruct_fn(db)
105 }
106 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction {
107 parent: _,
108 key: GeneratedFunctionKey::TraitFunc(function, _),
109 }) => Ok(function == &db.core_info().panic_destruct_fn),
110 _ => Ok(false),
111 }
112 }
113
114 pub fn generic_or_specialized(&self, db: &'db dyn Database) -> GenericOrSpecialized<'db> {
117 self.long(db).clone().generic_or_specialized(db)
118 }
119}
120
121impl<'db> UnstableSalsaId for ConcreteFunctionWithBodyId<'db> {
122 fn get_internal_id(&self) -> salsa::Id {
123 self.as_intern_id()
124 }
125}
126impl<'db> ConcreteFunctionWithBodyLongId<'db> {
127 pub fn generic_or_specialized(self, db: &'db dyn Database) -> GenericOrSpecialized<'db> {
130 let long_id = match self {
131 ConcreteFunctionWithBodyLongId::Semantic(id) => {
132 FunctionWithBodyLongId::Semantic(id.function_with_body_id(db))
133 }
134 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction { parent, key }) => {
135 FunctionWithBodyLongId::Generated { parent: parent.function_with_body_id(db), key }
136 }
137 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
138 return GenericOrSpecialized::Specialized(specialized);
139 }
140 };
141 GenericOrSpecialized::Generic(long_id.intern(db))
142 }
143 pub fn substitution(&self, db: &'db dyn Database) -> Maybe<GenericSubstitution<'db>> {
144 match self {
145 ConcreteFunctionWithBodyLongId::Semantic(id) => id.substitution(db),
146 ConcreteFunctionWithBodyLongId::Generated(GeneratedFunction { parent, .. }) => {
147 parent.substitution(db)
148 }
149 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
150 specialized.base.substitution(db)
151 }
152 }
153 }
154 pub fn function_id(&self, db: &'db dyn Database) -> Maybe<FunctionId<'db>> {
155 let long_id = match self {
156 ConcreteFunctionWithBodyLongId::Semantic(id) => {
157 FunctionLongId::Semantic(id.function_id(db)?)
158 }
159 ConcreteFunctionWithBodyLongId::Generated(generated) => {
160 FunctionLongId::Generated(*generated)
161 }
162 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
163 FunctionLongId::Specialized(specialized.clone())
164 }
165 };
166 Ok(long_id.intern(db))
167 }
168 pub fn base_semantic_function(
169 &self,
170 db: &'db dyn Database,
171 ) -> semantic::ConcreteFunctionWithBodyId<'db> {
172 match self {
173 ConcreteFunctionWithBodyLongId::Semantic(id) => *id,
174 ConcreteFunctionWithBodyLongId::Generated(generated) => generated.parent,
175 ConcreteFunctionWithBodyLongId::Specialized(specialized) => {
176 specialized.base.base_semantic_function(db)
177 }
178 }
179 }
180 pub fn full_path(&self, db: &dyn Database) -> String {
181 match self {
182 ConcreteFunctionWithBodyLongId::Semantic(semantic) => semantic.full_path(db),
183 ConcreteFunctionWithBodyLongId::Generated(generated) => generated.full_path(db),
184 ConcreteFunctionWithBodyLongId::Specialized(specialized) => specialized.full_path(db),
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.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.base.stable_location(db)?
236 }
237 })
238 }
239}
240
241#[derive(Clone, Debug, Hash, PartialEq, Eq)]
243pub enum FunctionLongId<'db> {
244 Semantic(semantic::FunctionId<'db>),
246 Generated(GeneratedFunction<'db>),
248 Specialized(SpecializedFunction<'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.wrapper_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.clone()).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.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.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, 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)]
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)]
447pub struct SpecializedFunction<'db> {
448 pub base: crate::ids::ConcreteFunctionWithBodyId<'db>,
450 pub args: Arc<[SpecializationArg<'db>]>,
452}
453
454impl<'db> SpecializedFunction<'db> {
455 pub fn body(&self, db: &'db dyn Database) -> ConcreteFunctionWithBodyId<'db> {
456 let long_id = ConcreteFunctionWithBodyLongId::Specialized(self.clone());
457 long_id.intern(db)
458 }
459 pub fn full_path(&self, db: &dyn Database) -> String {
460 format!("{:?}", self.debug(db))
461 }
462
463 pub fn signature(&self, db: &'db dyn Database) -> Maybe<Signature<'db>> {
464 let mut base_sign = self.base.signature(db)?;
465
466 let mut params = vec![];
467 let mut stack = vec![];
468 for (param, arg) in zip_eq(base_sign.params.iter().rev(), self.args.iter().rev()) {
469 stack.push((param.clone(), arg));
470 }
471
472 while let Some((param, arg)) = stack.pop() {
473 match arg {
474 SpecializationArg::Const { .. } => {}
475 SpecializationArg::Snapshot(inner) => {
476 let desnap_ty = *extract_matches!(param.ty.long(db), TypeLongId::Snapshot);
477 stack.push((
478 LoweredParam { ty: desnap_ty, stable_ptr: param.stable_ptr },
479 inner.as_ref(),
480 ));
481 }
482 SpecializationArg::Enum { variant, payload } => {
483 let lowered_param =
484 LoweredParam { ty: variant.ty, stable_ptr: param.stable_ptr };
485 stack.push((lowered_param, payload.as_ref()));
486 }
487 SpecializationArg::Array(ty, values) => {
488 for arg in values.iter().rev() {
489 let lowered_param = LoweredParam { ty: *ty, stable_ptr: param.stable_ptr };
490 stack.push((lowered_param, arg));
491 }
492 }
493 SpecializationArg::Struct(specialization_args) => {
494 let ty = param.ty;
495 let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct)) = ty.long(db)
496 else {
497 unreachable!("Expected a concrete struct type");
498 };
499 let Ok(inner_param) = db.concrete_struct_members(*concrete_struct) else {
500 continue;
501 };
502 for ((_, inner_param), arg) in
503 zip_eq(inner_param.iter().rev(), specialization_args.iter().rev())
504 {
505 let lowered_param =
506 LoweredParam { ty: inner_param.ty, stable_ptr: param.stable_ptr };
507 stack.push((lowered_param, arg));
508 }
509 }
510 SpecializationArg::NotSpecialized => {
511 params.push(param.clone());
512 }
513 }
514 }
515
516 base_sign.params = params;
517
518 Ok(base_sign)
519 }
520}
521impl<'a> DebugWithDb<'a> for SpecializedFunction<'a> {
522 type Db = dyn Database;
523 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'a dyn Database) -> std::fmt::Result {
524 write!(f, "{}{{", self.base.full_path(db))?;
525 for arg in self.args.iter() {
526 write!(f, "{:?}, ", arg.debug(db))?;
527 }
528 write!(f, "}}")
529 }
530}
531
532#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::Update)]
534#[debug_db(dyn Database)]
535pub struct EnrichedSemanticSignature<'db> {
536 pub params: Vec<semantic::ExprVarMemberPath<'db>>,
538 pub extra_rets: Vec<semantic::ExprVarMemberPath<'db>>,
540 pub return_type: semantic::TypeId<'db>,
542 pub implicits: Vec<semantic::TypeId<'db>>,
544 #[dont_rewrite]
546 pub panicable: bool,
547 #[dont_rewrite]
549 #[hide_field_debug_with_db]
550 pub location: LocationId<'db>,
551}
552impl<'db> EnrichedSemanticSignature<'db> {
553 pub fn from_semantic(db: &'db dyn Database, value: &semantic::Signature<'db>) -> Self {
554 let semantic::Signature {
555 params,
556 return_type,
557 implicits,
558 panicable,
559 stable_ptr,
560 is_const: _,
561 } = value;
562 let ref_params = params
563 .iter()
564 .filter(|param| param.mutability == Mutability::Reference)
565 .map(|param| parameter_as_member_path(param.clone()))
566 .collect();
567 let params: Vec<semantic::ExprVarMemberPath<'_>> =
568 params.iter().cloned().map(parameter_as_member_path).collect();
569 Self {
570 params,
571 extra_rets: ref_params,
572 return_type: *return_type,
573 implicits: implicits.clone(),
574 panicable: *panicable,
575 location: LocationId::from_stable_location(
576 db,
577 StableLocation::new(stable_ptr.untyped()),
578 ),
579 }
580 }
581 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
582 self.params.iter().all(|param| param.ty().is_fully_concrete(db))
583 && self.extra_rets.iter().all(|param| param.ty().is_fully_concrete(db))
584 && self.return_type.is_fully_concrete(db)
585 && self.implicits.iter().all(|ty| ty.is_fully_concrete(db))
586 }
587}
588semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, EnrichedSemanticSignature<'a>);
589
590#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::Update)]
591#[debug_db(dyn Database)]
592pub struct LoweredParam<'db> {
594 pub ty: semantic::TypeId<'db>,
595 #[dont_rewrite]
596 pub stable_ptr: ast::ExprPtr<'db>,
597}
598semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, LoweredParam<'a>);
599
600#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject, Hash, salsa::Update)]
602#[debug_db(dyn Database)]
603pub struct Signature<'db> {
604 pub params: Vec<LoweredParam<'db>>, pub extra_rets: Vec<semantic::ExprVarMemberPath<'db>>,
608 pub return_type: semantic::TypeId<'db>,
610 pub implicits: Vec<semantic::TypeId<'db>>,
612 #[dont_rewrite]
614 pub panicable: bool,
615 #[dont_rewrite]
617 #[hide_field_debug_with_db]
618 pub location: LocationId<'db>,
619}
620semantic::add_rewrite!(<'a, 'b>, SubstitutionRewriter<'a, 'b>, DiagnosticAdded, Signature<'a>);
621
622impl<'db> From<EnrichedSemanticSignature<'db>> for Signature<'db> {
623 fn from(signature: EnrichedSemanticSignature<'db>) -> Self {
624 Signature {
625 params: signature
626 .params
627 .iter()
628 .map(|param| LoweredParam { ty: param.ty(), stable_ptr: param.stable_ptr() })
629 .collect(),
630 extra_rets: signature.extra_rets,
631 return_type: signature.return_type,
632 implicits: signature.implicits,
633 panicable: signature.panicable,
634 location: signature.location,
635 }
636 }
637}
638
639pub(crate) fn parameter_as_member_path<'db>(
641 param: semantic::Parameter<'db>,
642) -> semantic::ExprVarMemberPath<'db> {
643 let semantic::Parameter { id, ty, stable_ptr, .. } = param;
644 semantic::ExprVarMemberPath::Var(ExprVar {
645 var: semantic::VarId::Param(id),
646 ty,
647 stable_ptr: ast::ExprPtr(stable_ptr.0),
648 })
649}
650
651define_short_id!(LocationId, Location<'db>);
652impl<'db> LocationId<'db> {
653 pub fn from_stable_location(
654 db: &'db dyn Database,
655 stable_location: StableLocation<'db>,
656 ) -> LocationId<'db> {
657 Location::new(stable_location).intern(db)
658 }
659
660 pub fn with_note(&self, db: &'db dyn Database, note: DiagnosticNote<'db>) -> LocationId<'db> {
662 self.long(db).clone().with_note(note).intern(db)
663 }
664
665 pub fn with_auto_generation_note(
667 &self,
668 db: &'db dyn Database,
669 logic_name: &str,
670 ) -> LocationId<'db> {
671 self.with_note(
672 db,
673 DiagnosticNote::text_only(format!(
674 "this error originates in auto-generated {logic_name} logic."
675 )),
676 )
677 }
678}