cairo_lang_semantic/items/
functions.rs

1use std::fmt::Debug;
2use std::sync::Arc;
3
4use cairo_lang_debug::DebugWithDb;
5use cairo_lang_defs::diagnostic_utils::StableLocation;
6use cairo_lang_defs::ids::{
7    ExternFunctionId, FreeFunctionId, FunctionTitleId, FunctionWithBodyId, ImplFunctionId,
8    LanguageElementId, ModuleFileId, ModuleItemId, NamedLanguageElementId, ParamLongId,
9    TopLevelLanguageElementId, TraitFunctionId,
10};
11use cairo_lang_diagnostics::{Diagnostics, Maybe};
12use cairo_lang_filesystem::ids::UnstableSalsaId;
13use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
14use cairo_lang_syntax as syntax;
15use cairo_lang_syntax::attribute::structured::Attribute;
16use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode, ast};
17use cairo_lang_utils::{
18    Intern, LookupIntern, OptionFrom, define_short_id, require, try_extract_matches,
19};
20use itertools::{Itertools, chain};
21use smol_str::SmolStr;
22use syntax::attribute::consts::MUST_USE_ATTR;
23use syntax::node::TypedStablePtr;
24
25use super::attribute::SemanticQueryAttrs;
26use super::generics::generic_params_to_args;
27use super::imp::{ImplId, ImplLongId};
28use super::modifiers;
29use super::trt::ConcreteTraitGenericFunctionId;
30use crate::corelib::{panic_destruct_trait_fn, unit_ty};
31use crate::db::SemanticGroup;
32use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder};
33use crate::expr::compute::Environment;
34use crate::resolve::{Resolver, ResolverData};
35use crate::substitution::{GenericSubstitution, SemanticRewriter, SubstitutionRewriter};
36use crate::types::resolve_type;
37use crate::{
38    ConcreteImplId, ConcreteImplLongId, ConcreteTraitLongId, GenericParam, SemanticDiagnostic,
39    TypeId, semantic, semantic_object_for_id,
40};
41
42/// A generic function of an impl.
43#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
44pub struct ImplGenericFunctionId {
45    // TODO(spapini): Consider making these private and enforcing invariants in the ctor.
46    /// The impl the function is in.
47    pub impl_id: ImplId,
48    /// The trait function this impl function implements.
49    pub function: TraitFunctionId,
50}
51impl ImplGenericFunctionId {
52    /// Gets the impl function language element, if self.impl_id is of a concrete impl.
53    pub fn impl_function(&self, db: &dyn SemanticGroup) -> Maybe<Option<ImplFunctionId>> {
54        match self.impl_id.lookup_intern(db) {
55            ImplLongId::Concrete(concrete_impl_id) => {
56                concrete_impl_id.get_impl_function(db, self.function)
57            }
58            ImplLongId::GenericParameter(_)
59            | ImplLongId::ImplVar(_)
60            | ImplLongId::ImplImpl(_)
61            | ImplLongId::TraitImpl(_)
62            | ImplLongId::GeneratedImpl(_) => Ok(None),
63        }
64    }
65    pub fn format(&self, db: &dyn SemanticGroup) -> SmolStr {
66        format!("{}::{}", self.impl_id.name(db.upcast()), self.function.name(db.upcast())).into()
67    }
68}
69impl DebugWithDb<dyn SemanticGroup> for ImplGenericFunctionId {
70    fn fmt(
71        &self,
72        f: &mut std::fmt::Formatter<'_>,
73        db: &(dyn SemanticGroup + 'static),
74    ) -> std::fmt::Result {
75        write!(f, "{}", self.format(db))
76    }
77}
78
79/// The ID of a generic function that can be concretized.
80#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
81pub enum GenericFunctionId {
82    /// A generic free function.
83    Free(FreeFunctionId),
84    /// A generic extern function.
85    Extern(ExternFunctionId),
86    /// A generic function of an impl.
87    Impl(ImplGenericFunctionId),
88    Trait(ConcreteTraitGenericFunctionId),
89}
90impl GenericFunctionId {
91    pub fn from_generic_with_body(
92        db: &dyn SemanticGroup,
93        val: GenericFunctionWithBodyId,
94    ) -> Maybe<Self> {
95        Ok(match val {
96            GenericFunctionWithBodyId::Free(id) => GenericFunctionId::Free(id),
97            GenericFunctionWithBodyId::Impl(id) => {
98                let impl_id = ImplLongId::Concrete(id.concrete_impl_id).intern(db);
99                let function = match id.function_body {
100                    ImplFunctionBodyId::Impl(body_id) => {
101                        db.impl_function_trait_function(body_id)?
102                    }
103                    ImplFunctionBodyId::Trait(body_id) => body_id,
104                };
105                GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function })
106            }
107            GenericFunctionWithBodyId::Trait(id) => GenericFunctionId::Trait(id),
108        })
109    }
110    pub fn format(&self, db: &dyn SemanticGroup) -> String {
111        let defs_db = db.upcast();
112        match self {
113            GenericFunctionId::Free(id) => id.full_path(defs_db),
114            GenericFunctionId::Extern(id) => id.full_path(defs_db),
115            GenericFunctionId::Impl(id) => {
116                format!("{:?}::{}", id.impl_id.debug(db.elongate()), id.function.name(defs_db))
117            }
118            GenericFunctionId::Trait(id) => {
119                format!(
120                    "{}::{}",
121                    id.concrete_trait(db).full_path(db),
122                    id.trait_function(db).name(defs_db)
123                )
124            }
125        }
126    }
127    pub fn generic_signature(&self, db: &dyn SemanticGroup) -> Maybe<Signature> {
128        match *self {
129            GenericFunctionId::Free(id) => db.free_function_signature(id),
130            GenericFunctionId::Extern(id) => db.extern_function_signature(id),
131            GenericFunctionId::Impl(id) => {
132                let concrete_trait_id = id.impl_id.concrete_trait(db)?;
133                let signature = db.concrete_trait_function_signature(
134                    ConcreteTraitGenericFunctionId::new(db, concrete_trait_id, id.function),
135                )?;
136
137                let substitution = &GenericSubstitution::from_impl(id.impl_id);
138                SubstitutionRewriter { db, substitution }.rewrite(signature)
139            }
140            GenericFunctionId::Trait(id) => db.concrete_trait_function_signature(id),
141        }
142    }
143    pub fn generic_params(&self, db: &dyn SemanticGroup) -> Maybe<Vec<GenericParam>> {
144        match *self {
145            GenericFunctionId::Free(id) => db.free_function_generic_params(id),
146            GenericFunctionId::Extern(id) => db.extern_function_declaration_generic_params(id),
147            GenericFunctionId::Impl(id) => {
148                let concrete_trait_id = db.impl_concrete_trait(id.impl_id)?;
149                let id = ConcreteTraitGenericFunctionId::new(db, concrete_trait_id, id.function);
150                db.concrete_trait_function_generic_params(id)
151            }
152            GenericFunctionId::Trait(id) => db.concrete_trait_function_generic_params(id),
153        }
154    }
155    pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
156        match self {
157            GenericFunctionId::Free(free_function) => free_function.name(db.upcast()),
158            GenericFunctionId::Extern(extern_function) => extern_function.name(db.upcast()),
159            GenericFunctionId::Impl(impl_function) => impl_function.format(db.upcast()),
160            GenericFunctionId::Trait(trait_function) => {
161                trait_function.trait_function(db).name(db.upcast())
162            }
163        }
164    }
165    /// Returns the ModuleFileId of the function's definition if possible.
166    pub fn module_file_id(&self, db: &dyn SemanticGroup) -> Option<ModuleFileId> {
167        match self {
168            GenericFunctionId::Free(free_function) => {
169                Some(free_function.module_file_id(db.upcast()))
170            }
171            GenericFunctionId::Extern(extern_function) => {
172                Some(extern_function.module_file_id(db.upcast()))
173            }
174            GenericFunctionId::Impl(impl_generic_function_id) => {
175                // Return the module file of the impl containing the function.
176                if let ImplLongId::Concrete(concrete_impl_id) =
177                    impl_generic_function_id.impl_id.lookup_intern(db)
178                {
179                    Some(concrete_impl_id.impl_def_id(db).module_file_id(db.upcast()))
180                } else {
181                    None
182                }
183            }
184            GenericFunctionId::Trait(trait_function) => Some(
185                trait_function.trait_function(db).trait_id(db.upcast()).module_file_id(db.upcast()),
186            ),
187        }
188    }
189    /// Returns whether the function has the `#[must_use]` attribute.
190    pub fn is_must_use(&self, db: &dyn SemanticGroup) -> Maybe<bool> {
191        match self {
192            GenericFunctionId::Free(id) => id.has_attr(db, MUST_USE_ATTR),
193            GenericFunctionId::Impl(id) => id.function.has_attr(db, MUST_USE_ATTR),
194            GenericFunctionId::Trait(id) => id.trait_function(db).has_attr(db, MUST_USE_ATTR),
195            GenericFunctionId::Extern(_) => Ok(false),
196        }
197    }
198    /// Returns true if the function does not depend on any generics.
199    pub fn is_fully_concrete(&self, db: &dyn SemanticGroup) -> bool {
200        match self {
201            GenericFunctionId::Free(_) | GenericFunctionId::Extern(_) => true,
202            GenericFunctionId::Impl(impl_generic_function) => {
203                impl_generic_function.impl_id.is_fully_concrete(db)
204            }
205            GenericFunctionId::Trait(_) => false,
206        }
207    }
208    /// Returns true if the function does not depend on impl or type variables.
209    pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool {
210        match self {
211            GenericFunctionId::Free(_) | GenericFunctionId::Extern(_) => true,
212            GenericFunctionId::Impl(impl_generic_function) => {
213                impl_generic_function.impl_id.is_var_free(db)
214            }
215            GenericFunctionId::Trait(_) => false,
216        }
217    }
218}
219/// Conversion from ModuleItemId to GenericFunctionId.
220impl OptionFrom<ModuleItemId> for GenericFunctionId {
221    fn option_from(item: ModuleItemId) -> Option<Self> {
222        match item {
223            ModuleItemId::FreeFunction(id) => Some(GenericFunctionId::Free(id)),
224            ModuleItemId::ExternFunction(id) => Some(GenericFunctionId::Extern(id)),
225            ModuleItemId::Constant(_)
226            | ModuleItemId::Submodule(_)
227            | ModuleItemId::Use(_)
228            | ModuleItemId::Trait(_)
229            | ModuleItemId::Impl(_)
230            | ModuleItemId::Struct(_)
231            | ModuleItemId::Enum(_)
232            | ModuleItemId::TypeAlias(_)
233            | ModuleItemId::ImplAlias(_)
234            | ModuleItemId::ExternType(_) => None,
235        }
236    }
237}
238impl DebugWithDb<dyn SemanticGroup> for GenericFunctionId {
239    fn fmt(
240        &self,
241        f: &mut std::fmt::Formatter<'_>,
242        db: &(dyn SemanticGroup + 'static),
243    ) -> std::fmt::Result {
244        match self {
245            GenericFunctionId::Free(func) => write!(f, "{:?}", func.debug(db)),
246            GenericFunctionId::Extern(func) => write!(f, "{:?}", func.debug(db)),
247            GenericFunctionId::Impl(func) => write!(f, "{:?}", func.debug(db)),
248            GenericFunctionId::Trait(func) => write!(f, "{:?}", func.debug(db)),
249        }
250    }
251}
252
253/// Function instance.
254/// For example: `ImplA::foo<A, B>`, or `bar<A>`.
255// TODO(spapini): Make it an enum and add a function pointer variant.
256#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
257pub struct FunctionLongId {
258    pub function: ConcreteFunction,
259}
260impl DebugWithDb<dyn SemanticGroup> for FunctionLongId {
261    fn fmt(
262        &self,
263        f: &mut std::fmt::Formatter<'_>,
264        db: &(dyn SemanticGroup + 'static),
265    ) -> std::fmt::Result {
266        write!(f, "{:?}", self.function.debug(db))
267    }
268}
269
270define_short_id!(
271    FunctionId,
272    FunctionLongId,
273    SemanticGroup,
274    lookup_intern_function,
275    intern_function
276);
277semantic_object_for_id!(FunctionId, lookup_intern_function, intern_function, FunctionLongId);
278impl FunctionId {
279    pub fn get_concrete(&self, db: &dyn SemanticGroup) -> ConcreteFunction {
280        self.lookup_intern(db).function
281    }
282
283    /// Returns the ExternFunctionId if this is an extern function. Otherwise returns none.
284    pub fn try_get_extern_function_id(&self, db: &dyn SemanticGroup) -> Option<ExternFunctionId> {
285        try_extract_matches!(self.get_concrete(db).generic_function, GenericFunctionId::Extern)
286    }
287
288    pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
289        format!("{:?}", self.get_concrete(db).generic_function.name(db)).into()
290    }
291
292    pub fn full_name(&self, db: &dyn SemanticGroup) -> String {
293        self.get_concrete(db).full_name(db)
294    }
295
296    /// Returns true if the function does not depend on any generics.
297    pub fn is_fully_concrete(&self, db: &dyn SemanticGroup) -> bool {
298        let func = self.get_concrete(db);
299        func.generic_function.is_fully_concrete(db)
300            && func
301                .generic_args
302                .iter()
303                .all(|generic_argument_id| generic_argument_id.is_fully_concrete(db))
304    }
305    /// Returns true if the function does not depend on impl or type variables.
306    pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool {
307        let func = self.get_concrete(db);
308        func.generic_function.is_var_free(db)
309            && func
310                .generic_args
311                .iter()
312                .all(|generic_argument_id| generic_argument_id.is_var_free(db))
313    }
314}
315impl FunctionLongId {
316    pub fn from_generic(
317        db: &dyn SemanticGroup,
318        generic_function: GenericFunctionId,
319    ) -> Maybe<Self> {
320        let generic_params: Vec<_> = generic_function.generic_params(db)?;
321
322        Ok(FunctionLongId {
323            function: ConcreteFunction {
324                generic_function,
325                generic_args: generic_params_to_args(&generic_params, db),
326            },
327        })
328    }
329}
330
331/// A generic function of a concrete impl.
332#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
333pub struct ImplGenericFunctionWithBodyId {
334    pub concrete_impl_id: ConcreteImplId,
335    pub function_body: ImplFunctionBodyId,
336}
337
338/// The body of an impl function implementation.
339#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
340pub enum ImplFunctionBodyId {
341    /// A function that was implemented in the impl.
342    Impl(ImplFunctionId),
343    /// The default implementation of a trait function in the trait.
344    Trait(TraitFunctionId),
345}
346impl ImplFunctionBodyId {
347    pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
348        match self {
349            Self::Impl(body_id) => body_id.name(db.upcast()),
350            Self::Trait(body_id) => body_id.name(db.upcast()),
351        }
352    }
353    pub fn stable_location(&self, db: &dyn SemanticGroup) -> StableLocation {
354        match self {
355            Self::Impl(body_id) => body_id.stable_location(db.upcast()),
356            Self::Trait(body_id) => body_id.stable_location(db.upcast()),
357        }
358    }
359
360    pub fn trait_function(&self, db: &dyn SemanticGroup) -> Maybe<TraitFunctionId> {
361        match self {
362            Self::Impl(impl_function) => db.impl_function_trait_function(*impl_function),
363            Self::Trait(trait_function) => Ok(*trait_function),
364        }
365    }
366}
367
368/// The ID of a generic function with body that can be concretized.
369#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
370pub enum GenericFunctionWithBodyId {
371    Free(FreeFunctionId),
372    Impl(ImplGenericFunctionWithBodyId),
373    Trait(ConcreteTraitGenericFunctionId),
374}
375impl GenericFunctionWithBodyId {
376    pub fn from_generic(db: &dyn SemanticGroup, other: GenericFunctionId) -> Maybe<Option<Self>> {
377        Ok(Some(match other {
378            GenericFunctionId::Free(id) => GenericFunctionWithBodyId::Free(id),
379            GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }) => {
380                let ImplLongId::Concrete(concrete_impl_id) = impl_id.lookup_intern(db) else {
381                    return Ok(None);
382                };
383                GenericFunctionWithBodyId::Impl(ImplGenericFunctionWithBodyId {
384                    concrete_impl_id,
385                    function_body: if let Some(impl_function) =
386                        concrete_impl_id.get_impl_function(db, function)?
387                    {
388                        ImplFunctionBodyId::Impl(impl_function)
389                    } else {
390                        ImplFunctionBodyId::Trait(function)
391                    },
392                })
393            }
394            GenericFunctionId::Trait(id) => GenericFunctionWithBodyId::Trait(id),
395            _ => return Ok(None),
396        }))
397    }
398    pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
399        match self {
400            GenericFunctionWithBodyId::Free(free) => free.name(db.upcast()),
401            GenericFunctionWithBodyId::Impl(imp) => {
402                format!("{}::{}", imp.concrete_impl_id.name(db), imp.function_body.name(db)).into()
403            }
404            GenericFunctionWithBodyId::Trait(trt) => format!(
405                "{}::{}",
406                trt.concrete_trait(db).name(db),
407                trt.trait_function(db).name(db.upcast())
408            )
409            .into(),
410        }
411    }
412
413    pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
414        let defs_db = db.upcast();
415        match self {
416            GenericFunctionWithBodyId::Free(free) => free.full_path(defs_db),
417            GenericFunctionWithBodyId::Impl(imp) => {
418                format!(
419                    "{}::{}",
420                    imp.concrete_impl_id.impl_def_id(db).full_path(defs_db),
421                    imp.function_body.name(db)
422                )
423            }
424            GenericFunctionWithBodyId::Trait(trt) => format!(
425                "{}::{}",
426                trt.concrete_trait(db).full_path(db),
427                trt.trait_function(db).name(defs_db)
428            ),
429        }
430    }
431    pub fn stable_location(&self, db: &dyn SemanticGroup) -> StableLocation {
432        match self {
433            GenericFunctionWithBodyId::Free(free_function) => {
434                free_function.stable_location(db.upcast())
435            }
436            GenericFunctionWithBodyId::Impl(impl_function) => {
437                impl_function.function_body.stable_location(db.upcast())
438            }
439            GenericFunctionWithBodyId::Trait(trait_function) => {
440                trait_function.trait_function(db).stable_location(db.upcast())
441            }
442        }
443    }
444}
445
446/// A long Id of a concrete function with body.
447#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
448pub struct ConcreteFunctionWithBody {
449    pub generic_function: GenericFunctionWithBodyId,
450    pub generic_args: Vec<semantic::GenericArgumentId>,
451}
452impl ConcreteFunctionWithBody {
453    pub fn function_with_body_id(&self, db: &dyn SemanticGroup) -> FunctionWithBodyId {
454        match self.generic_function {
455            GenericFunctionWithBodyId::Free(id) => FunctionWithBodyId::Free(id),
456            GenericFunctionWithBodyId::Impl(id) => match id.function_body {
457                ImplFunctionBodyId::Impl(id) => FunctionWithBodyId::Impl(id),
458                ImplFunctionBodyId::Trait(id) => FunctionWithBodyId::Trait(id),
459            },
460            GenericFunctionWithBodyId::Trait(id) => {
461                FunctionWithBodyId::Trait(id.trait_function(db))
462            }
463        }
464    }
465    pub fn substitution(&self, db: &dyn SemanticGroup) -> Maybe<GenericSubstitution> {
466        Ok(match self.generic_function {
467            GenericFunctionWithBodyId::Free(f) => {
468                GenericSubstitution::new(&db.free_function_generic_params(f)?, &self.generic_args)
469            }
470            GenericFunctionWithBodyId::Impl(f) => match f.function_body {
471                ImplFunctionBodyId::Impl(body_id) => {
472                    let concrete_impl = f.concrete_impl_id.lookup_intern(db);
473                    GenericSubstitution::from_impl(
474                        ImplLongId::Concrete(f.concrete_impl_id).intern(db),
475                    )
476                    .concat(GenericSubstitution::new(
477                        &chain!(
478                            db.impl_function_generic_params(body_id)?,
479                            db.impl_def_generic_params(concrete_impl.impl_def_id)?
480                        )
481                        .collect_vec(),
482                        &chain!(
483                            self.generic_args.iter().copied(),
484                            concrete_impl.generic_args.iter().copied()
485                        )
486                        .collect_vec(),
487                    ))
488                }
489                ImplFunctionBodyId::Trait(body_id) => {
490                    let concrete_impl_id = ImplLongId::Concrete(f.concrete_impl_id).intern(db);
491                    let concrete_trait = concrete_impl_id.concrete_trait(db)?.lookup_intern(db);
492                    GenericSubstitution::from_impl(concrete_impl_id).concat(
493                        GenericSubstitution::new(
494                            &chain!(
495                                db.trait_function_generic_params(body_id)?,
496                                db.trait_generic_params(concrete_trait.trait_id)?
497                            )
498                            .collect_vec(),
499                            &chain!(
500                                self.generic_args.iter().copied(),
501                                concrete_trait.generic_args.iter().copied()
502                            )
503                            .collect_vec(),
504                        ),
505                    )
506                }
507            },
508            GenericFunctionWithBodyId::Trait(f) => {
509                let concrete_trait = f.concrete_trait(db).lookup_intern(db);
510                GenericSubstitution::new(
511                    &chain!(
512                        db.trait_function_generic_params(f.trait_function(db))?,
513                        db.trait_generic_params(concrete_trait.trait_id)?
514                    )
515                    .collect_vec(),
516                    &chain!(
517                        self.generic_args.iter().copied(),
518                        concrete_trait.generic_args.iter().copied()
519                    )
520                    .collect_vec(),
521                )
522            }
523        })
524    }
525    pub fn from_no_generics_free(
526        db: &dyn SemanticGroup,
527        free_function_id: FreeFunctionId,
528    ) -> Option<Self> {
529        require(db.free_function_generic_params(free_function_id).ok()?.is_empty())?;
530        Some(ConcreteFunctionWithBody {
531            generic_function: GenericFunctionWithBodyId::Free(free_function_id),
532            generic_args: vec![],
533        })
534    }
535    pub fn from_generic(db: &dyn SemanticGroup, function_id: FunctionWithBodyId) -> Maybe<Self> {
536        Ok(match function_id {
537            FunctionWithBodyId::Free(free) => {
538                let params = db.free_function_generic_params(free)?;
539                let generic_args = generic_params_to_args(&params, db);
540                ConcreteFunctionWithBody {
541                    generic_function: GenericFunctionWithBodyId::Free(free),
542                    generic_args,
543                }
544            }
545            FunctionWithBodyId::Impl(impl_function_id) => {
546                let params = db.impl_function_generic_params(impl_function_id)?;
547                let generic_args = generic_params_to_args(&params, db);
548                let impl_def_id = impl_function_id.impl_def_id(db.upcast());
549                let impl_def_params = db.impl_def_generic_params(impl_def_id)?;
550                let impl_generic_args = generic_params_to_args(&impl_def_params, db);
551                let impl_generic_function = ImplGenericFunctionWithBodyId {
552                    concrete_impl_id: ConcreteImplLongId {
553                        impl_def_id,
554                        generic_args: impl_generic_args,
555                    }
556                    .intern(db),
557                    function_body: ImplFunctionBodyId::Impl(impl_function_id),
558                };
559                ConcreteFunctionWithBody {
560                    generic_function: GenericFunctionWithBodyId::Impl(impl_generic_function),
561                    generic_args,
562                }
563            }
564            FunctionWithBodyId::Trait(trait_function_id) => {
565                let params = db.trait_function_generic_params(trait_function_id)?;
566                let generic_args = generic_params_to_args(&params, db);
567                let trait_id = trait_function_id.trait_id(db.upcast());
568                let trait_generic_params = db.trait_generic_params(trait_id)?;
569                let trait_generic_args = generic_params_to_args(&trait_generic_params, db);
570                let concrete_trait_id = ConcreteTraitLongId {
571                    generic_args: trait_generic_args,
572                    trait_id: trait_function_id.trait_id(db.upcast()),
573                }
574                .intern(db);
575                let trait_generic_function =
576                    ConcreteTraitGenericFunctionId::new(db, concrete_trait_id, trait_function_id);
577                ConcreteFunctionWithBody {
578                    generic_function: GenericFunctionWithBodyId::Trait(trait_generic_function),
579                    generic_args,
580                }
581            }
582        })
583    }
584    pub fn concrete(&self, db: &dyn SemanticGroup) -> Maybe<ConcreteFunction> {
585        Ok(ConcreteFunction {
586            generic_function: GenericFunctionId::from_generic_with_body(db, self.generic_function)?,
587            generic_args: self.generic_args.clone(),
588        })
589    }
590    pub fn function_id(&self, db: &dyn SemanticGroup) -> Maybe<FunctionId> {
591        Ok(FunctionLongId { function: self.concrete(db)? }.intern(db))
592    }
593    pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
594        self.function_with_body_id(db).name(db.upcast())
595    }
596    pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
597        self.generic_function.full_path(db)
598    }
599}
600
601impl DebugWithDb<dyn SemanticGroup> for ConcreteFunctionWithBody {
602    fn fmt(
603        &self,
604        f: &mut std::fmt::Formatter<'_>,
605        db: &(dyn SemanticGroup + 'static),
606    ) -> std::fmt::Result {
607        write!(f, "{:?}", self.generic_function.name(db.upcast()))?;
608        if !self.generic_args.is_empty() {
609            write!(f, "::<")?;
610            for (i, arg) in self.generic_args.iter().enumerate() {
611                if i > 0 {
612                    write!(f, ", ")?;
613                }
614                write!(f, "{:?}", arg.debug(db))?;
615            }
616            write!(f, ">")?;
617        }
618        Ok(())
619    }
620}
621
622define_short_id!(
623    ConcreteFunctionWithBodyId,
624    ConcreteFunctionWithBody,
625    SemanticGroup,
626    lookup_intern_concrete_function_with_body,
627    intern_concrete_function_with_body
628);
629semantic_object_for_id!(
630    ConcreteFunctionWithBodyId,
631    lookup_intern_concrete_function_with_body,
632    intern_concrete_function_with_body,
633    ConcreteFunctionWithBody
634);
635impl ConcreteFunctionWithBodyId {
636    pub fn function_with_body_id(&self, db: &dyn SemanticGroup) -> FunctionWithBodyId {
637        self.lookup_intern(db).function_with_body_id(db)
638    }
639    pub fn substitution(&self, db: &dyn SemanticGroup) -> Maybe<GenericSubstitution> {
640        self.lookup_intern(db).substitution(db)
641    }
642    pub fn from_no_generics_free(
643        db: &dyn SemanticGroup,
644        free_function_id: FreeFunctionId,
645    ) -> Option<Self> {
646        Some(ConcreteFunctionWithBody::from_no_generics_free(db, free_function_id)?.intern(db))
647    }
648    pub fn from_generic(db: &dyn SemanticGroup, function_id: FunctionWithBodyId) -> Maybe<Self> {
649        Ok(ConcreteFunctionWithBody::from_generic(db, function_id)?.intern(db))
650    }
651    pub fn concrete(&self, db: &dyn SemanticGroup) -> Maybe<ConcreteFunction> {
652        self.lookup_intern(db).concrete(db)
653    }
654    pub fn function_id(&self, db: &dyn SemanticGroup) -> Maybe<FunctionId> {
655        self.lookup_intern(db).function_id(db)
656    }
657    pub fn generic_function(&self, db: &dyn SemanticGroup) -> GenericFunctionWithBodyId {
658        self.lookup_intern(db).generic_function
659    }
660    pub fn name(&self, db: &dyn SemanticGroup) -> SmolStr {
661        self.lookup_intern(db).name(db)
662    }
663    pub fn full_path(&self, db: &dyn SemanticGroup) -> String {
664        self.lookup_intern(db).full_path(db)
665    }
666
667    pub fn stable_location(&self, db: &dyn SemanticGroup) -> StableLocation {
668        self.lookup_intern(db).generic_function.stable_location(db)
669    }
670
671    pub fn is_panic_destruct_fn(&self, db: &dyn SemanticGroup) -> Maybe<bool> {
672        let trait_function = match self.generic_function(db) {
673            GenericFunctionWithBodyId::Free(_) => return Ok(false),
674            GenericFunctionWithBodyId::Impl(impl_func) => {
675                impl_func.function_body.trait_function(db)?
676            }
677            GenericFunctionWithBodyId::Trait(trait_func) => trait_func.trait_function(db),
678        };
679        Ok(trait_function == panic_destruct_trait_fn(db.upcast()))
680    }
681}
682
683impl UnstableSalsaId for ConcreteFunctionWithBodyId {
684    fn get_internal_id(&self) -> &salsa::InternId {
685        &self.0
686    }
687}
688
689#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
690pub struct ConcreteFunction {
691    pub generic_function: GenericFunctionId,
692    pub generic_args: Vec<semantic::GenericArgumentId>,
693}
694impl ConcreteFunction {
695    pub fn body(&self, db: &dyn SemanticGroup) -> Maybe<Option<ConcreteFunctionWithBodyId>> {
696        let Some(generic_function) =
697            GenericFunctionWithBodyId::from_generic(db, self.generic_function)?
698        else {
699            return Ok(None);
700        };
701        Ok(Some(
702            ConcreteFunctionWithBody { generic_function, generic_args: self.generic_args.clone() }
703                .intern(db),
704        ))
705    }
706    pub fn full_name(&self, db: &dyn SemanticGroup) -> String {
707        let maybe_generic_part = if !self.generic_args.is_empty() {
708            let mut generics = String::new();
709            for (i, arg) in self.generic_args.iter().enumerate() {
710                if i > 0 {
711                    generics.push_str(", ");
712                }
713                generics.push_str(&arg.format(db));
714            }
715            format!("::<{generics}>")
716        } else {
717            "".to_string()
718        };
719        format!("{}{maybe_generic_part}", self.generic_function.format(db.upcast()))
720    }
721}
722impl DebugWithDb<dyn SemanticGroup> for ConcreteFunction {
723    fn fmt(
724        &self,
725        f: &mut std::fmt::Formatter<'_>,
726        db: &(dyn SemanticGroup + 'static),
727    ) -> std::fmt::Result {
728        write!(f, "{}", self.generic_function.format(db.upcast()))?;
729        if !self.generic_args.is_empty() {
730            write!(f, "::<")?;
731            for (i, arg) in self.generic_args.iter().enumerate() {
732                if i > 0 {
733                    write!(f, ", ")?;
734                }
735                write!(f, "{:?}", arg.debug(db))?;
736            }
737            write!(f, ">")?;
738        }
739        Ok(())
740    }
741}
742
743#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject)]
744#[debug_db(dyn SemanticGroup + 'static)]
745pub struct Signature {
746    pub params: Vec<semantic::Parameter>,
747    pub return_type: semantic::TypeId,
748    /// implicit parameters
749    pub implicits: Vec<semantic::TypeId>,
750    #[dont_rewrite]
751    pub panicable: bool,
752    #[hide_field_debug_with_db]
753    #[dont_rewrite]
754    pub stable_ptr: ast::FunctionSignaturePtr,
755}
756
757impl Signature {
758    pub fn from_ast(
759        diagnostics: &mut SemanticDiagnostics,
760        db: &dyn SemanticGroup,
761        resolver: &mut Resolver<'_>,
762        signature_syntax: &ast::FunctionSignature,
763        function_title_id: FunctionTitleId,
764        environment: &mut Environment,
765    ) -> Self {
766        let syntax_db = db.upcast();
767        let params = function_signature_params(
768            diagnostics,
769            db,
770            resolver,
771            &signature_syntax.parameters(syntax_db).elements(syntax_db),
772            Some(function_title_id),
773            environment,
774        );
775        let return_type =
776            function_signature_return_type(diagnostics, db, resolver, signature_syntax);
777        let implicits =
778            function_signature_implicit_parameters(diagnostics, db, resolver, signature_syntax);
779        let panicable = match signature_syntax.optional_no_panic(db.upcast()) {
780            ast::OptionTerminalNoPanic::Empty(_) => true,
781            ast::OptionTerminalNoPanic::TerminalNoPanic(_) => false,
782        };
783        let stable_ptr = signature_syntax.stable_ptr();
784        semantic::Signature { params, return_type, implicits, panicable, stable_ptr }
785    }
786}
787
788pub fn function_signature_return_type(
789    diagnostics: &mut SemanticDiagnostics,
790    db: &dyn SemanticGroup,
791    resolver: &mut Resolver<'_>,
792    sig: &ast::FunctionSignature,
793) -> semantic::TypeId {
794    let ty_syntax = match sig.ret_ty(db.upcast()) {
795        ast::OptionReturnTypeClause::Empty(_) => {
796            return unit_ty(db);
797        }
798        ast::OptionReturnTypeClause::ReturnTypeClause(ret_type_clause) => {
799            ret_type_clause.ty(db.upcast())
800        }
801    };
802    resolve_type(db, diagnostics, resolver, &ty_syntax)
803}
804
805/// Returns the implicit parameters of the given function signature's AST.
806pub fn function_signature_implicit_parameters(
807    diagnostics: &mut SemanticDiagnostics,
808    db: &dyn SemanticGroup,
809    resolver: &mut Resolver<'_>,
810    sig: &ast::FunctionSignature,
811) -> Vec<semantic::TypeId> {
812    let syntax_db = db.upcast();
813
814    let ast_implicits = match sig.implicits_clause(syntax_db) {
815        ast::OptionImplicitsClause::Empty(_) => Vec::new(),
816        ast::OptionImplicitsClause::ImplicitsClause(implicits_clause) => {
817            implicits_clause.implicits(syntax_db).elements(syntax_db)
818        }
819    };
820
821    let mut implicits = Vec::new();
822    for implicit in ast_implicits {
823        implicits.push(resolve_type(
824            db,
825            diagnostics,
826            resolver,
827            &syntax::node::ast::Expr::Path(implicit),
828        ));
829    }
830    implicits
831}
832
833/// Returns the parameters of the given function signature's AST.
834pub fn function_signature_params(
835    diagnostics: &mut SemanticDiagnostics,
836    db: &dyn SemanticGroup,
837    resolver: &mut Resolver<'_>,
838    params: &[ast::Param],
839    function_title_id: Option<FunctionTitleId>,
840    env: &mut Environment,
841) -> Vec<semantic::Parameter> {
842    update_env_with_ast_params(diagnostics, db, resolver, params, function_title_id, env)
843}
844
845/// Query implementation of [crate::db::SemanticGroup::function_title_signature].
846pub fn function_title_signature(
847    db: &dyn SemanticGroup,
848    function_title_id: FunctionTitleId,
849) -> Maybe<Signature> {
850    match function_title_id {
851        FunctionTitleId::Free(free_function) => db.free_function_signature(free_function),
852        FunctionTitleId::Extern(extern_function) => db.extern_function_signature(extern_function),
853        FunctionTitleId::Trait(trait_function) => db.trait_function_signature(trait_function),
854        FunctionTitleId::Impl(impl_function) => db.impl_function_signature(impl_function),
855    }
856}
857/// Query implementation of [crate::db::SemanticGroup::function_title_generic_params].
858pub fn function_title_generic_params(
859    db: &dyn SemanticGroup,
860    function_title_id: FunctionTitleId,
861) -> Maybe<Vec<semantic::GenericParam>> {
862    match function_title_id {
863        FunctionTitleId::Free(free_function) => db.free_function_generic_params(free_function),
864        FunctionTitleId::Extern(extern_function) => {
865            db.extern_function_declaration_generic_params(extern_function)
866        }
867        FunctionTitleId::Trait(trait_function) => db.trait_function_generic_params(trait_function),
868        FunctionTitleId::Impl(impl_function) => db.impl_function_generic_params(impl_function),
869    }
870}
871
872/// Query implementation of [crate::db::SemanticGroup::concrete_function_signature].
873pub fn concrete_function_signature(
874    db: &dyn SemanticGroup,
875    function_id: FunctionId,
876) -> Maybe<Signature> {
877    let ConcreteFunction { generic_function, generic_args, .. } =
878        function_id.lookup_intern(db).function;
879    let generic_params = generic_function.generic_params(db)?;
880    let generic_signature = generic_function.generic_signature(db)?;
881    // TODO(spapini): When trait generics are supported, they need to be substituted
882    //   one by one, not together.
883    // Panic shouldn't occur since ConcreteFunction is assumed to be constructed correctly.
884    let substitution = GenericSubstitution::new(&generic_params, &generic_args);
885    SubstitutionRewriter { db, substitution: &substitution }.rewrite(generic_signature)
886}
887
888/// For a given list of AST parameters, returns the list of semantic parameters along with the
889/// corresponding environment.
890fn update_env_with_ast_params(
891    diagnostics: &mut SemanticDiagnostics,
892    db: &dyn SemanticGroup,
893    resolver: &mut Resolver<'_>,
894    ast_params: &[ast::Param],
895    function_title_id: Option<FunctionTitleId>,
896    env: &mut Environment,
897) -> Vec<semantic::Parameter> {
898    let mut semantic_params = Vec::new();
899    for ast_param in ast_params.iter() {
900        let semantic_param = ast_param_to_semantic(diagnostics, db, resolver, ast_param);
901
902        if env.add_param(diagnostics, semantic_param.clone(), ast_param, function_title_id).is_ok()
903        {
904            semantic_params.push(semantic_param);
905        }
906    }
907    semantic_params
908}
909
910/// Returns a semantic parameter (and its name) for the given AST parameter.
911fn ast_param_to_semantic(
912    diagnostics: &mut SemanticDiagnostics,
913    db: &dyn SemanticGroup,
914    resolver: &mut Resolver<'_>,
915    ast_param: &ast::Param,
916) -> semantic::Parameter {
917    let syntax_db = db.upcast();
918
919    let name = ast_param.name(syntax_db).text(syntax_db);
920
921    let id = ParamLongId(resolver.module_file_id, ast_param.stable_ptr()).intern(db);
922
923    let ty = match ast_param.type_clause(syntax_db) {
924        ast::OptionTypeClause::Empty(missing) => {
925            resolver.inference().new_type_var(Some(missing.stable_ptr().untyped()))
926        }
927        ast::OptionTypeClause::TypeClause(ty_syntax) => {
928            resolve_type(db, diagnostics, resolver, &ty_syntax.ty(syntax_db))
929        }
930    };
931
932    let mutability = modifiers::compute_mutability(
933        diagnostics,
934        syntax_db,
935        &ast_param.modifiers(syntax_db).elements(syntax_db),
936    );
937
938    semantic::Parameter {
939        id,
940        name,
941        ty,
942        mutability,
943        stable_ptr: ast_param.name(syntax_db).stable_ptr(),
944    }
945}
946
947// === Function Declaration ===
948
949#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
950#[debug_db(dyn SemanticGroup + 'static)]
951pub struct FunctionDeclarationData {
952    pub diagnostics: Diagnostics<SemanticDiagnostic>,
953    pub signature: semantic::Signature,
954    /// The environment induced by the function's signature.
955    pub environment: Environment,
956    pub generic_params: Vec<semantic::GenericParam>,
957    pub attributes: Vec<Attribute>,
958    pub resolver_data: Arc<ResolverData>,
959    pub inline_config: InlineConfiguration,
960    /// Order of implicits to follow by this function.
961    ///
962    /// For example, this can be used to enforce ABI compatibility with Starknet OS.
963    pub implicit_precedence: ImplicitPrecedence,
964}
965
966#[derive(Debug, PartialEq, Eq, Clone)]
967pub enum InlineConfiguration {
968    /// The user did not specify any inlining preferences.
969    None,
970    Always(Attribute),
971    Should(Attribute),
972    Never(Attribute),
973}
974
975/// If a function with impl generic parameters is marked as '#[inline(always)]', raise a diagnostic.
976pub fn forbid_inline_always_with_impl_generic_param(
977    diagnostics: &mut SemanticDiagnostics,
978    generic_params: &[GenericParam],
979    inline_config: &InlineConfiguration,
980) {
981    let has_impl_generic_param = generic_params.iter().any(|p| matches!(p, GenericParam::Impl(_)));
982    match &inline_config {
983        InlineConfiguration::Always(attr) if has_impl_generic_param => {
984            diagnostics.report(
985                attr.stable_ptr.untyped(),
986                SemanticDiagnosticKind::InlineAlwaysWithImplGenericArgNotAllowed,
987            );
988        }
989        _ => {}
990    }
991}
992
993/// Extra information about sorting of implicit arguments of the function.
994///
995/// In most of the user written code, the implicits are not stated explicitly, but instead are
996/// inferred by the compiler. The order on how these implicit arguments are laid out on Sierra level
997/// is unspecified though for the users. Currently, the compiler sorts them alphabetically by name
998/// for reproducibility, but it can equally just randomize the order on each compilation.
999///
1000/// Some compilation targets tend to expect that particular functions accept particular implicit
1001/// arguments at fixed positions. For example, the Starknet OS has such assumptions. By reading the
1002/// implicit precedence information attached to functions, the compiler can now reliably generate
1003/// compatible code.
1004///
1005/// To set, add the `#[implicit_precedence(...)]` attribute to function declaration. Only free or
1006/// impl functions can have this information defined. For extern functions, the compiler raises an
1007/// error. It is recommended to always create this attribute from compiler plugins, and not force
1008/// users to write it manually.
1009///
1010/// Use [ImplicitPrecedence::UNSPECIFIED] to represent lack of information.
1011#[derive(Clone, Debug, Default, Eq, PartialEq)]
1012pub struct ImplicitPrecedence(Vec<TypeId>);
1013
1014impl ImplicitPrecedence {
1015    /// A precedence that does not actually prefer any implicit.
1016    ///
1017    /// When applied to a sequence of implicits, they will just be reordered alphabetically.
1018    pub const UNSPECIFIED: Self = Self(Vec::new());
1019
1020    /// Sort implicits according to this precedence: first the ones with precedence
1021    /// (according to it), then the others by their name.
1022    pub fn apply(&self, implicits: &mut [TypeId], db: &dyn SemanticGroup) {
1023        implicits.sort_by_cached_key(|implicit| {
1024            if let Some(idx) = self.0.iter().position(|item| item == implicit) {
1025                return (idx, "".to_string());
1026            }
1027
1028            (self.0.len(), implicit.format(db))
1029        });
1030    }
1031}
1032
1033impl FromIterator<TypeId> for ImplicitPrecedence {
1034    fn from_iter<T: IntoIterator<Item = TypeId>>(iter: T) -> Self {
1035        Self(Vec::from_iter(iter))
1036    }
1037}