Skip to main content

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