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