cairo_lang_defs/
ids.rs

1// The following ids represent all the definitions in the code.
2// Roughly, this refers to the first appearance of each identifier.
3// Everything that can be returned by "Go to definition" is a definition.
4//
5// Examples:
6// * let x = 5.
7// Has a definition for the variable "x".
8// * fn foo<T>(a: T){ return (); }.
9// Has 3 definitions:
10//   * Function "foo".
11//   * Generic parameter "T" (only the first occurrence of "T").
12//   * Function parameter "a".
13// * trait MyTrait{ fn foo() -> (); }
14// Has 2 definitions:
15//   * Trait "MyTrait"
16//   * TraitFunction "foo".
17// * impl A for MyTrait{ fn foo() -> (){...} }
18// Has 2 definitions:
19//   * Impl "A"
20//   * ImplFunction "foo".
21//
22// Call sites, variable usages, assignments, etc. are NOT definitions.
23
24use cairo_lang_debug::debug::DebugWithDb;
25use cairo_lang_diagnostics::Maybe;
26pub use cairo_lang_filesystem::ids::UnstableSalsaId;
27use cairo_lang_filesystem::ids::{CrateId, FileId};
28use cairo_lang_syntax::node::ast::TerminalIdentifierGreen;
29use cairo_lang_syntax::node::db::SyntaxGroup;
30use cairo_lang_syntax::node::helpers::{GetIdentifier, NameGreen};
31use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
32use cairo_lang_syntax::node::kind::SyntaxKind;
33use cairo_lang_syntax::node::stable_ptr::SyntaxStablePtr;
34use cairo_lang_syntax::node::{Terminal, TypedStablePtr, TypedSyntaxNode, ast};
35use cairo_lang_utils::{Intern, LookupIntern, OptionFrom, define_short_id, require};
36use smol_str::SmolStr;
37
38use crate::db::DefsGroup;
39use crate::diagnostic_utils::StableLocation;
40
41// A trait for an id for a language element.
42pub trait LanguageElementId {
43    fn module_file_id(&self, db: &dyn DefsGroup) -> ModuleFileId;
44    fn untyped_stable_ptr(&self, db: &dyn DefsGroup) -> SyntaxStablePtrId;
45
46    fn parent_module(&self, db: &dyn DefsGroup) -> ModuleId {
47        self.module_file_id(db).0
48    }
49    fn file_index(&self, db: &dyn DefsGroup) -> FileIndex {
50        self.module_file_id(db).1
51    }
52
53    fn stable_location(&self, db: &dyn DefsGroup) -> StableLocation;
54}
55
56pub trait NamedLanguageElementLongId {
57    fn name(&self, db: &dyn DefsGroup) -> SmolStr;
58}
59pub trait NamedLanguageElementId: LanguageElementId {
60    fn name(&self, db: &dyn DefsGroup) -> SmolStr;
61}
62pub trait TopLevelLanguageElementId: NamedLanguageElementId {
63    fn full_path(&self, db: &dyn DefsGroup) -> String {
64        format!("{}::{}", self.parent_module(db).full_path(db), self.name(db))
65    }
66}
67
68/// Utility macro for defining an id for a top level language element.
69/// 1. Defines a long id representing some element by a module_id and a stable pointer.
70/// 2. Defines a short id to be used for interning of the long id.
71/// 3. Requires the lookup function name for the lookup of the long id from the short id, as defined
72///    in DefsGroup.
73/// 4. Implements `NamedLanguageElementId` using a key_field. See the documentation of
74///    'define_short_id' and `stable_ptr.rs` for more details.
75macro_rules! define_top_level_language_element_id {
76    ($short_id:ident, $long_id:ident, $ast_ty:ty, $lookup:ident, $intern:ident) => {
77        define_named_language_element_id!($short_id, $long_id, $ast_ty, $lookup, $intern);
78        impl TopLevelLanguageElementId for $short_id {}
79    };
80}
81
82/// Utility macro for defining an id for a language element, with a name but without full path.
83/// This is used by `define_top_level_language_element_id` (see its documentation), but doesn't
84/// implement TopLevelLanguageElementId for the type.
85///
86/// Note: prefer to use `define_top_level_language_element_id`, unless you need to overwrite the
87/// behavior of `TopLevelLanguageElementId` for the type.
88macro_rules! define_named_language_element_id {
89    ($short_id:ident, $long_id:ident, $ast_ty:ty, $lookup:ident, $intern:ident) => {
90        define_language_element_id_basic!($short_id, $long_id, $ast_ty, $lookup, $intern);
91        impl<'a, T: ?Sized + cairo_lang_utils::Upcast<dyn DefsGroup + 'a>>
92            cairo_lang_debug::DebugWithDb<T> for $long_id
93        {
94            fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &T) -> std::fmt::Result {
95                let db: &(dyn DefsGroup + 'a) = db.upcast();
96                let $long_id(module_file_id, _stable_ptr) = self;
97                write!(
98                    f,
99                    "{}({}::{})",
100                    stringify!($short_id),
101                    module_file_id.0.full_path(db),
102                    self.name(db)
103                )
104            }
105        }
106        impl NamedLanguageElementLongId for $long_id {
107            fn name(&self, db: &dyn DefsGroup) -> SmolStr {
108                let syntax_db = db.upcast();
109                let terminal_green = self.1.name_green(syntax_db);
110                terminal_green.identifier(syntax_db)
111            }
112        }
113        impl NamedLanguageElementId for $short_id {
114            fn name(&self, db: &dyn DefsGroup) -> SmolStr {
115                db.$lookup(*self).name(db)
116            }
117        }
118    };
119}
120
121/// Utility macro for defining an id for a language element, without a name and full path.
122/// This is used by `define_named_language_element_id` (see its documentation), but doesn't
123/// implement NamedLanguageElementId for the type.
124///
125/// Use for language elements that are not top level and don't have a name.
126macro_rules! define_language_element_id_basic {
127    ($short_id:ident, $long_id:ident, $ast_ty:ty, $lookup:ident, $intern:ident) => {
128        #[derive(Clone, PartialEq, Eq, Hash, Debug)]
129        pub struct $long_id(pub ModuleFileId, pub <$ast_ty as TypedSyntaxNode>::StablePtr);
130        define_short_id!($short_id, $long_id, DefsGroup, $lookup, $intern);
131        impl $short_id {
132            pub fn stable_ptr(
133                &self,
134                db: &dyn DefsGroup,
135            ) -> <$ast_ty as TypedSyntaxNode>::StablePtr {
136                db.$lookup(*self).1
137            }
138        }
139        impl LanguageElementId for $short_id {
140            fn module_file_id(&self, db: &dyn DefsGroup) -> ModuleFileId {
141                db.$lookup(*self).0
142            }
143            fn untyped_stable_ptr(&self, db: &dyn DefsGroup) -> SyntaxStablePtrId {
144                self.stable_ptr(db).untyped()
145            }
146            fn stable_location(&self, db: &dyn DefsGroup) -> StableLocation {
147                let $long_id(_module_file_id, stable_ptr) = db.$lookup(*self);
148                StableLocation::new(stable_ptr.untyped())
149            }
150        }
151    };
152}
153
154/// Defines and implements LanguageElementId for a subset of other language elements.
155macro_rules! define_language_element_id_as_enum {
156    (
157        #[toplevel]
158        $(#[doc = $doc:expr])*
159        pub enum $enum_name:ident {
160            $($variant:ident ($variant_ty:ty),)*
161        }
162    ) => {
163        toplevel_enum! {
164            pub enum $enum_name {
165                $($variant($variant_ty),)*
166            }
167        }
168        define_language_element_id_as_enum! {
169            $(#[doc = $doc])*
170            pub enum $enum_name {
171                $($variant($variant_ty),)*
172            }
173        }
174    };
175    (
176        $(#[doc = $doc:expr])*
177        pub enum $enum_name:ident {
178            $($variant:ident ($variant_ty:ty),)*
179        }
180    ) => {
181        $(#[doc = $doc])*
182        #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
183        pub enum $enum_name {
184            $($variant($variant_ty),)*
185        }
186        impl<T: ?Sized + cairo_lang_utils::Upcast<dyn DefsGroup + 'static>> cairo_lang_debug::DebugWithDb<T>
187            for $enum_name
188        {
189            fn fmt(
190                &self,
191                f: &mut std::fmt::Formatter<'_>,
192                db: &T,
193            ) -> std::fmt::Result {
194                let db : &(dyn DefsGroup + 'static) = db.upcast();
195                match self {
196                    $(
197                        $enum_name::$variant(id) => id.fmt(f, db),
198                    )*
199                }
200            }
201        }
202        impl LanguageElementId for $enum_name {
203            fn module_file_id(&self, db: &dyn DefsGroup) -> ModuleFileId {
204                match self {
205                    $(
206                        $enum_name::$variant(id) => id.module_file_id(db),
207                    )*
208                }
209            }
210            fn untyped_stable_ptr(&self, db: &dyn DefsGroup) -> SyntaxStablePtrId {
211                match self {
212                    $(
213                        $enum_name::$variant(id) => id.untyped_stable_ptr(db),
214                    )*
215                }
216            }
217            fn stable_location(&self, db: &dyn DefsGroup) -> StableLocation {
218                 match self {
219                    $(
220                        $enum_name::$variant(id) => id.stable_location(db),
221                    )*
222                }
223            }
224
225        }
226
227        // Conversion from enum to its child.
228        $(
229            impl OptionFrom<$enum_name> for $variant_ty {
230                fn option_from(other: $enum_name) -> Option<Self> {
231                    #[allow(irrefutable_let_patterns)]
232                    if let $enum_name::$variant(id) = other {
233                        Some(id)
234                    } else {
235                        None
236                    }
237                }
238            }
239        )*
240    }
241}
242
243macro_rules! toplevel_enum {
244    (
245        pub enum $enum_name:ident {
246            $($variant:ident ($variant_ty:ty),)*
247        }
248    ) => {
249        impl NamedLanguageElementId for $enum_name {
250            fn name(&self, db: &dyn DefsGroup) -> SmolStr {
251                match self {
252                    $(
253                        $enum_name::$variant(id) => id.name(db),
254                    )*
255                }
256            }
257        }
258        impl TopLevelLanguageElementId for $enum_name {}
259    }
260}
261
262/// Id for a module. Either the root module of a crate, or a submodule.
263#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
264pub enum ModuleId {
265    CrateRoot(CrateId),
266    Submodule(SubmoduleId),
267}
268impl ModuleId {
269    pub fn full_path(&self, db: &dyn DefsGroup) -> String {
270        match self {
271            ModuleId::CrateRoot(id) => id.lookup_intern(db).name().into(),
272            ModuleId::Submodule(id) => {
273                format!("{}::{}", id.parent_module(db).full_path(db), id.name(db))
274            }
275        }
276    }
277    pub fn name(&self, db: &dyn DefsGroup) -> SmolStr {
278        match self {
279            ModuleId::CrateRoot(id) => id.lookup_intern(db).name(),
280            ModuleId::Submodule(id) => id.name(db),
281        }
282    }
283    pub fn owning_crate(&self, db: &dyn DefsGroup) -> CrateId {
284        match self {
285            ModuleId::CrateRoot(crate_id) => *crate_id,
286            ModuleId::Submodule(submodule) => submodule.parent_module(db).owning_crate(db),
287        }
288    }
289}
290impl DebugWithDb<dyn DefsGroup> for ModuleId {
291    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn DefsGroup) -> std::fmt::Result {
292        write!(f, "ModuleId({})", self.full_path(db))
293    }
294}
295/// Index of file in module.
296#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq)]
297pub struct FileIndex(pub usize);
298#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
299pub struct ModuleFileId(pub ModuleId, pub FileIndex);
300impl ModuleFileId {
301    pub fn file_id(&self, db: &dyn DefsGroup) -> Maybe<FileId> {
302        Ok(db.module_files(self.0)?[self.1.0])
303    }
304}
305
306/// An id for a file defined out of the filesystem crate, for files generated by plugins.
307#[derive(Clone, Debug, Hash, PartialEq, Eq)]
308pub struct PluginGeneratedFileLongId {
309    /// The module that the file was generated from.
310    pub module_id: ModuleId,
311    /// The stable pointer the file was generated from being ran on.
312    pub stable_ptr: SyntaxStablePtrId,
313    /// The name of the generated file to differentiate between different generated files.
314    pub name: SmolStr,
315}
316define_short_id!(
317    PluginGeneratedFileId,
318    PluginGeneratedFileLongId,
319    DefsGroup,
320    lookup_intern_plugin_generated_file,
321    intern_plugin_generated_file
322);
323
324define_language_element_id_as_enum! {
325    #[toplevel]
326    /// Id for direct children of a module.
327    pub enum ModuleItemId {
328        Constant(ConstantId),
329        Submodule(SubmoduleId),
330        Use(UseId),
331        FreeFunction(FreeFunctionId),
332        Struct(StructId),
333        Enum(EnumId),
334        TypeAlias(ModuleTypeAliasId),
335        ImplAlias(ImplAliasId),
336        Trait(TraitId),
337        Impl(ImplDefId),
338        ExternType(ExternTypeId),
339        ExternFunction(ExternFunctionId),
340    }
341}
342define_top_level_language_element_id!(
343    SubmoduleId,
344    SubmoduleLongId,
345    ast::ItemModule,
346    lookup_intern_submodule,
347    intern_submodule
348);
349impl UnstableSalsaId for SubmoduleId {
350    fn get_internal_id(&self) -> &salsa::InternId {
351        &self.0
352    }
353}
354
355define_top_level_language_element_id!(
356    ConstantId,
357    ConstantLongId,
358    ast::ItemConstant,
359    lookup_intern_constant,
360    intern_constant
361);
362define_language_element_id_basic!(
363    GlobalUseId,
364    GlobalUseLongId,
365    ast::UsePathStar,
366    lookup_intern_global_use,
367    intern_global_use
368);
369define_top_level_language_element_id!(
370    UseId,
371    UseLongId,
372    ast::UsePathLeaf,
373    lookup_intern_use,
374    intern_use
375);
376define_top_level_language_element_id!(
377    FreeFunctionId,
378    FreeFunctionLongId,
379    ast::FunctionWithBody,
380    lookup_intern_free_function,
381    intern_free_function
382);
383
384impl UnstableSalsaId for FreeFunctionId {
385    fn get_internal_id(&self) -> &salsa::InternId {
386        &self.0
387    }
388}
389
390// --- Impls ---
391define_top_level_language_element_id!(
392    ImplDefId,
393    ImplDefLongId,
394    ast::ItemImpl,
395    lookup_intern_impl_def,
396    intern_impl_def
397);
398
399// --- Impl type items ---
400define_named_language_element_id!(
401    ImplTypeDefId,
402    ImplTypeDefLongId,
403    ast::ItemTypeAlias,
404    lookup_intern_impl_type_def,
405    intern_impl_type_def
406);
407impl ImplTypeDefId {
408    pub fn impl_def_id(&self, db: &dyn DefsGroup) -> ImplDefId {
409        let ImplTypeDefLongId(module_file_id, ptr) = self.lookup_intern(db);
410
411        // Impl type ast lies 3 levels below the impl ast.
412        let impl_ptr = ast::ItemImplPtr(ptr.untyped().nth_parent(db.upcast(), 3));
413        ImplDefLongId(module_file_id, impl_ptr).intern(db)
414    }
415}
416impl TopLevelLanguageElementId for ImplTypeDefId {
417    fn full_path(&self, db: &dyn DefsGroup) -> String {
418        format!("{}::{}", self.impl_def_id(db).full_path(db), self.name(db))
419    }
420}
421
422// --- Impl constant items ---
423define_named_language_element_id!(
424    ImplConstantDefId,
425    ImplConstantDefLongId,
426    ast::ItemConstant,
427    lookup_intern_impl_constant_def,
428    intern_impl_constant_def
429);
430impl ImplConstantDefId {
431    pub fn impl_def_id(&self, db: &dyn DefsGroup) -> ImplDefId {
432        let ImplConstantDefLongId(module_file_id, ptr) = self.lookup_intern(db);
433
434        // Impl constant ast lies 3 levels below the impl ast.
435        let impl_ptr = ast::ItemImplPtr(ptr.untyped().nth_parent(db.upcast(), 3));
436        ImplDefLongId(module_file_id, impl_ptr).intern(db)
437    }
438}
439impl TopLevelLanguageElementId for ImplConstantDefId {
440    fn full_path(&self, db: &dyn DefsGroup) -> String {
441        format!("{}::{}", self.impl_def_id(db).full_path(db), self.name(db))
442    }
443}
444
445// --- Impl Impl items ---
446define_named_language_element_id!(
447    ImplImplDefId,
448    ImplImplDefLongId,
449    ast::ItemImplAlias,
450    lookup_intern_impl_impl_def,
451    intern_impl_impl_def
452);
453impl ImplImplDefId {
454    pub fn impl_def_id(&self, db: &dyn DefsGroup) -> ImplDefId {
455        let ImplImplDefLongId(module_file_id, ptr) = self.lookup_intern(db);
456
457        // Impl constant ast lies 3 levels below the impl ast.
458        let impl_ptr = ast::ItemImplPtr(ptr.untyped().nth_parent(db.upcast(), 3));
459        ImplDefLongId(module_file_id, impl_ptr).intern(db)
460    }
461}
462impl TopLevelLanguageElementId for ImplImplDefId {
463    fn full_path(&self, db: &dyn DefsGroup) -> String {
464        format!("{}::{}", self.impl_def_id(db).full_path(db), self.name(db))
465    }
466}
467
468// --- Impl functions ---
469define_named_language_element_id!(
470    ImplFunctionId,
471    ImplFunctionLongId,
472    ast::FunctionWithBody,
473    lookup_intern_impl_function,
474    intern_impl_function
475);
476impl ImplFunctionId {
477    pub fn impl_def_id(&self, db: &dyn DefsGroup) -> ImplDefId {
478        let ImplFunctionLongId(module_file_id, ptr) = self.lookup_intern(db);
479
480        // Impl function ast lies 3 levels below the impl ast.
481        let impl_ptr = ast::ItemImplPtr(ptr.untyped().nth_parent(db.upcast(), 3));
482        ImplDefLongId(module_file_id, impl_ptr).intern(db)
483    }
484}
485impl UnstableSalsaId for ImplFunctionId {
486    fn get_internal_id(&self) -> &salsa::InternId {
487        &self.0
488    }
489}
490impl TopLevelLanguageElementId for ImplFunctionId {
491    fn full_path(&self, db: &dyn DefsGroup) -> String {
492        format!("{}::{}", self.impl_def_id(db).full_path(db), self.name(db))
493    }
494}
495
496define_language_element_id_as_enum! {
497    #[toplevel]
498    /// Represents a function that has a body.
499    pub enum FunctionWithBodyId {
500        Free(FreeFunctionId),
501        Impl(ImplFunctionId),
502        Trait(TraitFunctionId),
503    }
504}
505
506define_top_level_language_element_id!(
507    ExternFunctionId,
508    ExternFunctionLongId,
509    ast::ItemExternFunction,
510    lookup_intern_extern_function,
511    intern_extern_function
512);
513define_top_level_language_element_id!(
514    StructId,
515    StructLongId,
516    ast::ItemStruct,
517    lookup_intern_struct,
518    intern_struct
519);
520define_top_level_language_element_id!(
521    EnumId,
522    EnumLongId,
523    ast::ItemEnum,
524    lookup_intern_enum,
525    intern_enum
526);
527define_top_level_language_element_id!(
528    ModuleTypeAliasId,
529    ModuleTypeAliasLongId,
530    ast::ItemTypeAlias,
531    lookup_intern_module_type_alias,
532    intern_module_type_alias
533);
534define_top_level_language_element_id!(
535    ImplAliasId,
536    ImplAliasLongId,
537    ast::ItemImplAlias,
538    lookup_intern_impl_alias,
539    intern_impl_alias
540);
541define_top_level_language_element_id!(
542    ExternTypeId,
543    ExternTypeLongId,
544    ast::ItemExternType,
545    lookup_intern_extern_type,
546    intern_extern_type
547);
548
549// --- Trait ---
550define_top_level_language_element_id!(
551    TraitId,
552    TraitLongId,
553    ast::ItemTrait,
554    lookup_intern_trait,
555    intern_trait
556);
557
558// --- Trait type items ---
559define_named_language_element_id!(
560    TraitTypeId,
561    TraitTypeLongId,
562    ast::TraitItemType,
563    lookup_intern_trait_type,
564    intern_trait_type
565);
566impl TraitTypeId {
567    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
568        let TraitTypeLongId(module_file_id, ptr) = self.lookup_intern(db);
569        // Trait type ast lies 3 levels below the trait ast.
570        let trait_ptr = ast::ItemTraitPtr(ptr.untyped().nth_parent(db.upcast(), 3));
571        TraitLongId(module_file_id, trait_ptr).intern(db)
572    }
573}
574impl TopLevelLanguageElementId for TraitTypeId {
575    fn full_path(&self, db: &dyn DefsGroup) -> String {
576        format!("{}::{}", self.trait_id(db).full_path(db), self.name(db))
577    }
578}
579impl UnstableSalsaId for TraitTypeId {
580    fn get_internal_id(&self) -> &salsa::InternId {
581        &self.0
582    }
583}
584
585// --- Trait constant items ---
586define_named_language_element_id!(
587    TraitConstantId,
588    TraitConstantLongId,
589    ast::TraitItemConstant,
590    lookup_intern_trait_constant,
591    intern_trait_constant
592);
593impl TraitConstantId {
594    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
595        let TraitConstantLongId(module_file_id, ptr) = self.lookup_intern(db);
596        // Trait constant ast lies 3 levels below the trait ast.
597        let trait_ptr = ast::ItemTraitPtr(ptr.untyped().nth_parent(db.upcast(), 3));
598        TraitLongId(module_file_id, trait_ptr).intern(db)
599    }
600}
601impl TopLevelLanguageElementId for TraitConstantId {
602    fn full_path(&self, db: &dyn DefsGroup) -> String {
603        format!("{}::{}", self.trait_id(db).full_path(db), self.name(db))
604    }
605}
606
607// --- Trait impl items ---
608define_named_language_element_id!(
609    TraitImplId,
610    TraitImplLongId,
611    ast::TraitItemImpl,
612    lookup_intern_trait_impl,
613    intern_trait_impl
614);
615impl TraitImplId {
616    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
617        let TraitImplLongId(module_file_id, ptr) = self.lookup_intern(db);
618        // Trait impl ast lies 3 levels below the trait ast.
619        let trait_ptr = ast::ItemTraitPtr(ptr.untyped().nth_parent(db.upcast(), 3));
620        TraitLongId(module_file_id, trait_ptr).intern(db)
621    }
622}
623impl TopLevelLanguageElementId for TraitImplId {
624    fn full_path(&self, db: &dyn DefsGroup) -> String {
625        format!("{}::{}", self.trait_id(db).full_path(db), self.name(db))
626    }
627}
628
629// --- Trait functions ---
630define_named_language_element_id!(
631    TraitFunctionId,
632    TraitFunctionLongId,
633    ast::TraitItemFunction,
634    lookup_intern_trait_function,
635    intern_trait_function
636);
637impl TraitFunctionId {
638    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
639        let TraitFunctionLongId(module_file_id, ptr) = self.lookup_intern(db);
640        // Trait function ast lies 3 levels below the trait ast.
641        let trait_ptr = ast::ItemTraitPtr(ptr.untyped().nth_parent(db.upcast(), 3));
642        TraitLongId(module_file_id, trait_ptr).intern(db)
643    }
644}
645impl TopLevelLanguageElementId for TraitFunctionId {
646    fn full_path(&self, db: &dyn DefsGroup) -> String {
647        format!("{}::{}", self.trait_id(db).full_path(db), self.name(db))
648    }
649}
650
651// --- Struct items ---
652define_named_language_element_id!(
653    MemberId,
654    MemberLongId,
655    ast::Member,
656    lookup_intern_member,
657    intern_member
658);
659impl MemberId {
660    pub fn struct_id(&self, db: &dyn DefsGroup) -> StructId {
661        let MemberLongId(module_file_id, ptr) = self.lookup_intern(db);
662        let struct_ptr = ast::ItemStructPtr(ptr.untyped().nth_parent(db.upcast(), 2));
663        StructLongId(module_file_id, struct_ptr).intern(db)
664    }
665}
666
667impl TopLevelLanguageElementId for MemberId {
668    fn full_path(&self, db: &dyn DefsGroup) -> String {
669        format!("{}::{}", self.struct_id(db).full_path(db), self.name(db))
670    }
671}
672
673// --- Enum variants ---
674define_named_language_element_id!(
675    VariantId,
676    VariantLongId,
677    ast::Variant,
678    lookup_intern_variant,
679    intern_variant
680);
681impl VariantId {
682    pub fn enum_id(&self, db: &dyn DefsGroup) -> EnumId {
683        let VariantLongId(module_file_id, ptr) = self.lookup_intern(db);
684        let struct_ptr = ast::ItemEnumPtr(ptr.untyped().nth_parent(db.upcast(), 2));
685        EnumLongId(module_file_id, struct_ptr).intern(db)
686    }
687}
688
689impl TopLevelLanguageElementId for VariantId {
690    fn full_path(&self, db: &dyn DefsGroup) -> String {
691        format!("{}::{}", self.enum_id(db).full_path(db), self.name(db))
692    }
693}
694
695define_language_element_id_as_enum! {
696    /// Id for any variable definition.
697    pub enum VarId {
698        Param(ParamId),
699        Local(LocalVarId),
700        Item(StatementItemId),
701        // TODO(spapini): Add var from pattern matching.
702    }
703}
704
705// TODO(spapini): Override full_path for to include parents, for better debug.
706define_top_level_language_element_id!(
707    ParamId,
708    ParamLongId,
709    ast::Param,
710    lookup_intern_param,
711    intern_param
712);
713define_language_element_id_basic!(
714    GenericParamId,
715    GenericParamLongId,
716    ast::GenericParam,
717    lookup_intern_generic_param,
718    intern_generic_param
719);
720impl GenericParamLongId {
721    pub fn name(&self, db: &dyn SyntaxGroup) -> Option<SmolStr> {
722        let SyntaxStablePtr::Child { key_fields, kind, .. } = self.1.0.lookup_intern(db) else {
723            unreachable!()
724        };
725        require(!matches!(
726            kind,
727            SyntaxKind::GenericParamImplAnonymous | SyntaxKind::GenericParamNegativeImpl
728        ))?;
729
730        let name_green = TerminalIdentifierGreen(key_fields[0]);
731        Some(name_green.identifier(db))
732    }
733
734    pub fn debug_name(&self, db: &dyn SyntaxGroup) -> SmolStr {
735        self.name(db).unwrap_or_else(|| "_".into())
736    }
737    pub fn kind(&self, db: &dyn SyntaxGroup) -> GenericKind {
738        let SyntaxStablePtr::Child { kind, .. } = self.1.0.lookup_intern(db) else {
739            unreachable!()
740        };
741        match kind {
742            SyntaxKind::GenericParamType => GenericKind::Type,
743            SyntaxKind::GenericParamConst => GenericKind::Const,
744            SyntaxKind::GenericParamImplNamed | SyntaxKind::GenericParamImplAnonymous => {
745                GenericKind::Impl
746            }
747            SyntaxKind::GenericParamNegativeImpl => GenericKind::NegImpl,
748            _ => unreachable!(),
749        }
750    }
751    /// Retrieves the ID of the generic item holding this generic parameter.
752    pub fn generic_item(&self, db: &dyn DefsGroup) -> GenericItemId {
753        let item_ptr = self.1.0.nth_parent(db.upcast(), 3);
754        GenericItemId::from_ptr(db, self.0, item_ptr)
755    }
756}
757impl GenericParamId {
758    pub fn name(&self, db: &dyn DefsGroup) -> Option<SmolStr> {
759        self.lookup_intern(db).name(db.upcast())
760    }
761    pub fn debug_name(&self, db: &dyn DefsGroup) -> SmolStr {
762        self.lookup_intern(db).debug_name(db.upcast())
763    }
764    pub fn format(&self, db: &dyn DefsGroup) -> String {
765        let long_ids = self.lookup_intern(db);
766        let SyntaxStablePtr::Child { key_fields, kind, .. } = long_ids.1.0.lookup_intern(db) else {
767            unreachable!()
768        };
769
770        let syntax_db = db.upcast();
771        if matches!(
772            kind,
773            SyntaxKind::GenericParamImplAnonymous | SyntaxKind::GenericParamNegativeImpl
774        ) {
775            // For anonymous impls print the declaration.
776            return self.stable_location(db).syntax_node(db).get_text_without_trivia(syntax_db);
777        }
778
779        let name_green = TerminalIdentifierGreen(key_fields[0]);
780        name_green.identifier(syntax_db).into()
781    }
782
783    pub fn kind(&self, db: &dyn DefsGroup) -> GenericKind {
784        self.lookup_intern(db).kind(db.upcast())
785    }
786    pub fn generic_item(&self, db: &dyn DefsGroup) -> GenericItemId {
787        self.lookup_intern(db).generic_item(db.upcast())
788    }
789}
790impl DebugWithDb<dyn DefsGroup> for GenericParamLongId {
791    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn DefsGroup) -> std::fmt::Result {
792        write!(
793            f,
794            "GenericParam{}({}::{})",
795            self.kind(db.upcast()),
796            self.generic_item(db).full_path(db),
797            self.debug_name(db.upcast())
798        )
799    }
800}
801
802define_language_element_id_as_enum! {
803    #[toplevel]
804    /// The ID of a module item with generic parameters.
805    pub enum GenericModuleItemId {
806        FreeFunc(FreeFunctionId),
807        ExternFunc(ExternFunctionId),
808        TraitFunc(TraitFunctionId),
809        ImplFunc(ImplFunctionId),
810        Trait(TraitId),
811        Impl(ImplDefId),
812        Struct(StructId),
813        Enum(EnumId),
814        ExternType(ExternTypeId),
815        TypeAlias(ModuleTypeAliasId),
816        ImplAlias(ImplAliasId),
817    }
818}
819define_language_element_id_as_enum! {
820    #[toplevel]
821    /// The ID of a trait item with generic parameters.
822    pub enum GenericTraitItemId {
823        Type(TraitTypeId),
824    }
825}
826define_language_element_id_as_enum! {
827    #[toplevel]
828    /// The ID of a impl item with generic parameters.
829    pub enum GenericImplItemId {
830        Type(ImplTypeDefId),
831    }
832}
833
834define_language_element_id_as_enum! {
835    #[toplevel]
836    /// The ID of an item with generic parameters.
837    pub enum GenericItemId {
838        ModuleItem(GenericModuleItemId),
839        TraitItem(GenericTraitItemId),
840        ImplItem(GenericImplItemId),
841    }
842}
843impl GenericItemId {
844    pub fn from_ptr(
845        db: &dyn DefsGroup,
846        module_file: ModuleFileId,
847        stable_ptr: SyntaxStablePtrId,
848    ) -> Self {
849        let SyntaxStablePtr::Child { parent: parent0, kind, .. } = stable_ptr.lookup_intern(db)
850        else {
851            panic!()
852        };
853        match kind {
854            SyntaxKind::FunctionDeclaration => {
855                let SyntaxStablePtr::Child { parent: parent1, kind, .. } =
856                    parent0.lookup_intern(db)
857                else {
858                    panic!()
859                };
860                match kind {
861                    SyntaxKind::FunctionWithBody => {
862                        // `FunctionWithBody` must be at least 2 levels below the root, and thus
863                        // `parent1.parent()` is safe.
864                        match parent1.parent(db.upcast()).lookup_intern(db) {
865                            SyntaxStablePtr::Root(_, _) => {
866                                GenericItemId::ModuleItem(GenericModuleItemId::FreeFunc(
867                                    FreeFunctionLongId(
868                                        module_file,
869                                        ast::FunctionWithBodyPtr(parent0),
870                                    )
871                                    .intern(db),
872                                ))
873                            }
874                            SyntaxStablePtr::Child { kind, .. } => match kind {
875                                SyntaxKind::ModuleBody => {
876                                    GenericItemId::ModuleItem(GenericModuleItemId::FreeFunc(
877                                        FreeFunctionLongId(
878                                            module_file,
879                                            ast::FunctionWithBodyPtr(parent0),
880                                        )
881                                        .intern(db),
882                                    ))
883                                }
884                                SyntaxKind::ImplBody => {
885                                    GenericItemId::ModuleItem(GenericModuleItemId::ImplFunc(
886                                        ImplFunctionLongId(
887                                            module_file,
888                                            ast::FunctionWithBodyPtr(parent0),
889                                        )
890                                        .intern(db),
891                                    ))
892                                }
893                                _ => panic!(),
894                            },
895                        }
896                    }
897                    SyntaxKind::ItemExternFunction => {
898                        GenericItemId::ModuleItem(GenericModuleItemId::ExternFunc(
899                            ExternFunctionLongId(module_file, ast::ItemExternFunctionPtr(parent0))
900                                .intern(db),
901                        ))
902                    }
903                    SyntaxKind::TraitItemFunction => {
904                        GenericItemId::ModuleItem(GenericModuleItemId::TraitFunc(
905                            TraitFunctionLongId(module_file, ast::TraitItemFunctionPtr(parent0))
906                                .intern(db),
907                        ))
908                    }
909                    _ => panic!(),
910                }
911            }
912            SyntaxKind::ItemImpl => GenericItemId::ModuleItem(GenericModuleItemId::Impl(
913                ImplDefLongId(module_file, ast::ItemImplPtr(stable_ptr)).intern(db),
914            )),
915            SyntaxKind::ItemTrait => GenericItemId::ModuleItem(GenericModuleItemId::Trait(
916                TraitLongId(module_file, ast::ItemTraitPtr(stable_ptr)).intern(db),
917            )),
918            SyntaxKind::ItemStruct => GenericItemId::ModuleItem(GenericModuleItemId::Struct(
919                StructLongId(module_file, ast::ItemStructPtr(stable_ptr)).intern(db),
920            )),
921            SyntaxKind::ItemEnum => GenericItemId::ModuleItem(GenericModuleItemId::Enum(
922                EnumLongId(module_file, ast::ItemEnumPtr(stable_ptr)).intern(db),
923            )),
924            SyntaxKind::ItemExternType => {
925                GenericItemId::ModuleItem(GenericModuleItemId::ExternType(
926                    ExternTypeLongId(module_file, ast::ItemExternTypePtr(stable_ptr)).intern(db),
927                ))
928            }
929            SyntaxKind::ItemTypeAlias => {
930                // `ItemTypeAlias` must be at least 2 levels below the root, and thus
931                // `parent0.kind()` is safe.
932                match parent0.kind(db.upcast()) {
933                    SyntaxKind::ModuleItemList => {
934                        GenericItemId::ModuleItem(GenericModuleItemId::TypeAlias(
935                            ModuleTypeAliasLongId(module_file, ast::ItemTypeAliasPtr(stable_ptr))
936                                .intern(db),
937                        ))
938                    }
939                    SyntaxKind::ImplItemList => GenericItemId::ImplItem(GenericImplItemId::Type(
940                        ImplTypeDefLongId(module_file, ast::ItemTypeAliasPtr(stable_ptr))
941                            .intern(db),
942                    )),
943                    _ => panic!(),
944                }
945            }
946            SyntaxKind::ItemImplAlias => GenericItemId::ModuleItem(GenericModuleItemId::ImplAlias(
947                ImplAliasLongId(module_file, ast::ItemImplAliasPtr(stable_ptr)).intern(db),
948            )),
949            SyntaxKind::TraitItemType => GenericItemId::TraitItem(GenericTraitItemId::Type(
950                TraitTypeLongId(module_file, ast::TraitItemTypePtr(stable_ptr)).intern(db),
951            )),
952            _ => panic!(),
953        }
954    }
955}
956
957#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
958pub enum GenericKind {
959    Type,
960    Const,
961    Impl,
962    NegImpl,
963}
964impl std::fmt::Display for GenericKind {
965    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
966        match self {
967            GenericKind::Type => write!(f, "Type"),
968            GenericKind::Const => write!(f, "Const"),
969            GenericKind::Impl => write!(f, "Impl"),
970            GenericKind::NegImpl => write!(f, "-Impl"),
971        }
972    }
973}
974
975// TODO(spapini): change this to a binding inside a pattern.
976// TODO(spapini): Override full_path to include parents, for better debug.
977define_language_element_id_basic!(
978    LocalVarId,
979    LocalVarLongId,
980    ast::TerminalIdentifier,
981    lookup_intern_local_var,
982    intern_local_var
983);
984impl DebugWithDb<dyn DefsGroup> for LocalVarLongId {
985    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn DefsGroup) -> std::fmt::Result {
986        let syntax_db = db.upcast();
987        let LocalVarLongId(module_file_id, ptr) = self;
988        let text = ptr.lookup(syntax_db).text(syntax_db);
989        write!(f, "LocalVarId({}::{})", module_file_id.0.full_path(db), text)
990    }
991}
992
993define_top_level_language_element_id!(
994    StatementConstId,
995    StatementConstLongId,
996    ast::ItemConstant,
997    lookup_intern_statement_const,
998    intern_statement_const
999);
1000
1001define_top_level_language_element_id!(
1002    StatementUseId,
1003    StatementUseLongId,
1004    ast::UsePathLeaf,
1005    lookup_intern_statement_use,
1006    intern_statement_use
1007);
1008
1009define_language_element_id_as_enum! {
1010    #[toplevel]
1011    /// The ID of a function's signature in the code.
1012    pub enum FunctionTitleId {
1013        Free(FreeFunctionId),
1014        Extern(ExternFunctionId),
1015        Trait(TraitFunctionId),
1016        Impl(ImplFunctionId),
1017    }
1018}
1019impl FunctionTitleId {
1020    pub fn format(&self, db: &dyn DefsGroup) -> String {
1021        let function_name = match *self {
1022            FunctionTitleId::Free(_) | FunctionTitleId::Extern(_) => self.name(db).into(),
1023            FunctionTitleId::Trait(id) => id.full_path(db),
1024            FunctionTitleId::Impl(id) => id.full_path(db),
1025        };
1026        format!("{}::{}", self.parent_module(db).full_path(db), function_name)
1027    }
1028}
1029
1030define_language_element_id_as_enum! {
1031    #[toplevel]
1032    /// Generic type ids enum.
1033    pub enum GenericTypeId {
1034        Struct(StructId),
1035        Enum(EnumId),
1036        Extern(ExternTypeId),
1037        // TODO(spapini): associated types in impls.
1038    }
1039}
1040impl GenericTypeId {
1041    pub fn format(&self, db: &dyn DefsGroup) -> String {
1042        format!("{}::{}", self.parent_module(db).full_path(db), self.name(db))
1043    }
1044}
1045
1046/// Conversion from ModuleItemId to GenericTypeId.
1047impl OptionFrom<ModuleItemId> for GenericTypeId {
1048    fn option_from(item: ModuleItemId) -> Option<Self> {
1049        match item {
1050            ModuleItemId::Struct(id) => Some(GenericTypeId::Struct(id)),
1051            ModuleItemId::Enum(id) => Some(GenericTypeId::Enum(id)),
1052            ModuleItemId::ExternType(id) => Some(GenericTypeId::Extern(id)),
1053            ModuleItemId::Constant(_)
1054            | ModuleItemId::Submodule(_)
1055            | ModuleItemId::TypeAlias(_)
1056            | ModuleItemId::ImplAlias(_)
1057            | ModuleItemId::Use(_)
1058            | ModuleItemId::FreeFunction(_)
1059            | ModuleItemId::Trait(_)
1060            | ModuleItemId::Impl(_)
1061            | ModuleItemId::ExternFunction(_) => None,
1062        }
1063    }
1064}
1065
1066// Conversion from GenericItemId to LookupItemId.
1067impl From<GenericItemId> for LookupItemId {
1068    fn from(item: GenericItemId) -> Self {
1069        match item {
1070            GenericItemId::ModuleItem(module_item) => match module_item {
1071                GenericModuleItemId::FreeFunc(id) => {
1072                    LookupItemId::ModuleItem(ModuleItemId::FreeFunction(id))
1073                }
1074                GenericModuleItemId::ExternFunc(id) => {
1075                    LookupItemId::ModuleItem(ModuleItemId::ExternFunction(id))
1076                }
1077                GenericModuleItemId::TraitFunc(id) => {
1078                    LookupItemId::TraitItem(TraitItemId::Function(id))
1079                }
1080                GenericModuleItemId::ImplFunc(id) => {
1081                    LookupItemId::ImplItem(ImplItemId::Function(id))
1082                }
1083                GenericModuleItemId::Trait(id) => LookupItemId::ModuleItem(ModuleItemId::Trait(id)),
1084                GenericModuleItemId::Impl(id) => LookupItemId::ModuleItem(ModuleItemId::Impl(id)),
1085                GenericModuleItemId::Struct(id) => {
1086                    LookupItemId::ModuleItem(ModuleItemId::Struct(id))
1087                }
1088                GenericModuleItemId::Enum(id) => LookupItemId::ModuleItem(ModuleItemId::Enum(id)),
1089                GenericModuleItemId::ExternType(id) => {
1090                    LookupItemId::ModuleItem(ModuleItemId::ExternType(id))
1091                }
1092                GenericModuleItemId::TypeAlias(id) => {
1093                    LookupItemId::ModuleItem(ModuleItemId::TypeAlias(id))
1094                }
1095                GenericModuleItemId::ImplAlias(id) => {
1096                    LookupItemId::ModuleItem(ModuleItemId::ImplAlias(id))
1097                }
1098            },
1099            GenericItemId::TraitItem(trait_item) => match trait_item {
1100                GenericTraitItemId::Type(id) => LookupItemId::TraitItem(TraitItemId::Type(id)),
1101            },
1102            GenericItemId::ImplItem(impl_item) => match impl_item {
1103                GenericImplItemId::Type(id) => LookupItemId::ImplItem(ImplItemId::Type(id)),
1104            },
1105        }
1106    }
1107}
1108
1109define_language_element_id_as_enum! {
1110    #[toplevel]
1111    pub enum StatementItemId {
1112        Constant(StatementConstId),
1113        Use(StatementUseId),
1114    }
1115}
1116
1117impl StatementItemId {
1118    pub fn name(&self, db: &dyn DefsGroup) -> SmolStr {
1119        match self {
1120            StatementItemId::Constant(id) => id.name(db),
1121            StatementItemId::Use(id) => id.name(db),
1122        }
1123    }
1124    pub fn name_stable_ptr(&self, db: &dyn DefsGroup) -> SyntaxStablePtrId {
1125        match self {
1126            StatementItemId::Constant(id) => {
1127                id.lookup_intern(db).1.lookup(db.upcast()).name(db.upcast()).stable_ptr().untyped()
1128            }
1129            StatementItemId::Use(id) => {
1130                id.lookup_intern(db).1.lookup(db.upcast()).name_stable_ptr(db.upcast())
1131            }
1132        }
1133    }
1134}
1135
1136define_language_element_id_as_enum! {
1137    #[toplevel]
1138    /// Id for direct children of a trait.
1139    pub enum TraitItemId {
1140        Function(TraitFunctionId),
1141        Type(TraitTypeId),
1142        Constant(TraitConstantId),
1143        Impl(TraitImplId),
1144    }
1145}
1146impl TraitItemId {
1147    pub fn name(&self, db: &dyn DefsGroup) -> SmolStr {
1148        match self {
1149            TraitItemId::Function(id) => id.name(db),
1150            TraitItemId::Type(id) => id.name(db),
1151            TraitItemId::Constant(id) => id.name(db),
1152            TraitItemId::Impl(id) => id.name(db),
1153        }
1154    }
1155    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
1156        match self {
1157            TraitItemId::Function(id) => id.trait_id(db),
1158            TraitItemId::Type(id) => id.trait_id(db),
1159            TraitItemId::Constant(id) => id.trait_id(db),
1160            TraitItemId::Impl(id) => id.trait_id(db),
1161        }
1162    }
1163}
1164
1165define_language_element_id_as_enum! {
1166    #[toplevel]
1167    /// Id for direct children of an impl.
1168    pub enum ImplItemId {
1169        Function(ImplFunctionId),
1170        Type(ImplTypeDefId),
1171        Constant(ImplConstantDefId),
1172        Impl(ImplImplDefId),
1173    }
1174}
1175impl ImplItemId {
1176    pub fn name(&self, db: &dyn DefsGroup) -> SmolStr {
1177        match self {
1178            ImplItemId::Function(id) => id.name(db),
1179            ImplItemId::Type(id) => id.name(db),
1180            ImplItemId::Constant(id) => id.name(db),
1181            ImplItemId::Impl(id) => id.name(db),
1182        }
1183    }
1184    pub fn impl_def_id(&self, db: &dyn DefsGroup) -> ImplDefId {
1185        match self {
1186            ImplItemId::Function(id) => id.impl_def_id(db),
1187            ImplItemId::Type(id) => id.impl_def_id(db),
1188            ImplItemId::Constant(id) => id.impl_def_id(db),
1189            ImplItemId::Impl(id) => id.impl_def_id(db),
1190        }
1191    }
1192}
1193
1194define_language_element_id_as_enum! {
1195    /// Items for resolver lookups.
1196    /// These are top items that hold semantic information.
1197    /// Semantic info lookups should be performed against these items.
1198    pub enum LookupItemId {
1199        ModuleItem(ModuleItemId),
1200        TraitItem(TraitItemId),
1201        ImplItem(ImplItemId),
1202    }
1203}