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