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