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