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}
579
580// --- Trait constant items ---
581define_named_language_element_id!(
582    TraitConstantId,
583    TraitConstantLongId,
584    ast::TraitItemConstant,
585    lookup_intern_trait_constant,
586    intern_trait_constant
587);
588impl TraitConstantId {
589    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
590        let TraitConstantLongId(module_file_id, ptr) = self.lookup_intern(db);
591        // Trait constant ast lies 3 levels below the trait ast.
592        let trait_ptr = ast::ItemTraitPtr(ptr.untyped().nth_parent(db.upcast(), 3));
593        TraitLongId(module_file_id, trait_ptr).intern(db)
594    }
595}
596impl TopLevelLanguageElementId for TraitConstantId {
597    fn full_path(&self, db: &dyn DefsGroup) -> String {
598        format!("{}::{}", self.trait_id(db).full_path(db), self.name(db))
599    }
600}
601
602// --- Trait impl items ---
603define_named_language_element_id!(
604    TraitImplId,
605    TraitImplLongId,
606    ast::TraitItemImpl,
607    lookup_intern_trait_impl,
608    intern_trait_impl
609);
610impl TraitImplId {
611    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
612        let TraitImplLongId(module_file_id, ptr) = self.lookup_intern(db);
613        // Trait impl ast lies 3 levels below the trait ast.
614        let trait_ptr = ast::ItemTraitPtr(ptr.untyped().nth_parent(db.upcast(), 3));
615        TraitLongId(module_file_id, trait_ptr).intern(db)
616    }
617}
618impl TopLevelLanguageElementId for TraitImplId {
619    fn full_path(&self, db: &dyn DefsGroup) -> String {
620        format!("{}::{}", self.trait_id(db).full_path(db), self.name(db))
621    }
622}
623
624// --- Trait functions ---
625define_named_language_element_id!(
626    TraitFunctionId,
627    TraitFunctionLongId,
628    ast::TraitItemFunction,
629    lookup_intern_trait_function,
630    intern_trait_function
631);
632impl TraitFunctionId {
633    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
634        let TraitFunctionLongId(module_file_id, ptr) = self.lookup_intern(db);
635        // Trait function ast lies 3 levels below the trait ast.
636        let trait_ptr = ast::ItemTraitPtr(ptr.untyped().nth_parent(db.upcast(), 3));
637        TraitLongId(module_file_id, trait_ptr).intern(db)
638    }
639}
640impl TopLevelLanguageElementId for TraitFunctionId {
641    fn full_path(&self, db: &dyn DefsGroup) -> String {
642        format!("{}::{}", self.trait_id(db).full_path(db), self.name(db))
643    }
644}
645
646// --- Struct items ---
647define_named_language_element_id!(
648    MemberId,
649    MemberLongId,
650    ast::Member,
651    lookup_intern_member,
652    intern_member
653);
654impl MemberId {
655    pub fn struct_id(&self, db: &dyn DefsGroup) -> StructId {
656        let MemberLongId(module_file_id, ptr) = self.lookup_intern(db);
657        let struct_ptr = ast::ItemStructPtr(ptr.untyped().nth_parent(db.upcast(), 2));
658        StructLongId(module_file_id, struct_ptr).intern(db)
659    }
660}
661
662impl TopLevelLanguageElementId for MemberId {
663    fn full_path(&self, db: &dyn DefsGroup) -> String {
664        format!("{}::{}", self.struct_id(db).full_path(db), self.name(db))
665    }
666}
667
668// --- Enum variants ---
669define_named_language_element_id!(
670    VariantId,
671    VariantLongId,
672    ast::Variant,
673    lookup_intern_variant,
674    intern_variant
675);
676impl VariantId {
677    pub fn enum_id(&self, db: &dyn DefsGroup) -> EnumId {
678        let VariantLongId(module_file_id, ptr) = self.lookup_intern(db);
679        let struct_ptr = ast::ItemEnumPtr(ptr.untyped().nth_parent(db.upcast(), 2));
680        EnumLongId(module_file_id, struct_ptr).intern(db)
681    }
682}
683
684impl TopLevelLanguageElementId for VariantId {
685    fn full_path(&self, db: &dyn DefsGroup) -> String {
686        format!("{}::{}", self.enum_id(db).full_path(db), self.name(db))
687    }
688}
689
690define_language_element_id_as_enum! {
691    /// Id for any variable definition.
692    pub enum VarId {
693        Param(ParamId),
694        Local(LocalVarId),
695        Item(StatementItemId),
696        // TODO(spapini): Add var from pattern matching.
697    }
698}
699
700// TODO(spapini): Override full_path for to include parents, for better debug.
701define_top_level_language_element_id!(
702    ParamId,
703    ParamLongId,
704    ast::Param,
705    lookup_intern_param,
706    intern_param
707);
708define_language_element_id_basic!(
709    GenericParamId,
710    GenericParamLongId,
711    ast::GenericParam,
712    lookup_intern_generic_param,
713    intern_generic_param
714);
715impl GenericParamLongId {
716    pub fn name(&self, db: &dyn SyntaxGroup) -> Option<SmolStr> {
717        let SyntaxStablePtr::Child { key_fields, kind, .. } = self.1.0.lookup_intern(db) else {
718            unreachable!()
719        };
720        require(!matches!(
721            kind,
722            SyntaxKind::GenericParamImplAnonymous | SyntaxKind::GenericParamNegativeImpl
723        ))?;
724
725        let name_green = TerminalIdentifierGreen(key_fields[0]);
726        Some(name_green.identifier(db))
727    }
728
729    pub fn debug_name(&self, db: &dyn SyntaxGroup) -> SmolStr {
730        self.name(db).unwrap_or_else(|| "_".into())
731    }
732    pub fn kind(&self, db: &dyn SyntaxGroup) -> GenericKind {
733        let SyntaxStablePtr::Child { kind, .. } = self.1.0.lookup_intern(db) else {
734            unreachable!()
735        };
736        match kind {
737            SyntaxKind::GenericParamType => GenericKind::Type,
738            SyntaxKind::GenericParamConst => GenericKind::Const,
739            SyntaxKind::GenericParamImplNamed | SyntaxKind::GenericParamImplAnonymous => {
740                GenericKind::Impl
741            }
742            SyntaxKind::GenericParamNegativeImpl => GenericKind::NegImpl,
743            _ => unreachable!(),
744        }
745    }
746    /// Retrieves the ID of the generic item holding this generic parameter.
747    pub fn generic_item(&self, db: &dyn DefsGroup) -> GenericItemId {
748        let item_ptr = self.1.0.nth_parent(db.upcast(), 3);
749        GenericItemId::from_ptr(db, self.0, item_ptr)
750    }
751}
752impl GenericParamId {
753    pub fn name(&self, db: &dyn DefsGroup) -> Option<SmolStr> {
754        self.lookup_intern(db).name(db.upcast())
755    }
756    pub fn debug_name(&self, db: &dyn DefsGroup) -> SmolStr {
757        self.lookup_intern(db).debug_name(db.upcast())
758    }
759    pub fn format(&self, db: &dyn DefsGroup) -> String {
760        let long_ids = self.lookup_intern(db);
761        let SyntaxStablePtr::Child { key_fields, kind, .. } = long_ids.1.0.lookup_intern(db) else {
762            unreachable!()
763        };
764
765        let syntax_db = db.upcast();
766        if matches!(
767            kind,
768            SyntaxKind::GenericParamImplAnonymous | SyntaxKind::GenericParamNegativeImpl
769        ) {
770            // For anonymous impls print the declaration.
771            return self.stable_location(db).syntax_node(db).get_text_without_trivia(syntax_db);
772        }
773
774        let name_green = TerminalIdentifierGreen(key_fields[0]);
775        name_green.identifier(syntax_db).into()
776    }
777
778    pub fn kind(&self, db: &dyn DefsGroup) -> GenericKind {
779        self.lookup_intern(db).kind(db.upcast())
780    }
781    pub fn generic_item(&self, db: &dyn DefsGroup) -> GenericItemId {
782        self.lookup_intern(db).generic_item(db.upcast())
783    }
784}
785impl DebugWithDb<dyn DefsGroup> for GenericParamLongId {
786    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn DefsGroup) -> std::fmt::Result {
787        write!(
788            f,
789            "GenericParam{}({}::{})",
790            self.kind(db.upcast()),
791            self.generic_item(db).full_path(db),
792            self.debug_name(db.upcast())
793        )
794    }
795}
796
797define_language_element_id_as_enum! {
798    #[toplevel]
799    /// The ID of a module item with generic parameters.
800    pub enum GenericModuleItemId {
801        FreeFunc(FreeFunctionId),
802        ExternFunc(ExternFunctionId),
803        TraitFunc(TraitFunctionId),
804        ImplFunc(ImplFunctionId),
805        Trait(TraitId),
806        Impl(ImplDefId),
807        Struct(StructId),
808        Enum(EnumId),
809        ExternType(ExternTypeId),
810        TypeAlias(ModuleTypeAliasId),
811        ImplAlias(ImplAliasId),
812    }
813}
814define_language_element_id_as_enum! {
815    #[toplevel]
816    /// The ID of a trait item with generic parameters.
817    pub enum GenericTraitItemId {
818        Type(TraitTypeId),
819    }
820}
821define_language_element_id_as_enum! {
822    #[toplevel]
823    /// The ID of a impl item with generic parameters.
824    pub enum GenericImplItemId {
825        Type(ImplTypeDefId),
826    }
827}
828
829define_language_element_id_as_enum! {
830    #[toplevel]
831    /// The ID of an item with generic parameters.
832    pub enum GenericItemId {
833        ModuleItem(GenericModuleItemId),
834        TraitItem(GenericTraitItemId),
835        ImplItem(GenericImplItemId),
836    }
837}
838impl GenericItemId {
839    pub fn from_ptr(
840        db: &dyn DefsGroup,
841        module_file: ModuleFileId,
842        stable_ptr: SyntaxStablePtrId,
843    ) -> Self {
844        let SyntaxStablePtr::Child { parent: parent0, kind, .. } = stable_ptr.lookup_intern(db)
845        else {
846            panic!()
847        };
848        match kind {
849            SyntaxKind::FunctionDeclaration => {
850                let SyntaxStablePtr::Child { parent: parent1, kind, .. } =
851                    parent0.lookup_intern(db)
852                else {
853                    panic!()
854                };
855                match kind {
856                    SyntaxKind::FunctionWithBody => {
857                        // `FunctionWithBody` must be at least 2 levels below the root, and thus
858                        // `parent1.parent()` is safe.
859                        match parent1.parent(db.upcast()).lookup_intern(db) {
860                            SyntaxStablePtr::Root(_, _) => {
861                                GenericItemId::ModuleItem(GenericModuleItemId::FreeFunc(
862                                    FreeFunctionLongId(
863                                        module_file,
864                                        ast::FunctionWithBodyPtr(parent0),
865                                    )
866                                    .intern(db),
867                                ))
868                            }
869                            SyntaxStablePtr::Child { kind, .. } => match kind {
870                                SyntaxKind::ModuleBody => {
871                                    GenericItemId::ModuleItem(GenericModuleItemId::FreeFunc(
872                                        FreeFunctionLongId(
873                                            module_file,
874                                            ast::FunctionWithBodyPtr(parent0),
875                                        )
876                                        .intern(db),
877                                    ))
878                                }
879                                SyntaxKind::ImplBody => {
880                                    GenericItemId::ModuleItem(GenericModuleItemId::ImplFunc(
881                                        ImplFunctionLongId(
882                                            module_file,
883                                            ast::FunctionWithBodyPtr(parent0),
884                                        )
885                                        .intern(db),
886                                    ))
887                                }
888                                _ => panic!(),
889                            },
890                        }
891                    }
892                    SyntaxKind::ItemExternFunction => {
893                        GenericItemId::ModuleItem(GenericModuleItemId::ExternFunc(
894                            ExternFunctionLongId(module_file, ast::ItemExternFunctionPtr(parent0))
895                                .intern(db),
896                        ))
897                    }
898                    SyntaxKind::TraitItemFunction => {
899                        GenericItemId::ModuleItem(GenericModuleItemId::TraitFunc(
900                            TraitFunctionLongId(module_file, ast::TraitItemFunctionPtr(parent0))
901                                .intern(db),
902                        ))
903                    }
904                    _ => panic!(),
905                }
906            }
907            SyntaxKind::ItemImpl => GenericItemId::ModuleItem(GenericModuleItemId::Impl(
908                ImplDefLongId(module_file, ast::ItemImplPtr(stable_ptr)).intern(db),
909            )),
910            SyntaxKind::ItemTrait => GenericItemId::ModuleItem(GenericModuleItemId::Trait(
911                TraitLongId(module_file, ast::ItemTraitPtr(stable_ptr)).intern(db),
912            )),
913            SyntaxKind::ItemStruct => GenericItemId::ModuleItem(GenericModuleItemId::Struct(
914                StructLongId(module_file, ast::ItemStructPtr(stable_ptr)).intern(db),
915            )),
916            SyntaxKind::ItemEnum => GenericItemId::ModuleItem(GenericModuleItemId::Enum(
917                EnumLongId(module_file, ast::ItemEnumPtr(stable_ptr)).intern(db),
918            )),
919            SyntaxKind::ItemExternType => {
920                GenericItemId::ModuleItem(GenericModuleItemId::ExternType(
921                    ExternTypeLongId(module_file, ast::ItemExternTypePtr(stable_ptr)).intern(db),
922                ))
923            }
924            SyntaxKind::ItemTypeAlias => {
925                // `ItemTypeAlias` must be at least 2 levels below the root, and thus
926                // `parent0.kind()` is safe.
927                match parent0.kind(db.upcast()) {
928                    SyntaxKind::ModuleItemList => {
929                        GenericItemId::ModuleItem(GenericModuleItemId::TypeAlias(
930                            ModuleTypeAliasLongId(module_file, ast::ItemTypeAliasPtr(stable_ptr))
931                                .intern(db),
932                        ))
933                    }
934                    SyntaxKind::ImplItemList => GenericItemId::ImplItem(GenericImplItemId::Type(
935                        ImplTypeDefLongId(module_file, ast::ItemTypeAliasPtr(stable_ptr))
936                            .intern(db),
937                    )),
938                    _ => panic!(),
939                }
940            }
941            SyntaxKind::ItemImplAlias => GenericItemId::ModuleItem(GenericModuleItemId::ImplAlias(
942                ImplAliasLongId(module_file, ast::ItemImplAliasPtr(stable_ptr)).intern(db),
943            )),
944            SyntaxKind::TraitItemType => GenericItemId::TraitItem(GenericTraitItemId::Type(
945                TraitTypeLongId(module_file, ast::TraitItemTypePtr(stable_ptr)).intern(db),
946            )),
947            _ => panic!(),
948        }
949    }
950}
951
952#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
953pub enum GenericKind {
954    Type,
955    Const,
956    Impl,
957    NegImpl,
958}
959impl std::fmt::Display for GenericKind {
960    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
961        match self {
962            GenericKind::Type => write!(f, "Type"),
963            GenericKind::Const => write!(f, "Const"),
964            GenericKind::Impl => write!(f, "Impl"),
965            GenericKind::NegImpl => write!(f, "-Impl"),
966        }
967    }
968}
969
970// TODO(spapini): change this to a binding inside a pattern.
971// TODO(spapini): Override full_path to include parents, for better debug.
972define_language_element_id_basic!(
973    LocalVarId,
974    LocalVarLongId,
975    ast::TerminalIdentifier,
976    lookup_intern_local_var,
977    intern_local_var
978);
979impl DebugWithDb<dyn DefsGroup> for LocalVarLongId {
980    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn DefsGroup) -> std::fmt::Result {
981        let syntax_db = db.upcast();
982        let LocalVarLongId(module_file_id, ptr) = self;
983        let text = ptr.lookup(syntax_db).text(syntax_db);
984        write!(f, "LocalVarId({}::{})", module_file_id.0.full_path(db), text)
985    }
986}
987
988define_top_level_language_element_id!(
989    StatementConstId,
990    StatementConstLongId,
991    ast::ItemConstant,
992    lookup_intern_statement_const,
993    intern_statement_const
994);
995
996define_top_level_language_element_id!(
997    StatementUseId,
998    StatementUseLongId,
999    ast::UsePathLeaf,
1000    lookup_intern_statement_use,
1001    intern_statement_use
1002);
1003
1004define_language_element_id_as_enum! {
1005    #[toplevel]
1006    /// The ID of a function's signature in the code.
1007    pub enum FunctionTitleId {
1008        Free(FreeFunctionId),
1009        Extern(ExternFunctionId),
1010        Trait(TraitFunctionId),
1011        Impl(ImplFunctionId),
1012    }
1013}
1014impl FunctionTitleId {
1015    pub fn format(&self, db: &dyn DefsGroup) -> String {
1016        let function_name = match *self {
1017            FunctionTitleId::Free(_) | FunctionTitleId::Extern(_) => self.name(db).into(),
1018            FunctionTitleId::Trait(id) => id.full_path(db),
1019            FunctionTitleId::Impl(id) => id.full_path(db),
1020        };
1021        format!("{}::{}", self.parent_module(db).full_path(db), function_name)
1022    }
1023}
1024
1025define_language_element_id_as_enum! {
1026    #[toplevel]
1027    /// Generic type ids enum.
1028    pub enum GenericTypeId {
1029        Struct(StructId),
1030        Enum(EnumId),
1031        Extern(ExternTypeId),
1032        // TODO(spapini): associated types in impls.
1033    }
1034}
1035impl GenericTypeId {
1036    pub fn format(&self, db: &dyn DefsGroup) -> String {
1037        format!("{}::{}", self.parent_module(db).full_path(db), self.name(db))
1038    }
1039}
1040
1041/// Conversion from ModuleItemId to GenericTypeId.
1042impl OptionFrom<ModuleItemId> for GenericTypeId {
1043    fn option_from(item: ModuleItemId) -> Option<Self> {
1044        match item {
1045            ModuleItemId::Struct(id) => Some(GenericTypeId::Struct(id)),
1046            ModuleItemId::Enum(id) => Some(GenericTypeId::Enum(id)),
1047            ModuleItemId::ExternType(id) => Some(GenericTypeId::Extern(id)),
1048            ModuleItemId::Constant(_)
1049            | ModuleItemId::Submodule(_)
1050            | ModuleItemId::TypeAlias(_)
1051            | ModuleItemId::ImplAlias(_)
1052            | ModuleItemId::Use(_)
1053            | ModuleItemId::FreeFunction(_)
1054            | ModuleItemId::Trait(_)
1055            | ModuleItemId::Impl(_)
1056            | ModuleItemId::ExternFunction(_) => None,
1057        }
1058    }
1059}
1060
1061// Conversion from GenericItemId to LookupItemId.
1062impl From<GenericItemId> for LookupItemId {
1063    fn from(item: GenericItemId) -> Self {
1064        match item {
1065            GenericItemId::ModuleItem(module_item) => match module_item {
1066                GenericModuleItemId::FreeFunc(id) => {
1067                    LookupItemId::ModuleItem(ModuleItemId::FreeFunction(id))
1068                }
1069                GenericModuleItemId::ExternFunc(id) => {
1070                    LookupItemId::ModuleItem(ModuleItemId::ExternFunction(id))
1071                }
1072                GenericModuleItemId::TraitFunc(id) => {
1073                    LookupItemId::TraitItem(TraitItemId::Function(id))
1074                }
1075                GenericModuleItemId::ImplFunc(id) => {
1076                    LookupItemId::ImplItem(ImplItemId::Function(id))
1077                }
1078                GenericModuleItemId::Trait(id) => LookupItemId::ModuleItem(ModuleItemId::Trait(id)),
1079                GenericModuleItemId::Impl(id) => LookupItemId::ModuleItem(ModuleItemId::Impl(id)),
1080                GenericModuleItemId::Struct(id) => {
1081                    LookupItemId::ModuleItem(ModuleItemId::Struct(id))
1082                }
1083                GenericModuleItemId::Enum(id) => LookupItemId::ModuleItem(ModuleItemId::Enum(id)),
1084                GenericModuleItemId::ExternType(id) => {
1085                    LookupItemId::ModuleItem(ModuleItemId::ExternType(id))
1086                }
1087                GenericModuleItemId::TypeAlias(id) => {
1088                    LookupItemId::ModuleItem(ModuleItemId::TypeAlias(id))
1089                }
1090                GenericModuleItemId::ImplAlias(id) => {
1091                    LookupItemId::ModuleItem(ModuleItemId::ImplAlias(id))
1092                }
1093            },
1094            GenericItemId::TraitItem(trait_item) => match trait_item {
1095                GenericTraitItemId::Type(id) => LookupItemId::TraitItem(TraitItemId::Type(id)),
1096            },
1097            GenericItemId::ImplItem(impl_item) => match impl_item {
1098                GenericImplItemId::Type(id) => LookupItemId::ImplItem(ImplItemId::Type(id)),
1099            },
1100        }
1101    }
1102}
1103
1104define_language_element_id_as_enum! {
1105    #[toplevel]
1106    pub enum StatementItemId {
1107        Constant(StatementConstId),
1108        Use(StatementUseId),
1109    }
1110}
1111
1112impl StatementItemId {
1113    pub fn name(&self, db: &dyn DefsGroup) -> SmolStr {
1114        match self {
1115            StatementItemId::Constant(id) => id.name(db),
1116            StatementItemId::Use(id) => id.name(db),
1117        }
1118    }
1119    pub fn name_stable_ptr(&self, db: &dyn DefsGroup) -> SyntaxStablePtrId {
1120        match self {
1121            StatementItemId::Constant(id) => {
1122                id.lookup_intern(db).1.lookup(db.upcast()).name(db.upcast()).stable_ptr().untyped()
1123            }
1124            StatementItemId::Use(id) => {
1125                id.lookup_intern(db).1.lookup(db.upcast()).name_stable_ptr(db.upcast())
1126            }
1127        }
1128    }
1129}
1130
1131define_language_element_id_as_enum! {
1132    #[toplevel]
1133    /// Id for direct children of a trait.
1134    pub enum TraitItemId {
1135        Function(TraitFunctionId),
1136        Type(TraitTypeId),
1137        Constant(TraitConstantId),
1138        Impl(TraitImplId),
1139    }
1140}
1141impl TraitItemId {
1142    pub fn name(&self, db: &dyn DefsGroup) -> SmolStr {
1143        match self {
1144            TraitItemId::Function(id) => id.name(db),
1145            TraitItemId::Type(id) => id.name(db),
1146            TraitItemId::Constant(id) => id.name(db),
1147            TraitItemId::Impl(id) => id.name(db),
1148        }
1149    }
1150    pub fn trait_id(&self, db: &dyn DefsGroup) -> TraitId {
1151        match self {
1152            TraitItemId::Function(id) => id.trait_id(db),
1153            TraitItemId::Type(id) => id.trait_id(db),
1154            TraitItemId::Constant(id) => id.trait_id(db),
1155            TraitItemId::Impl(id) => id.trait_id(db),
1156        }
1157    }
1158}
1159
1160define_language_element_id_as_enum! {
1161    #[toplevel]
1162    /// Id for direct children of an impl.
1163    pub enum ImplItemId {
1164        Function(ImplFunctionId),
1165        Type(ImplTypeDefId),
1166        Constant(ImplConstantDefId),
1167        Impl(ImplImplDefId),
1168    }
1169}
1170impl ImplItemId {
1171    pub fn name(&self, db: &dyn DefsGroup) -> SmolStr {
1172        match self {
1173            ImplItemId::Function(id) => id.name(db),
1174            ImplItemId::Type(id) => id.name(db),
1175            ImplItemId::Constant(id) => id.name(db),
1176            ImplItemId::Impl(id) => id.name(db),
1177        }
1178    }
1179    pub fn impl_def_id(&self, db: &dyn DefsGroup) -> ImplDefId {
1180        match self {
1181            ImplItemId::Function(id) => id.impl_def_id(db),
1182            ImplItemId::Type(id) => id.impl_def_id(db),
1183            ImplItemId::Constant(id) => id.impl_def_id(db),
1184            ImplItemId::Impl(id) => id.impl_def_id(db),
1185        }
1186    }
1187}
1188
1189define_language_element_id_as_enum! {
1190    /// Items for resolver lookups.
1191    /// These are top items that hold semantic information.
1192    /// Semantic info lookups should be performed against these items.
1193    pub enum LookupItemId {
1194        ModuleItem(ModuleItemId),
1195        TraitItem(TraitItemId),
1196        ImplItem(ImplItemId),
1197    }
1198}