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