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