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