1use std::iter::Peekable;
2use std::marker::PhantomData;
3use std::ops::{Deref, DerefMut};
4use std::sync::Arc;
5
6use cairo_lang_defs::db::DefsGroup;
7use cairo_lang_defs::ids::{
8 GenericKind, GenericParamId, GenericTypeId, ImplDefId, InlineMacroExprPluginId,
9 LanguageElementId, ModuleId, ModuleItemId, TopLevelLanguageElementId, TraitId, TraitItemId,
10 UseId, VariantId,
11};
12use cairo_lang_diagnostics::{Maybe, skip_diagnostic};
13use cairo_lang_filesystem::db::{
14 CORELIB_CRATE_NAME, CrateSettings, FilesGroup, default_crate_settings,
15};
16use cairo_lang_filesystem::ids::{CodeMapping, CrateId, CrateLongId, FileId, SmolStrId};
17use cairo_lang_filesystem::span::TextOffset;
18use cairo_lang_proc_macros::DebugWithDb;
19use cairo_lang_syntax as syntax;
20use cairo_lang_syntax::attribute::consts::DEPRECATED_ATTR;
21use cairo_lang_syntax::node::ast::TerminalIdentifier;
22use cairo_lang_syntax::node::helpers::{GetIdentifier, PathSegmentEx};
23use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
24use cairo_lang_syntax::node::kind::SyntaxKind;
25use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode, ast};
26use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
27use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
28use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
29use cairo_lang_utils::{Intern, extract_matches, require, try_extract_matches};
30pub use item::{ResolvedConcreteItem, ResolvedGenericItem};
31use itertools::Itertools;
32use salsa::Database;
33use syntax::node::TypedStablePtr;
34use syntax::node::helpers::QueryAttrs;
35
36use crate::corelib::CorelibSemantic;
37use crate::diagnostic::SemanticDiagnosticKind::{self, *};
38use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics, SemanticDiagnosticsBuilder};
39use crate::expr::compute::{
40 ComputationContext, Environment, ExpansionOffset, compute_expr_semantic,
41 get_statement_item_by_name,
42};
43use crate::expr::inference::canonic::ResultNoErrEx;
44use crate::expr::inference::conform::InferenceConform;
45use crate::expr::inference::infers::InferenceEmbeddings;
46use crate::expr::inference::{Inference, InferenceData, InferenceId};
47use crate::items::constant::{
48 ConstValue, ConstantSemantic, ImplConstantId, resolve_const_expr_and_evaluate,
49};
50use crate::items::enm::{EnumSemantic, SemanticEnumEx};
51use crate::items::feature_kind::{
52 FeatureConfig, FeatureConfigRestore, FeatureKind, HasFeatureKind, feature_config_from_ast_item,
53 feature_config_from_item_and_parent_modules,
54};
55use crate::items::functions::{GenericFunctionId, ImplGenericFunctionId};
56use crate::items::generics::generic_params_to_args;
57use crate::items::imp::{
58 ConcreteImplId, ConcreteImplLongId, DerefInfo, ImplImplId, ImplLongId, ImplLookupContext,
59 ImplLookupContextId, ImplSemantic,
60};
61use crate::items::impl_alias::ImplAliasSemantic;
62use crate::items::macro_call::MacroCallSemantic;
63use crate::items::module::{ModuleItemInfo, ModuleSemantic};
64use crate::items::module_type_alias::ModuleTypeAliasSemantic;
65use crate::items::trt::{
66 ConcreteTraitConstantLongId, ConcreteTraitGenericFunctionLongId, ConcreteTraitId,
67 ConcreteTraitImplLongId, ConcreteTraitLongId, ConcreteTraitTypeId, TraitSemantic,
68};
69use crate::items::us::{UseAsPathSegments, UseSemantic, get_use_path_segments};
70use crate::items::{TraitOrImplContext, visibility};
71use crate::keyword::{
72 CRATE_KW, MACRO_CALL_SITE, MACRO_DEF_SITE, SELF_PARAM_KW, SELF_TYPE_KW, SUPER_KW,
73};
74use crate::substitution::{GenericSubstitution, SemanticRewriter};
75use crate::types::{
76 ConcreteEnumLongId, ImplTypeId, TypesSemantic, are_coupons_enabled, resolve_type,
77};
78use crate::{
79 ConcreteFunction, ConcreteTypeId, ConcreteVariant, FunctionId, FunctionLongId,
80 GenericArgumentId, GenericParam, Member, Mutability, TypeId, TypeLongId,
81};
82
83#[cfg(test)]
84mod test;
85
86mod item;
87
88const STARKNET_CRATE_NAME: &str = "starknet";
90
91#[derive(Clone, Default, Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
94#[debug_db(dyn Database)]
95pub struct ResolvedItems<'db> {
96 pub concrete: UnorderedHashMap<ast::TerminalIdentifierPtr<'db>, ResolvedConcreteItem<'db>>,
97 pub generic: UnorderedHashMap<ast::TerminalIdentifierPtr<'db>, ResolvedGenericItem<'db>>,
98}
99impl<'db> ResolvedItems<'db> {
100 pub fn mark_concrete(
103 &mut self,
104 db: &'db dyn Database,
105 segment: &syntax::node::ast::PathSegment<'db>,
106 resolved_item: ResolvedConcreteItem<'db>,
107 ) -> ResolvedConcreteItem<'db> {
108 let identifier = segment.identifier_ast(db);
109 if let Some(generic_item) = resolved_item.generic(db) {
110 self.generic.insert(identifier.stable_ptr(db), generic_item);
112 }
113 self.concrete.insert(identifier.stable_ptr(db), resolved_item.clone());
114 resolved_item
115 }
116 pub fn mark_generic(
119 &mut self,
120 db: &'db dyn Database,
121 segment: &syntax::node::ast::PathSegment<'db>,
122 resolved_item: ResolvedGenericItem<'db>,
123 ) -> ResolvedGenericItem<'db> {
124 let identifier = segment.identifier_ast(db);
125 self.generic.insert(identifier.stable_ptr(db), resolved_item.clone());
126 resolved_item
127 }
128}
129
130#[derive(Debug, PartialEq, Eq, DebugWithDb, Clone, salsa::Update)]
133#[debug_db(dyn Database)]
134pub struct EnrichedMembers<'db> {
135 pub members: OrderedHashMap<SmolStrId<'db>, (Member<'db>, usize)>,
138 pub deref_chain: Arc<Vec<DerefInfo<'db>>>,
140 pub explored_derefs: usize,
142}
143impl<'db> EnrichedMembers<'db> {
144 pub fn get_member(&self, name: SmolStrId<'db>) -> Option<EnrichedTypeMemberAccess<'db>> {
146 let (member, n_derefs) = self.members.get(&name)?;
147 Some(EnrichedTypeMemberAccess {
148 member: member.clone(),
149 deref_functions: self
150 .deref_chain
151 .iter()
152 .map(|deref_info| (deref_info.function_id, deref_info.self_mutability))
153 .take(*n_derefs)
154 .collect(),
155 })
156 }
157}
158
159pub struct EnrichedTypeMemberAccess<'db> {
162 pub member: Member<'db>,
164 pub deref_functions: Vec<(FunctionId<'db>, Mutability)>,
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, DebugWithDb)]
169#[debug_db(dyn Database)]
170enum MacroContextModifier {
171 DefSite,
173 CallSite,
175 None,
177}
178
179#[derive(Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
180#[debug_db(dyn Database)]
181pub struct ResolverData<'db> {
182 pub module_id: ModuleId<'db>,
184 generic_param_by_name: OrderedHashMap<SmolStrId<'db>, GenericParamId<'db>>,
186 pub generic_params: Vec<GenericParamId<'db>>,
188 pub type_enriched_members: OrderedHashMap<(TypeId<'db>, bool), EnrichedMembers<'db>>,
190 pub resolved_items: ResolvedItems<'db>,
192 pub inference_data: InferenceData<'db>,
194 pub trait_or_impl_ctx: TraitOrImplContext<'db>,
196 pub feature_config: FeatureConfig<'db>,
198 pub used_uses: OrderedHashSet<UseId<'db>>,
200 pub files: Vec<FileId<'db>>,
202}
203impl<'db> ResolverData<'db> {
204 pub fn new(module_id: ModuleId<'db>, inference_id: InferenceId<'db>) -> Self {
205 Self {
206 module_id,
207 generic_param_by_name: Default::default(),
208 generic_params: Default::default(),
209 type_enriched_members: Default::default(),
210 resolved_items: Default::default(),
211 inference_data: InferenceData::new(inference_id),
212 trait_or_impl_ctx: TraitOrImplContext::None,
213 feature_config: Default::default(),
214 used_uses: Default::default(),
215 files: vec![],
216 }
217 }
218 pub fn clone_with_inference_id(
219 &self,
220 db: &'db dyn Database,
221 inference_id: InferenceId<'db>,
222 ) -> Self {
223 Self {
224 module_id: self.module_id,
225 generic_param_by_name: self.generic_param_by_name.clone(),
226 generic_params: self.generic_params.clone(),
227 type_enriched_members: self.type_enriched_members.clone(),
228 resolved_items: self.resolved_items.clone(),
229 inference_data: self.inference_data.clone_with_inference_id(db, inference_id),
230 trait_or_impl_ctx: self.trait_or_impl_ctx,
231 feature_config: self.feature_config.clone(),
232 used_uses: self.used_uses.clone(),
233 files: self.files.clone(),
234 }
235 }
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
240pub struct ResolverMacroData<'db> {
241 pub defsite_module_id: ModuleId<'db>,
244 pub callsite_module_id: ModuleId<'db>,
249 pub expansion_mappings: Arc<[CodeMapping]>,
252 pub parent_macro_call_data: Option<Arc<ResolverMacroData<'db>>>,
255}
256
257struct MacroResolutionInfo<'db> {
259 base: ModuleId<'db>,
261 data: Option<Arc<ResolverMacroData<'db>>>,
263 modifier: MacroContextModifier,
265}
266impl<'db> MacroResolutionInfo<'db> {
267 fn from_resolver(resolver: &Resolver<'db>) -> Self {
268 Self {
269 base: resolver.data.module_id,
270 data: resolver.macro_call_data.clone(),
271 modifier: MacroContextModifier::None,
272 }
273 }
274}
275
276pub struct Resolver<'db> {
278 db: &'db dyn Database,
279 pub data: ResolverData<'db>,
280 pub macro_call_data: Option<Arc<ResolverMacroData<'db>>>,
283 pub default_module_allowed: bool,
286 pub owning_crate_id: CrateId<'db>,
287 pub settings: CrateSettings,
288}
289impl<'db> Deref for Resolver<'db> {
290 type Target = ResolverData<'db>;
291
292 fn deref(&self) -> &Self::Target {
293 &self.data
294 }
295}
296impl DerefMut for Resolver<'_> {
297 fn deref_mut(&mut self) -> &mut Self::Target {
298 &mut self.data
299 }
300}
301impl<'db> Resolver<'db> {
302 pub fn set_feature_config(
305 &mut self,
306 element_id: &impl LanguageElementId<'db>,
307 syntax: &impl QueryAttrs<'db>,
308 diagnostics: &mut SemanticDiagnostics<'db>,
309 ) {
310 self.feature_config =
311 feature_config_from_item_and_parent_modules(self.db, element_id, syntax, diagnostics);
312 }
313
314 pub fn extend_feature_config_from_item(
318 &mut self,
319 db: &'db dyn Database,
320 crate_id: CrateId<'db>,
321 diagnostics: &mut SemanticDiagnostics<'db>,
322 item: &impl QueryAttrs<'db>,
323 ) -> FeatureConfigRestore<'db> {
324 self.data.feature_config.override_with(feature_config_from_ast_item(
325 db,
326 crate_id,
327 item,
328 diagnostics,
329 ))
330 }
331
332 pub fn restore_feature_config(&mut self, restore: FeatureConfigRestore<'db>) {
335 self.data.feature_config.restore(restore);
336 }
337}
338
339pub enum ResolutionContext<'a, 'mt> {
340 Default,
342 ModuleItem(ModuleItemId<'a>),
344 Statement(&'mt mut Environment<'a>),
346}
347
348enum UseStarResult<'db> {
350 UniquePathFound(ModuleItemInfo<'db>),
352 AmbiguousPath(Vec<ModuleItemId<'db>>),
354 PathNotFound,
356 ItemNotVisible(ModuleItemId<'db>, Vec<ModuleId<'db>>),
358}
359
360pub trait AsSegments<'db> {
362 fn to_segments(self, db: &'db dyn Database) -> Vec<ast::PathSegment<'db>>;
363 fn placeholder_marker(&self, db: &'db dyn Database) -> Option<ast::TerminalDollar<'db>>;
366 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset>;
368}
369impl<'db> AsSegments<'db> for &ast::ExprPath<'db> {
370 fn to_segments(self, db: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
371 self.segments(db).elements_vec(db)
372 }
373 fn placeholder_marker(&self, db: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
374 match self.dollar(db) {
375 ast::OptionTerminalDollar::Empty(_) => None,
376 ast::OptionTerminalDollar::TerminalDollar(dollar) => Some(dollar),
377 }
378 }
379
380 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
381 Some(self.as_syntax_node().offset(db))
382 }
383}
384impl<'db> AsSegments<'db> for Vec<ast::PathSegment<'db>> {
385 fn to_segments(self, _: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
386 self
387 }
388 fn placeholder_marker(&self, _: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
389 None
392 }
393 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
394 self.first().map(|segment| segment.as_syntax_node().offset(db))
395 }
396}
397impl<'db> AsSegments<'db> for UseAsPathSegments<'db> {
398 fn to_segments(self, _: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
399 self.segments
400 }
401
402 fn placeholder_marker(&self, _: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
403 self.is_placeholder.clone()
404 }
405
406 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
407 if let Some(ref dollar) = self.is_placeholder {
408 Some(dollar.as_syntax_node().offset(db))
409 } else {
410 self.segments.first().map(|segment| segment.as_syntax_node().offset(db))
411 }
412 }
413}
414
415impl<'db> Resolver<'db> {
416 pub fn new(
417 db: &'db dyn Database,
418 module_id: ModuleId<'db>,
419 inference_id: InferenceId<'db>,
420 ) -> Self {
421 Self::with_data(db, ResolverData::new(module_id, inference_id))
422 }
423
424 pub fn with_data(db: &'db dyn Database, data: ResolverData<'db>) -> Self {
425 let owning_crate_id = data.module_id.owning_crate(db);
426 let macro_call_data = match data.module_id {
427 ModuleId::CrateRoot(_) | ModuleId::Submodule(_) => None,
428 ModuleId::MacroCall { id, .. } => match db.priv_macro_call_data(id) {
429 Ok(data) => Some(
430 ResolverMacroData {
431 defsite_module_id: data.defsite_module_id,
432 callsite_module_id: data.callsite_module_id,
433 expansion_mappings: data.expansion_mappings.clone(),
434 parent_macro_call_data: data.parent_macro_call_data,
435 }
436 .into(),
437 ),
438 Err(_) => None,
439 },
440 };
441 Self {
442 owning_crate_id,
443 settings: db
444 .crate_config(owning_crate_id)
445 .map(|c| c.settings.clone())
446 .unwrap_or_default(),
447 db,
448 data,
449 default_module_allowed: macro_call_data.is_some(),
450 macro_call_data,
451 }
452 }
453
454 pub fn inference(&mut self) -> Inference<'db, '_> {
455 self.data.inference_data.inference(self.db)
456 }
457
458 pub fn add_generic_param(&mut self, generic_param_id: GenericParamId<'db>) {
462 self.generic_params.push(generic_param_id);
463 if let Some(name) = generic_param_id.name(self.db) {
464 self.generic_param_by_name.insert(name, generic_param_id);
465 }
466 }
467
468 pub fn set_default_module_allowed(&mut self, default_module_allowed: bool) {
469 self.default_module_allowed = default_module_allowed;
470 }
471
472 fn active_module_id(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
475 if let Some(data) = &info.data {
476 match info.modifier {
477 MacroContextModifier::DefSite => data.defsite_module_id,
478 MacroContextModifier::CallSite => data.callsite_module_id,
479 MacroContextModifier::None => info.base,
480 }
481 } else {
482 assert_eq!(info.modifier, MacroContextModifier::None);
483 info.base
484 }
485 }
486
487 fn try_get_active_module_id(&self, info: &MacroResolutionInfo<'db>) -> Option<ModuleId<'db>> {
490 if let Some(data) = &info.data {
491 match info.modifier {
492 MacroContextModifier::DefSite => Some(data.defsite_module_id),
493 MacroContextModifier::CallSite => Some(data.callsite_module_id),
494 MacroContextModifier::None => (data.callsite_module_id != info.base
495 || self.default_module_allowed)
496 .then_some(info.base),
497 }
498 } else {
499 Some(info.base)
500 }
501 }
502
503 fn active_owning_crate_id(&self, info: &MacroResolutionInfo<'db>) -> CrateId<'db> {
506 self.active_module_id(info).owning_crate(self.db)
507 }
508
509 fn active_settings(&self, info: &MacroResolutionInfo<'db>) -> &CrateSettings {
512 self.db
513 .crate_config(self.active_owning_crate_id(info))
514 .map(|c| &c.settings)
515 .unwrap_or_else(|| default_crate_settings(self.db))
516 }
517
518 pub fn resolve_concrete_path(
522 &mut self,
523 diagnostics: &mut SemanticDiagnostics<'db>,
524 path: impl AsSegments<'db>,
525 item_type: NotFoundItemType,
526 ) -> Maybe<ResolvedConcreteItem<'db>> {
527 self.resolve_concrete_path_ex(diagnostics, path, item_type, ResolutionContext::Default)
528 }
529
530 pub fn resolve_concrete_path_ex(
533 &mut self,
534 diagnostics: &mut SemanticDiagnostics<'db>,
535 path: impl AsSegments<'db>,
536 item_type: NotFoundItemType,
537 ctx: ResolutionContext<'db, '_>,
538 ) -> Maybe<ResolvedConcreteItem<'db>> {
539 Resolution::new(self, diagnostics, path, item_type, ctx)?.full::<ResolvedConcreteItem<'db>>(
540 ResolutionCallbacks {
541 _phantom: PhantomData,
542 first: |resolution| resolution.first_concrete(),
543 next: |resolution, item, segment| resolution.next_concrete(item, segment),
544 validate: |_, _| Ok(()),
545 mark: |resolved_items: &mut ResolvedItems<'db>, db, segment, item| {
546 resolved_items.mark_concrete(db, segment, item);
547 },
548 },
549 )
550 }
551
552 pub fn resolve_generic_path(
555 &mut self,
556 diagnostics: &mut SemanticDiagnostics<'db>,
557 path: impl AsSegments<'db>,
558 item_type: NotFoundItemType,
559 ctx: ResolutionContext<'db, '_>,
560 ) -> Maybe<ResolvedGenericItem<'db>> {
561 self.resolve_generic_path_inner(diagnostics, path, item_type, false, ctx)
562 }
563
564 pub fn resolve_plugin_macro(
567 &mut self,
568 path: &ast::ExprPath<'db>,
569 ctx: ResolutionContext<'db, '_>,
570 ) -> Option<InlineMacroExprPluginId<'db>> {
571 let mut diagnostics = SemanticDiagnostics::new(self.module_id);
572 let resolution =
573 Resolution::new(self, &mut diagnostics, path, NotFoundItemType::Macro, ctx).ok()?;
574 let macro_name = resolution.segments.exactly_one().ok()?;
575 let macro_info = resolution.macro_info;
576 let crate_id = self.active_owning_crate_id(¯o_info);
577 let db = self.db;
578 db.crate_inline_macro_plugins(crate_id)
579 .get(macro_name.identifier(db).long(db).as_str())
580 .cloned()
581 }
582
583 pub fn resolve_use_path(
587 &mut self,
588 diagnostics: &mut SemanticDiagnostics<'db>,
589 use_path: ast::UsePath<'db>,
590 ctx: ResolutionContext<'db, '_>,
591 ) -> Maybe<ResolvedGenericItem<'db>> {
592 let mut segments = get_use_path_segments(self.db, use_path.clone())?;
593 if let Some(last) = segments.segments.last()
595 && last.identifier(self.db).long(self.db) == SELF_PARAM_KW
596 {
597 if use_path.as_syntax_node().parent_kind(self.db).unwrap() != SyntaxKind::UsePathList {
599 diagnostics.report(use_path.stable_ptr(self.db), UseSelfNonMulti);
600 }
601 segments.segments.pop();
602 }
603 if segments.segments.is_empty() {
604 return Err(diagnostics.report(use_path.stable_ptr(self.db), UseSelfEmptyPath));
605 }
606 self.resolve_generic_path(diagnostics, segments, NotFoundItemType::Identifier, ctx)
607 }
608
609 pub fn resolve_generic_path_with_args(
612 &mut self,
613 diagnostics: &mut SemanticDiagnostics<'db>,
614 path: impl AsSegments<'db>,
615 item_type: NotFoundItemType,
616 ctx: ResolutionContext<'db, '_>,
617 ) -> Maybe<ResolvedGenericItem<'db>> {
618 self.resolve_generic_path_inner(diagnostics, path, item_type, true, ctx)
619 }
620
621 fn resolve_generic_path_inner(
626 &mut self,
627 diagnostics: &mut SemanticDiagnostics<'db>,
628 path: impl AsSegments<'db>,
629 item_type: NotFoundItemType,
630 allow_generic_args: bool,
631 ctx: ResolutionContext<'db, '_>,
632 ) -> Maybe<ResolvedGenericItem<'db>> {
633 let validate = |diagnostics: &mut SemanticDiagnostics<'db>,
634 segment: &ast::PathSegment<'db>| {
635 match segment {
636 ast::PathSegment::WithGenericArgs(generic_args) if !allow_generic_args => {
637 Err(diagnostics.report(generic_args.stable_ptr(self.db), UnexpectedGenericArgs))
638 }
639 _ => Ok(()),
640 }
641 };
642 Resolution::new(self, diagnostics, path, item_type, ctx)?.full::<ResolvedGenericItem<'_>>(
643 ResolutionCallbacks {
644 _phantom: PhantomData,
645 first: |resolution| resolution.first_generic(allow_generic_args),
646 next: |resolution, item, segment| resolution.next_generic(item, segment),
647 validate,
648 mark: |resolved_items, db, segment, item| {
649 resolved_items.mark_generic(db, segment, item);
650 },
651 },
652 )
653 }
654
655 fn specialize_generic_module_item(
657 &mut self,
658 diagnostics: &mut SemanticDiagnostics<'db>,
659 identifier: &syntax::node::ast::TerminalIdentifier<'db>,
660 generic_item: ResolvedGenericItem<'db>,
661 generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
662 ) -> Maybe<ResolvedConcreteItem<'db>> {
663 let db: &'db dyn Database = self.db;
664 Ok(match generic_item {
665 ResolvedGenericItem::GenericConstant(id) => {
666 ResolvedConcreteItem::Constant(db.constant_const_value(id)?)
667 }
668 ResolvedGenericItem::Module(module_id) => {
669 if generic_args_syntax.is_some() {
670 return Err(
671 diagnostics.report(identifier.stable_ptr(db), UnexpectedGenericArgs)
672 );
673 }
674 ResolvedConcreteItem::Module(module_id)
675 }
676 ResolvedGenericItem::GenericFunction(generic_function) => {
677 ResolvedConcreteItem::Function(self.specialize_function(
678 diagnostics,
679 identifier.stable_ptr(db).untyped(),
680 generic_function,
681 &generic_args_syntax.unwrap_or_default(),
682 )?)
683 }
684 ResolvedGenericItem::GenericType(generic_type) => {
685 ResolvedConcreteItem::Type(self.specialize_type(
686 diagnostics,
687 identifier.stable_ptr(db).untyped(),
688 generic_type,
689 &generic_args_syntax.unwrap_or_default(),
690 )?)
691 }
692 ResolvedGenericItem::GenericTypeAlias(module_type_alias_id) => {
693 let ty = self.db.module_type_alias_resolved_type(module_type_alias_id)?;
694 let generic_params =
695 self.db.module_type_alias_generic_params(module_type_alias_id)?;
696 let generic_args = self.resolve_generic_args(
697 diagnostics,
698 GenericSubstitution::default(),
699 &generic_params,
700 &generic_args_syntax.unwrap_or_default(),
701 identifier.stable_ptr(db).untyped(),
702 )?;
703 ResolvedConcreteItem::Type(
704 GenericSubstitution::new(&generic_params, &generic_args).substitute(db, ty)?,
705 )
706 }
707 ResolvedGenericItem::GenericImplAlias(impl_alias_id) => {
708 let impl_id = db.impl_alias_resolved_impl(impl_alias_id)?;
709 let generic_params = db.impl_alias_generic_params(impl_alias_id)?;
710 let generic_args = self.resolve_generic_args(
711 diagnostics,
712 GenericSubstitution::default(),
713 &generic_params,
714 &generic_args_syntax.unwrap_or_default(),
715 identifier.stable_ptr(db).untyped(),
716 )?;
717 ResolvedConcreteItem::Impl(
718 GenericSubstitution::new(&generic_params, &generic_args)
719 .substitute(db, impl_id)?,
720 )
721 }
722 ResolvedGenericItem::Trait(trait_id) => {
723 ResolvedConcreteItem::Trait(self.specialize_trait(
724 diagnostics,
725 identifier.stable_ptr(db).untyped(),
726 trait_id,
727 &generic_args_syntax.unwrap_or_default(),
728 )?)
729 }
730 ResolvedGenericItem::Impl(impl_def_id) => ResolvedConcreteItem::Impl(
731 ImplLongId::Concrete(self.specialize_impl(
732 diagnostics,
733 identifier.stable_ptr(db).untyped(),
734 impl_def_id,
735 &generic_args_syntax.unwrap_or_default(),
736 )?)
737 .intern(self.db),
738 ),
739 ResolvedGenericItem::Macro(macro_declaration_id) => {
740 ResolvedConcreteItem::Macro(macro_declaration_id)
741 }
742 ResolvedGenericItem::Variant(var) => {
743 ResolvedConcreteItem::Variant(self.specialize_variant(
744 diagnostics,
745 identifier.stable_ptr(db).untyped(),
746 var.id,
747 &generic_args_syntax.unwrap_or_default(),
748 )?)
749 }
750 ResolvedGenericItem::Variable(_) => panic!("Variable is not a module item."),
751 ResolvedGenericItem::TraitItem(id) => {
752 panic!("`{}` is not a module item.", id.full_path(db))
753 }
754 })
755 }
756
757 fn resolve_path_using_use_star(
759 &mut self,
760 module_id: ModuleId<'db>,
761 ident: SmolStrId<'db>,
762 ) -> UseStarResult<'db> {
763 let mut item_info = None;
764 let mut module_items_found: OrderedHashSet<ModuleItemId<'_>> = OrderedHashSet::default();
765 let mut other_containing_modules = vec![];
766 for (item_module_id, info) in self.db.module_imported_modules((), module_id).iter() {
767 if *item_module_id == module_id {
769 continue;
770 }
771 if let Some(inner_item_info) =
772 self.resolve_item_in_module_or_expanded_macro(*item_module_id, ident)
773 {
774 if info.user_modules.iter().any(|user_module_id| {
775 self.is_item_visible(*item_module_id, &inner_item_info, *user_module_id)
776 }) {
777 item_info = Some(inner_item_info.clone());
778 module_items_found.insert(inner_item_info.item_id);
779 } else {
780 other_containing_modules.push(*item_module_id);
781 }
782 }
783 }
784 if module_items_found.len() > 1 {
785 return UseStarResult::AmbiguousPath(module_items_found.iter().cloned().collect());
786 }
787 match item_info {
788 Some(item_info) => UseStarResult::UniquePathFound(item_info),
789 None => {
790 for item_module_id in &other_containing_modules {
791 if let Some(inner_item_info) =
792 self.resolve_item_in_module_or_expanded_macro(*item_module_id, ident)
793 {
794 item_info = Some(inner_item_info.clone());
795 module_items_found.insert(inner_item_info.item_id);
796 }
797 }
798 if let Some(item_info) = item_info {
799 if module_items_found.len() > 1 {
800 UseStarResult::AmbiguousPath(module_items_found.iter().cloned().collect())
801 } else {
802 UseStarResult::ItemNotVisible(item_info.item_id, other_containing_modules)
803 }
804 } else {
805 UseStarResult::PathNotFound
806 }
807 }
808 }
809 }
810
811 pub fn resolve_item_in_module(
816 &mut self,
817 module_id: ModuleId<'db>,
818 ident: SmolStrId<'db>,
819 ) -> Option<ModuleItemInfo<'db>> {
820 self.resolve_item_in_module_ex(module_id, ident).ok()
821 }
822
823 fn resolve_item_in_module_ex(
828 &mut self,
829 module_id: ModuleId<'db>,
830 ident: SmolStrId<'db>,
831 ) -> Result<ModuleItemInfo<'db>, SemanticDiagnosticKind<'db>> {
832 if let Some(info) = self.resolve_item_in_module_or_expanded_macro(module_id, ident) {
833 return Ok(info);
834 }
835 match self.resolve_path_using_use_star(module_id, ident) {
836 UseStarResult::UniquePathFound(info) => Ok(info),
837 UseStarResult::AmbiguousPath(items) => Err(AmbiguousPath(items)),
838 UseStarResult::PathNotFound => Err(PathNotFound(NotFoundItemType::Identifier)),
839 UseStarResult::ItemNotVisible(item, modules) => Err(ItemNotVisible(item, modules)),
840 }
841 }
842
843 fn resolve_item_in_module_or_expanded_macro(
845 &mut self,
846 module_id: ModuleId<'db>,
847 ident: SmolStrId<'db>,
848 ) -> Option<ModuleItemInfo<'db>> {
849 if let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
850 self.insert_used_use(info.item_id);
851 return Some(info);
852 }
853 let mut stack = vec![(module_id, false)];
854 loop {
855 let (module_id, expose) = stack.pop()?;
856 if expose && let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
857 self.insert_used_use(info.item_id);
858 return Some(info);
859 }
860 if let Ok(macro_calls) = self.db.module_macro_calls_ids(module_id) {
861 for macro_call in macro_calls {
862 if let Ok(macro_module_id) = self.db.macro_call_module_id(*macro_call) {
863 let expose = expose
864 || matches!(
865 macro_module_id,
866 ModuleId::MacroCall { is_expose: true, .. }
867 );
868 stack.push((macro_module_id, expose));
869 }
870 }
871 }
872 }
873 }
874
875 pub fn determine_base_item_in_local_scope(
877 &mut self,
878 identifier: &ast::TerminalIdentifier<'db>,
879 ) -> Option<ResolvedConcreteItem<'db>> {
880 let db = self.db;
881 let ident = identifier.text(db);
882
883 if let Some(generic_param_id) = self.data.generic_param_by_name.get(&ident) {
885 let item = match generic_param_id.kind(self.db) {
886 GenericKind::Type => ResolvedConcreteItem::Type(
887 TypeLongId::GenericParameter(*generic_param_id).intern(self.db),
888 ),
889 GenericKind::Const => ResolvedConcreteItem::Constant(
890 ConstValue::Generic(*generic_param_id).intern(self.db),
891 ),
892 GenericKind::Impl => ResolvedConcreteItem::Impl(
893 ImplLongId::GenericParameter(*generic_param_id).intern(self.db),
894 ),
895 GenericKind::NegImpl => return None,
896 };
897 return Some(item);
898 }
899 None
902 }
903
904 pub fn prelude_submodule(&self) -> ModuleId<'db> {
905 self.prelude_submodule_ex(&MacroResolutionInfo::from_resolver(self))
906 }
907
908 fn prelude_submodule_ex(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
910 let active_settings = self.active_settings(info);
911 self.db.get_prelude_submodule(active_settings).unwrap_or_else(|| {
912 panic!(
913 "expected prelude submodule `{}` not found in `core::prelude`.",
914 active_settings.edition.prelude_submodule_name(self.db).long(self.db)
915 )
916 })
917 }
918
919 fn specialize_trait(
921 &mut self,
922 diagnostics: &mut SemanticDiagnostics<'db>,
923 stable_ptr: SyntaxStablePtrId<'db>,
924 trait_id: TraitId<'db>,
925 generic_args: &[ast::GenericArg<'db>],
926 ) -> Maybe<ConcreteTraitId<'db>> {
927 let generic_params = self
929 .db
930 .trait_generic_params(trait_id)
931 .map_err(|_| diagnostics.report(stable_ptr, UnknownTrait))?;
932 let generic_args = self.resolve_generic_args(
933 diagnostics,
934 GenericSubstitution::default(),
935 generic_params,
936 generic_args,
937 stable_ptr,
938 )?;
939
940 Ok(ConcreteTraitLongId { trait_id, generic_args }.intern(self.db))
941 }
942
943 fn specialize_impl(
945 &mut self,
946 diagnostics: &mut SemanticDiagnostics<'db>,
947 stable_ptr: SyntaxStablePtrId<'db>,
948 impl_def_id: ImplDefId<'db>,
949 generic_args: &[ast::GenericArg<'db>],
950 ) -> Maybe<ConcreteImplId<'db>> {
951 let generic_params = self
953 .db
954 .impl_def_generic_params(impl_def_id)
955 .map_err(|_| diagnostics.report(stable_ptr, UnknownImpl))?;
956 let generic_args = self.resolve_generic_args(
957 diagnostics,
958 GenericSubstitution::default(),
959 generic_params,
960 generic_args,
961 stable_ptr,
962 )?;
963
964 Ok(ConcreteImplLongId { impl_def_id, generic_args }.intern(self.db))
965 }
966
967 fn specialize_variant(
969 &mut self,
970 diagnostics: &mut SemanticDiagnostics<'db>,
971 stable_ptr: SyntaxStablePtrId<'db>,
972 variant_id: VariantId<'db>,
973 generic_args: &[ast::GenericArg<'db>],
974 ) -> Maybe<ConcreteVariant<'db>> {
975 let concrete_enum_id = ConcreteEnumLongId {
976 enum_id: variant_id.enum_id(self.db),
977 generic_args: self.resolve_generic_args(
978 diagnostics,
979 GenericSubstitution::default(),
980 self.db.enum_generic_params(variant_id.enum_id(self.db))?,
981 generic_args,
982 stable_ptr,
983 )?,
984 }
985 .intern(self.db);
986 self.db.concrete_enum_variant(
987 concrete_enum_id,
988 &self.db.variant_semantic(variant_id.enum_id(self.db), variant_id)?,
989 )
990 }
991
992 pub fn specialize_function(
994 &mut self,
995 diagnostics: &mut SemanticDiagnostics<'db>,
996 stable_ptr: SyntaxStablePtrId<'db>,
997 generic_function: GenericFunctionId<'db>,
998 generic_args: &[ast::GenericArg<'db>],
999 ) -> Maybe<FunctionId<'db>> {
1000 let generic_params = generic_function.generic_params(self.db)?;
1002 let generic_args = self.resolve_generic_args(
1003 diagnostics,
1004 GenericSubstitution::default(),
1005 generic_params,
1006 generic_args,
1007 stable_ptr,
1008 )?;
1009
1010 Ok(FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }
1011 .intern(self.db))
1012 }
1013
1014 pub fn specialize_type(
1016 &mut self,
1017 diagnostics: &mut SemanticDiagnostics<'db>,
1018 stable_ptr: SyntaxStablePtrId<'db>,
1019 generic_type: GenericTypeId<'db>,
1020 generic_args: &[ast::GenericArg<'db>],
1021 ) -> Maybe<TypeId<'db>> {
1022 let generic_params = self
1023 .db
1024 .generic_type_generic_params(generic_type)
1025 .map_err(|_| diagnostics.report(stable_ptr, UnknownType))?;
1026 let generic_args = self.resolve_generic_args(
1027 diagnostics,
1028 GenericSubstitution::default(),
1029 generic_params,
1030 generic_args,
1031 stable_ptr,
1032 )?;
1033
1034 Ok(TypeLongId::Concrete(ConcreteTypeId::new(self.db, generic_type, generic_args))
1035 .intern(self.db))
1036 }
1037
1038 pub fn impl_lookup_context(&self) -> ImplLookupContextId<'db> {
1040 self.impl_lookup_context_ex(&MacroResolutionInfo::from_resolver(self))
1041 }
1042
1043 fn impl_lookup_context_ex(&self, info: &MacroResolutionInfo<'db>) -> ImplLookupContextId<'db> {
1046 let mut lookup_context = ImplLookupContext::new(
1047 self.active_module_id(info),
1048 self.generic_params.clone(),
1049 self.db,
1050 );
1051
1052 if let TraitOrImplContext::Impl(impl_def_id) = &self.trait_or_impl_ctx {
1053 let Ok(generic_params) = self.db.impl_def_generic_params(*impl_def_id) else {
1054 return lookup_context.intern(self.db);
1055 };
1056 let generic_args = generic_params_to_args(generic_params, self.db);
1057 let impl_id: ConcreteImplId<'_> =
1058 ConcreteImplLongId { impl_def_id: *impl_def_id, generic_args }.intern(self.db);
1059 lookup_context.insert_impl(ImplLongId::Concrete(impl_id).intern(self.db), self.db);
1060 }
1061 lookup_context.intern(self.db)
1062 }
1063
1064 pub fn resolve_generic_args(
1068 &mut self,
1069 diagnostics: &mut SemanticDiagnostics<'db>,
1070 mut substitution: GenericSubstitution<'db>,
1071 generic_params: &[GenericParam<'db>],
1072 generic_args_syntax: &[ast::GenericArg<'db>],
1073 stable_ptr: SyntaxStablePtrId<'db>,
1074 ) -> Maybe<Vec<GenericArgumentId<'db>>> {
1075 let mut resolved_args = vec![];
1076 let arg_syntax_per_param = self.get_arg_syntax_per_param(
1077 diagnostics,
1078 &generic_params.iter().map(|generic_param| generic_param.id()).collect_vec(),
1079 generic_args_syntax,
1080 )?;
1081
1082 for generic_param in generic_params {
1083 let generic_param = substitution.substitute(self.db, generic_param.clone())?;
1084 let generic_arg = self.resolve_generic_arg(
1085 &generic_param,
1086 arg_syntax_per_param
1087 .get(&generic_param.id())
1088 .filter(|expr| !matches!(expr, ast::Expr::Underscore(_))),
1089 stable_ptr,
1090 diagnostics,
1091 )?;
1092 resolved_args.push(generic_arg);
1093 substitution.insert(generic_param.id(), generic_arg);
1094 }
1095
1096 Ok(resolved_args)
1097 }
1098
1099 pub fn get_arg_syntax_per_param(
1101 &self,
1102 diagnostics: &mut SemanticDiagnostics<'db>,
1103 generic_params: &[GenericParamId<'db>],
1104 generic_args_syntax: &[ast::GenericArg<'db>],
1105 ) -> Maybe<UnorderedHashMap<GenericParamId<'db>, ast::Expr<'db>>> {
1106 let db = self.db;
1107 let mut arg_syntax_per_param =
1108 UnorderedHashMap::<GenericParamId<'_>, ast::Expr<'_>>::default();
1109 let mut last_named_arg_index = None;
1110 let generic_param_by_name = generic_params
1111 .iter()
1112 .enumerate()
1113 .filter_map(|(i, param)| Some((param.name(self.db)?, (i, param))))
1114 .collect::<UnorderedHashMap<_, _>>();
1115 for (idx, generic_arg_syntax) in generic_args_syntax.iter().enumerate() {
1116 match generic_arg_syntax {
1117 ast::GenericArg::Named(arg_syntax) => {
1118 let name = arg_syntax.name(db).text(db);
1119 let Some((index, generic_param_id)) = generic_param_by_name.get(&name) else {
1120 return Err(diagnostics
1121 .report(arg_syntax.stable_ptr(db), UnknownGenericParam(name)));
1122 };
1123 if let Some(prev_index) = last_named_arg_index
1124 && prev_index > index
1125 {
1126 return Err(diagnostics
1127 .report(arg_syntax.stable_ptr(db), GenericArgOutOfOrder(name)));
1128 }
1129 last_named_arg_index = Some(index);
1130 if arg_syntax_per_param
1131 .insert(**generic_param_id, arg_syntax.value(db))
1132 .is_some()
1133 {
1134 return Err(diagnostics
1135 .report(arg_syntax.stable_ptr(db), GenericArgDuplicate(name)));
1136 }
1137 }
1138 ast::GenericArg::Unnamed(arg_syntax) => {
1139 if last_named_arg_index.is_some() {
1140 return Err(diagnostics
1141 .report(arg_syntax.stable_ptr(db), PositionalGenericAfterNamed));
1142 }
1143 let generic_param = generic_params.get(idx).ok_or_else(|| {
1144 diagnostics.report(
1145 arg_syntax.stable_ptr(db),
1146 TooManyGenericArguments {
1147 expected: generic_params.len(),
1148 actual: generic_args_syntax.len(),
1149 },
1150 )
1151 })?;
1152 assert_eq!(
1153 arg_syntax_per_param.insert(*generic_param, arg_syntax.value(db)),
1154 None,
1155 "Unexpected duplication in ordered params."
1156 );
1157 }
1158 }
1159 }
1160 Ok(arg_syntax_per_param)
1161 }
1162
1163 fn resolve_generic_arg(
1167 &mut self,
1168 generic_param: &GenericParam<'db>,
1169 generic_arg_syntax_opt: Option<&ast::Expr<'db>>,
1170 stable_ptr: SyntaxStablePtrId<'db>,
1171 diagnostics: &mut SemanticDiagnostics<'db>,
1172 ) -> Result<GenericArgumentId<'db>, cairo_lang_diagnostics::DiagnosticAdded> {
1173 let Some(generic_arg_syntax) = generic_arg_syntax_opt else {
1174 let lookup_context = self.impl_lookup_context();
1175 let inference = &mut self.data.inference_data.inference(self.db);
1176 return inference
1177 .infer_generic_arg(generic_param, lookup_context, Some(stable_ptr))
1178 .map_err(|err_set| {
1179 inference.report_on_pending_error(err_set, diagnostics, stable_ptr)
1180 });
1181 };
1182 let db = self.db;
1183 Ok(match generic_param {
1184 GenericParam::Type(_) => {
1185 GenericArgumentId::Type(resolve_type(db, diagnostics, self, generic_arg_syntax))
1186 }
1187 GenericParam::Const(const_param) => {
1188 let mut ctx = ComputationContext::new_global(db, diagnostics, self);
1192 let value = compute_expr_semantic(&mut ctx, generic_arg_syntax);
1193 GenericArgumentId::Constant(resolve_const_expr_and_evaluate(
1194 db,
1195 &mut ctx,
1196 &value,
1197 generic_arg_syntax.stable_ptr(db).untyped(),
1198 const_param.ty,
1199 false,
1200 ))
1201 }
1202
1203 GenericParam::Impl(param) => {
1204 let expr_path = try_extract_matches!(generic_arg_syntax, ast::Expr::Path)
1205 .ok_or_else(|| {
1206 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1207 })?;
1208 let resolved_impl = match self.resolve_concrete_path(
1209 diagnostics,
1210 expr_path,
1211 NotFoundItemType::Impl,
1212 )? {
1213 ResolvedConcreteItem::Impl(resolved_impl) => resolved_impl,
1214 ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
1215 ImplLongId::SelfImpl(concrete_trait_id).intern(self.db)
1216 }
1217 _ => {
1218 return Err(
1219 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1220 );
1221 }
1222 };
1223 let impl_def_concrete_trait = self.db.impl_concrete_trait(resolved_impl)?;
1224 let expected_concrete_trait = param.concrete_trait?;
1225 if let Err(err_set) = self
1226 .inference()
1227 .conform_traits(impl_def_concrete_trait, expected_concrete_trait)
1228 {
1229 let diag_added = diagnostics.report(
1230 generic_arg_syntax.stable_ptr(db),
1231 TraitMismatch {
1232 expected_trt: expected_concrete_trait,
1233 actual_trt: impl_def_concrete_trait,
1234 },
1235 );
1236 self.inference().consume_reported_error(err_set, diag_added);
1237 } else {
1238 for (trait_ty, ty1) in param.type_constraints.iter() {
1239 let ty0 = TypeLongId::ImplType(ImplTypeId::new(
1240 resolved_impl,
1241 *trait_ty,
1242 self.db,
1243 ))
1244 .intern(self.db);
1245 let _ = self.inference().conform_ty(ty0, *ty1).map_err(|err_set| {
1246 self.inference().report_on_pending_error(
1247 err_set,
1248 diagnostics,
1249 stable_ptr,
1250 )
1251 });
1252 }
1253 }
1254 GenericArgumentId::Impl(resolved_impl)
1255 }
1256 GenericParam::NegImpl(_) => {
1257 return Err(
1258 diagnostics.report(generic_arg_syntax.stable_ptr(db), ArgPassedToNegativeImpl)
1259 );
1260 }
1261 })
1262 }
1263
1264 pub fn ignore_visibility_checks(&self, module_id: ModuleId<'db>) -> bool {
1267 self.ignore_visibility_checks_ex(module_id, &MacroResolutionInfo::from_resolver(self))
1268 }
1269
1270 fn ignore_visibility_checks_ex(
1273 &self,
1274 module_id: ModuleId<'db>,
1275 info: &MacroResolutionInfo<'db>,
1276 ) -> bool {
1277 let module_crate = module_id.owning_crate(self.db);
1278 let module_edition =
1279 self.db.crate_config(module_crate).map(|c| c.settings.edition).unwrap_or_default();
1280 module_edition.ignore_visibility()
1281 || self.active_settings(info).edition.ignore_visibility()
1282 && module_crate == self.db.core_crate()
1283 }
1284
1285 pub fn validate_feature_constraints<T: HasFeatureKind<'db>>(
1290 &self,
1291 diagnostics: &mut SemanticDiagnostics<'db>,
1292 identifier: &ast::TerminalIdentifier<'db>,
1293 item_info: &T,
1294 ) {
1295 let db = self.db;
1296 match item_info.feature_kind() {
1297 FeatureKind::Unstable { feature, note }
1298 if !self.data.feature_config.allowed_features.contains(feature) =>
1299 {
1300 diagnostics.report(
1301 identifier.stable_ptr(db),
1302 UnstableFeature { feature_name: *feature, note: *note },
1303 );
1304 }
1305 FeatureKind::Deprecated { feature, note }
1306 if !self
1307 .data
1308 .feature_config
1309 .allowed_lints
1310 .contains(&SmolStrId::from(self.db, DEPRECATED_ATTR))
1311 && !self.data.feature_config.allowed_features.contains(feature) =>
1312 {
1313 diagnostics.report(
1314 identifier.stable_ptr(db),
1315 DeprecatedFeature { feature_name: *feature, note: *note },
1316 );
1317 }
1318 FeatureKind::Internal { feature, note }
1319 if !self.data.feature_config.allowed_features.contains(feature) =>
1320 {
1321 diagnostics.report(
1322 identifier.stable_ptr(db),
1323 InternalFeature { feature_name: *feature, note: *note },
1324 );
1325 }
1326 _ => {}
1327 }
1328 }
1329
1330 pub fn is_item_visible(
1332 &self,
1333 containing_module_id: ModuleId<'db>,
1334 item_info: &ModuleItemInfo<'db>,
1335 user_module: ModuleId<'db>,
1336 ) -> bool {
1337 self.is_item_visible_ex(
1338 containing_module_id,
1339 item_info,
1340 user_module,
1341 &MacroResolutionInfo::from_resolver(self),
1342 )
1343 }
1344
1345 fn is_item_visible_ex(
1347 &self,
1348 mut containing_module_id: ModuleId<'db>, item_info: &ModuleItemInfo<'db>,
1350 user_module: ModuleId<'db>,
1351 info: &MacroResolutionInfo<'db>,
1352 ) -> bool {
1353 let db = self.db;
1354 if containing_module_id == user_module {
1355 return true;
1356 }
1357 while let ModuleId::MacroCall { id, .. } = containing_module_id {
1358 containing_module_id = id.parent_module(self.db);
1359 }
1360 self.ignore_visibility_checks_ex(containing_module_id, info)
1361 || visibility::peek_visible_in(
1362 db,
1363 item_info.visibility,
1364 containing_module_id,
1365 user_module,
1366 )
1367 }
1368
1369 pub fn insert_used_use(&mut self, item_id: ModuleItemId<'db>) {
1371 if let ModuleItemId::Use(use_id) = item_id {
1372 self.data.used_uses.insert(use_id);
1373 }
1374 }
1375
1376 fn handle_same_impl_trait(
1382 &mut self,
1383 diagnostics: &mut SemanticDiagnostics<'db>,
1384 specialized_item: &mut ResolvedConcreteItem<'db>,
1385 generic_args_syntax_slice: &[ast::GenericArg<'db>],
1386 segment_stable_ptr: SyntaxStablePtrId<'db>,
1387 ) {
1388 match *specialized_item {
1389 ResolvedConcreteItem::Trait(current_segment_concrete_trait) => {
1390 match self.trait_or_impl_ctx {
1391 TraitOrImplContext::None => {}
1392 TraitOrImplContext::Trait(ctx_trait) => {
1393 if self
1394 .warn_trait_in_same_trait(
1395 diagnostics,
1396 current_segment_concrete_trait.trait_id(self.db),
1397 generic_args_syntax_slice,
1398 ctx_trait,
1399 segment_stable_ptr,
1400 )
1401 .is_err()
1402 {
1403 *specialized_item =
1404 ResolvedConcreteItem::SelfTrait(current_segment_concrete_trait);
1405 }
1406 }
1407 TraitOrImplContext::Impl(ctx_impl_def_id) => {
1408 self.warn_trait_in_its_impl(
1409 diagnostics,
1410 current_segment_concrete_trait,
1411 ctx_impl_def_id,
1412 segment_stable_ptr,
1413 )
1414 .ok();
1415 }
1416 };
1417 }
1418 ResolvedConcreteItem::Impl(current_segment_impl_id) => {
1419 if let TraitOrImplContext::Impl(ctx_impl) = self.trait_or_impl_ctx {
1420 let current_segment_concrete_impl_id = extract_matches!(
1423 current_segment_impl_id.long(self.db),
1424 ImplLongId::Concrete
1425 );
1426 self.warn_impl_in_same_impl(
1427 diagnostics,
1428 current_segment_concrete_impl_id.impl_def_id(self.db),
1429 generic_args_syntax_slice,
1430 ctx_impl,
1431 segment_stable_ptr,
1432 )
1433 .ok();
1434 }
1435 }
1436 _ => {}
1437 };
1438 }
1439
1440 fn warn_impl_in_same_impl(
1443 &mut self,
1444 diagnostics: &mut SemanticDiagnostics<'db>,
1445 current_segment_impl_def_id: ImplDefId<'db>,
1446 current_segment_generic_args: &[ast::GenericArg<'db>],
1447 ctx_impl: ImplDefId<'db>,
1448 segment_stable_ptr: SyntaxStablePtrId<'db>,
1449 ) -> Maybe<()> {
1450 if current_segment_impl_def_id != ctx_impl {
1451 return Ok(());
1452 }
1453
1454 let generic_params = self.db.impl_def_generic_params(ctx_impl)?;
1455 self.compare_segment_args_to_params(
1456 diagnostics,
1457 current_segment_generic_args,
1458 generic_params,
1459 segment_stable_ptr,
1460 ImplInImplMustBeExplicit,
1461 ImplItemForbiddenInTheImpl,
1462 )
1463 }
1464
1465 fn warn_trait_in_its_impl(
1468 &mut self,
1469 diagnostics: &mut SemanticDiagnostics<'db>,
1470 current_segment_concrete_trait_id: ConcreteTraitId<'db>,
1471 impl_ctx: ImplDefId<'db>,
1472 segment_stable_ptr: SyntaxStablePtrId<'db>,
1473 ) -> Maybe<()> {
1474 let ctx_impl_trait = self.db.impl_def_trait(impl_ctx)?;
1475 if current_segment_concrete_trait_id.trait_id(self.db) != ctx_impl_trait {
1476 return Ok(());
1477 }
1478
1479 let ctx_impl_concrete_trait = self.db.impl_def_concrete_trait(impl_ctx)?;
1480 if ctx_impl_concrete_trait.generic_args(self.db)
1481 == current_segment_concrete_trait_id.generic_args(self.db)
1482 {
1483 return Err(diagnostics.report(segment_stable_ptr, TraitItemForbiddenInItsImpl));
1484 }
1485 Ok(())
1486 }
1487
1488 fn warn_trait_in_same_trait(
1491 &mut self,
1492 diagnostics: &mut SemanticDiagnostics<'db>,
1493 current_segment_trait_id: TraitId<'db>,
1494 current_segment_generic_args: &[ast::GenericArg<'db>],
1495 ctx_trait: TraitId<'db>,
1496 segment_stable_ptr: SyntaxStablePtrId<'db>,
1497 ) -> Maybe<()> {
1498 if current_segment_trait_id != ctx_trait {
1499 return Ok(());
1500 }
1501
1502 let generic_params = self.db.trait_generic_params(ctx_trait)?;
1503 self.compare_segment_args_to_params(
1504 diagnostics,
1505 current_segment_generic_args,
1506 generic_params,
1507 segment_stable_ptr,
1508 TraitInTraitMustBeExplicit,
1509 TraitItemForbiddenInTheTrait,
1510 )
1511 }
1512
1513 fn compare_segment_args_to_params(
1520 &mut self,
1521 diagnostics: &mut SemanticDiagnostics<'db>,
1522 current_segment_generic_args: &[ast::GenericArg<'db>],
1523 generic_params: &[GenericParam<'db>],
1524 segment_stable_ptr: SyntaxStablePtrId<'db>,
1525 must_be_explicit_error: SemanticDiagnosticKind<'db>,
1526 item_forbidden_in_itself_explicit_error: SemanticDiagnosticKind<'db>,
1527 ) -> Maybe<()> {
1528 if current_segment_generic_args.len() < generic_params.len() {
1531 return Err(diagnostics.report(segment_stable_ptr, must_be_explicit_error));
1532 }
1533 let resolved_args = self.resolve_generic_args(
1534 diagnostics,
1535 GenericSubstitution::default(),
1536 generic_params,
1537 current_segment_generic_args,
1538 segment_stable_ptr,
1539 )?;
1540
1541 if generic_params
1542 .iter()
1543 .zip_eq(resolved_args.iter())
1544 .all(|(gparam, garg)| gparam.as_arg(self.db) == *garg)
1545 {
1546 return Err(
1547 diagnostics.report(segment_stable_ptr, item_forbidden_in_itself_explicit_error)
1548 );
1549 }
1550 Ok(())
1551 }
1552
1553 fn specialize_generic_statement_arg(
1555 &mut self,
1556 diagnostics: &mut SemanticDiagnostics<'db>,
1557 segment: &ast::PathSegment<'db>,
1558 identifier: &ast::TerminalIdentifier<'db>,
1559 inner_generic_item: ResolvedGenericItem<'db>,
1560 generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
1561 ) -> ResolvedConcreteItem<'db> {
1562 let segment_stable_ptr = segment.stable_ptr(self.db).untyped();
1563 let mut specialized_item = self
1564 .specialize_generic_module_item(
1565 diagnostics,
1566 identifier,
1567 inner_generic_item,
1568 generic_args_syntax.clone(),
1569 )
1570 .unwrap();
1571 self.handle_same_impl_trait(
1572 diagnostics,
1573 &mut specialized_item,
1574 &generic_args_syntax.unwrap_or_default(),
1575 segment_stable_ptr,
1576 );
1577 specialized_item
1578 }
1579}
1580
1581fn handle_macro_context_modifier<'db>(
1594 db: &'db dyn Database,
1595 diagnostics: &mut SemanticDiagnostics<'db>,
1596 segments: &mut Peekable<std::vec::IntoIter<ast::PathSegment<'db>>>,
1597) -> Maybe<MacroContextModifier> {
1598 if segments.len() == 1 {
1599 return Err(diagnostics.report_after(
1600 segments.next().unwrap().stable_ptr(db),
1601 EmptyPathAfterResolverModifier,
1602 ));
1603 }
1604 match segments.peek() {
1605 Some(ast::PathSegment::Simple(path_segment_simple)) => {
1606 let ident = path_segment_simple.ident(db);
1607 let ident_text = ident.text(db);
1608 match ident_text.long(db).as_str() {
1609 MACRO_DEF_SITE | MACRO_CALL_SITE => {
1610 segments.next();
1611 if ident_text.long(db) == MACRO_DEF_SITE {
1612 Ok(MacroContextModifier::DefSite)
1613 } else {
1614 Ok(MacroContextModifier::CallSite)
1615 }
1616 }
1617 _ => Err(diagnostics.report(
1618 ident.stable_ptr(db),
1619 UnknownResolverModifier { modifier: ident_text },
1620 )),
1621 }
1622 }
1623 _ => {
1624 Err(skip_diagnostic())
1626 }
1627 }
1628}
1629
1630fn resolve_self_segment<'db>(
1633 db: &'db dyn Database,
1634 diagnostics: &mut SemanticDiagnostics<'db>,
1635 identifier: &ast::TerminalIdentifier<'db>,
1636 trait_or_impl_ctx: &TraitOrImplContext<'db>,
1637) -> Option<Maybe<ResolvedConcreteItem<'db>>> {
1638 require(identifier.text(db).long(db) == SELF_TYPE_KW)?;
1639 Some(resolve_actual_self_segment(db, diagnostics, identifier, trait_or_impl_ctx))
1640}
1641
1642fn resolve_actual_self_segment<'db>(
1644 db: &'db dyn Database,
1645 diagnostics: &mut SemanticDiagnostics<'db>,
1646 identifier: &ast::TerminalIdentifier<'db>,
1647 trait_or_impl_ctx: &TraitOrImplContext<'db>,
1648) -> Maybe<ResolvedConcreteItem<'db>> {
1649 match trait_or_impl_ctx {
1650 TraitOrImplContext::None => {
1651 Err(diagnostics.report(identifier.stable_ptr(db), SelfNotSupportedInContext))
1652 }
1653 TraitOrImplContext::Trait(trait_id) => {
1654 let generic_parameters = db.trait_generic_params(*trait_id)?;
1655 let concrete_trait_id = ConcreteTraitLongId {
1656 trait_id: *trait_id,
1657 generic_args: generic_params_to_args(generic_parameters, db),
1658 }
1659 .intern(db);
1660 Ok(ResolvedConcreteItem::SelfTrait(concrete_trait_id))
1661 }
1662 TraitOrImplContext::Impl(impl_def_id) => {
1663 let generic_parameters = db.impl_def_generic_params(*impl_def_id)?;
1664 let impl_id = ImplLongId::Concrete(
1665 ConcreteImplLongId {
1666 impl_def_id: *impl_def_id,
1667 generic_args: generic_params_to_args(generic_parameters, db),
1668 }
1669 .intern(db),
1670 );
1671 Ok(ResolvedConcreteItem::Impl(impl_id.intern(db)))
1672 }
1673 }
1674}
1675
1676enum ResolvedBase<'db> {
1678 Module(ModuleId<'db>),
1680 Crate(CrateId<'db>),
1682 StatementEnvironment(ResolvedGenericItem<'db>),
1684 FoundThroughGlobalUse { item_info: ModuleItemInfo<'db>, containing_module: ModuleId<'db> },
1686 Ambiguous(Vec<ModuleItemId<'db>>),
1688 ItemNotVisible(ModuleItemId<'db>, Vec<ModuleId<'db>>),
1690}
1691
1692struct ResolutionCallbacks<'db, 'a, ResolvedItem, First, Next, Validate, Mark>
1694where
1695 First: FnOnce(&mut Resolution<'db, 'a>) -> Maybe<ResolvedItem>,
1696 Next: FnMut(
1697 &mut Resolution<'db, 'a>,
1698 &ResolvedItem,
1699 &ast::PathSegment<'db>,
1700 ) -> Maybe<ResolvedItem>,
1701 Validate: FnMut(&mut SemanticDiagnostics<'db>, &ast::PathSegment<'db>) -> Maybe<()>,
1702 Mark: FnMut(
1703 &mut ResolvedItems<'db>,
1704 &'db dyn Database,
1705 &syntax::node::ast::PathSegment<'db>,
1706 ResolvedItem,
1707 ),
1708{
1709 _phantom: PhantomData<(ResolvedItem, &'db (), &'a ())>,
1711 first: First,
1713 next: Next,
1715 validate: Validate,
1718 mark: Mark,
1720}
1721
1722struct Resolution<'db, 'a> {
1724 resolver: &'a mut Resolver<'db>,
1726 diagnostics: &'a mut SemanticDiagnostics<'db>,
1728 segments: Peekable<std::vec::IntoIter<ast::PathSegment<'db>>>,
1730 expected_item_type: NotFoundItemType,
1732 resolution_context: ResolutionContext<'db, 'a>,
1734 macro_info: MacroResolutionInfo<'db>,
1736}
1737impl<'db, 'a> Resolution<'db, 'a> {
1738 fn new(
1742 resolver: &'a mut Resolver<'db>,
1743 diagnostics: &'a mut SemanticDiagnostics<'db>,
1744 path: impl AsSegments<'db>,
1745 item_type: NotFoundItemType,
1746 resolution_context: ResolutionContext<'db, 'a>,
1747 ) -> Maybe<Self> {
1748 let db = resolver.db;
1749 let placeholder_marker = path.placeholder_marker(db);
1750
1751 let mut cur_offset =
1752 ExpansionOffset::new(path.offset(db).expect("Trying to resolve an empty path."));
1753 let mut segments = path.to_segments(db).into_iter().peekable();
1754 let mut cur_macro_call_data = resolver.macro_call_data.as_ref();
1755 let mut path_defining_module = resolver.data.module_id;
1756 while let Some(macro_call_data) = &cur_macro_call_data {
1759 let Some(new_offset) = cur_offset.mapped(¯o_call_data.expansion_mappings) else {
1760 break;
1761 };
1762 path_defining_module = macro_call_data.callsite_module_id;
1763 cur_macro_call_data = macro_call_data.parent_macro_call_data.as_ref();
1764 cur_offset = new_offset;
1765 }
1766 let macro_call_data = cur_macro_call_data.cloned();
1767
1768 let macro_context_modifier = if let Some(marker) = placeholder_marker {
1769 if macro_call_data.is_some() {
1770 handle_macro_context_modifier(db, diagnostics, &mut segments)?
1771 } else {
1772 return Err(diagnostics.report(marker.stable_ptr(db), DollarNotSupportedInContext));
1773 }
1774 } else {
1775 MacroContextModifier::None
1776 };
1777 let macro_info = MacroResolutionInfo {
1778 base: path_defining_module,
1779 data: macro_call_data,
1780 modifier: macro_context_modifier,
1781 };
1782 Ok(Resolution {
1783 resolver,
1784 diagnostics,
1785 segments,
1786 expected_item_type: item_type,
1787 resolution_context,
1788 macro_info,
1789 })
1790 }
1791
1792 fn full<ResolvedItem: Clone>(
1795 mut self,
1796 mut callbacks: ResolutionCallbacks<
1797 'db,
1798 'a,
1799 ResolvedItem,
1800 impl FnOnce(&mut Resolution<'db, 'a>) -> Maybe<ResolvedItem>,
1801 impl FnMut(
1802 &mut Resolution<'db, 'a>,
1803 &ResolvedItem,
1804 &ast::PathSegment<'db>,
1805 ) -> Maybe<ResolvedItem>,
1806 impl FnMut(&mut SemanticDiagnostics<'db>, &ast::PathSegment<'db>) -> Maybe<()>,
1807 impl FnMut(
1808 &mut ResolvedItems<'db>,
1809 &'db dyn Database,
1810 &syntax::node::ast::PathSegment<'db>,
1811 ResolvedItem,
1812 ),
1813 >,
1814 ) -> Maybe<ResolvedItem>
1815 where
1816 'db: 'a,
1817 {
1818 let mut item: ResolvedItem = (callbacks.first)(&mut self)?;
1820
1821 while let Some(segment) = self.segments.next() {
1823 (callbacks.validate)(self.diagnostics, &segment)?;
1824 item = (callbacks.next)(&mut self, &item, &segment)?;
1827 let db = self.resolver.db;
1828 (callbacks.mark)(&mut self.resolver.resolved_items, db, &segment, item.clone());
1829 }
1830 Ok(item)
1831 }
1832
1833 fn specialize_generic_inner_item(
1835 &mut self,
1836 module_id: ModuleId<'db>,
1837 segment: &ast::PathSegment<'db>,
1838 identifier: &TerminalIdentifier<'db>,
1839 inner_item_info: ModuleItemInfo<'db>,
1840 ) -> Maybe<ResolvedConcreteItem<'db>> {
1841 let db = self.resolver.db;
1842 let generic_args_syntax = segment.generic_args(db);
1843 let segment_stable_ptr = segment.stable_ptr(db).untyped();
1844 self.validate_module_item_usability(module_id, identifier, &inner_item_info);
1845 self.resolver.insert_used_use(inner_item_info.item_id);
1846 let inner_generic_item =
1847 ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)?;
1848 let mut specialized_item = self.resolver.specialize_generic_module_item(
1849 self.diagnostics,
1850 identifier,
1851 inner_generic_item.clone(),
1852 generic_args_syntax.clone(),
1853 )?;
1854 self.resolver
1855 .data
1856 .resolved_items
1857 .generic
1858 .insert(identifier.stable_ptr(db), inner_generic_item);
1859 self.resolver.handle_same_impl_trait(
1860 self.diagnostics,
1861 &mut specialized_item,
1862 &generic_args_syntax.unwrap_or_default(),
1863 segment_stable_ptr,
1864 );
1865 Ok(specialized_item)
1866 }
1867
1868 fn first_concrete(&mut self) -> Maybe<ResolvedConcreteItem<'db>> {
1870 if let Some(base_module) =
1871 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
1872 resolved_items.mark_concrete(db, segment, ResolvedConcreteItem::Module(module_id));
1873 })
1874 {
1875 return Ok(ResolvedConcreteItem::Module(base_module?));
1876 }
1877
1878 let db = self.resolver.db;
1879 Ok(match self.segments.peek().unwrap() {
1880 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
1881 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
1882 let identifier = generic_segment.ident(db);
1883 match self.determine_base(&identifier)? {
1885 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1886 ResolvedBase::Crate(_) => {
1887 return Err(self
1889 .diagnostics
1890 .report(generics_stable_ptr, UnexpectedGenericArgs));
1891 }
1892 ResolvedBase::StatementEnvironment(generic_item) => {
1893 let segment = self.segments.next().unwrap();
1894 let concrete_item = self.resolver.specialize_generic_statement_arg(
1895 self.diagnostics,
1896 &segment,
1897 &identifier,
1898 generic_item,
1899 segment.generic_args(db),
1900 );
1901 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1902 }
1903 ResolvedBase::FoundThroughGlobalUse {
1904 item_info: inner_module_item,
1905 containing_module: module_id,
1906 } => {
1907 let segment = self.segments.next().unwrap();
1908
1909 let concrete_item = self.specialize_generic_inner_item(
1910 module_id,
1911 &segment,
1912 &identifier,
1913 inner_module_item,
1914 )?;
1915 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1916 }
1917 ResolvedBase::Ambiguous(module_items) => {
1918 return Err(self
1919 .diagnostics
1920 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1921 }
1922 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1923 return Err(self.diagnostics.report(
1924 identifier.stable_ptr(db),
1925 ItemNotVisible(module_item_id, containing_modules),
1926 ));
1927 }
1928 }
1929 }
1930 syntax::node::ast::PathSegment::Simple(simple_segment) => {
1931 let identifier = simple_segment.ident(db);
1932
1933 if let Some(resolved_item) = resolve_self_segment(
1934 db,
1935 self.diagnostics,
1936 &identifier,
1937 &self.resolver.data.trait_or_impl_ctx,
1938 ) {
1939 return Ok(self.resolver.resolved_items.mark_concrete(
1941 db,
1942 &self.segments.next().unwrap(),
1943 resolved_item?,
1944 ));
1945 }
1946
1947 if let Some(local_item) =
1948 self.resolver.determine_base_item_in_local_scope(&identifier)
1949 {
1950 self.resolver.resolved_items.mark_concrete(
1951 db,
1952 &self.segments.next().unwrap(),
1953 local_item,
1954 )
1955 } else {
1956 match self.determine_base(&identifier)? {
1957 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1959 ResolvedBase::Crate(crate_id) => {
1960 self.resolver.resolved_items.mark_concrete(
1961 db,
1962 &self.segments.next().unwrap(),
1963 ResolvedConcreteItem::Module(ModuleId::CrateRoot(crate_id)),
1964 )
1965 }
1966 ResolvedBase::StatementEnvironment(generic_item) => {
1967 let segment = self.segments.next().unwrap();
1968
1969 let concrete_item = self.resolver.specialize_generic_statement_arg(
1970 self.diagnostics,
1971 &segment,
1972 &identifier,
1973 generic_item,
1974 segment.generic_args(db),
1975 );
1976 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1977 }
1978 ResolvedBase::FoundThroughGlobalUse {
1979 item_info: inner_module_item,
1980 containing_module: module_id,
1981 } => {
1982 let segment = self.segments.next().unwrap();
1983 let concrete_item = self.specialize_generic_inner_item(
1984 module_id,
1985 &segment,
1986 &identifier,
1987 inner_module_item,
1988 )?;
1989 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1990 }
1991 ResolvedBase::Ambiguous(module_items) => {
1992 return Err(self
1993 .diagnostics
1994 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1995 }
1996 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1997 return Err(self.diagnostics.report(
1998 identifier.stable_ptr(db),
1999 ItemNotVisible(module_item_id, containing_modules),
2000 ));
2001 }
2002 }
2003 }
2004 }
2005 syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
2007 })
2008 }
2009 fn first_generic(&mut self, allow_generic_args: bool) -> Maybe<ResolvedGenericItem<'db>> {
2012 if let Some(base_module) =
2013 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
2014 resolved_items.mark_generic(db, segment, ResolvedGenericItem::Module(module_id));
2015 })
2016 {
2017 return Ok(ResolvedGenericItem::Module(base_module?));
2018 }
2019 let db = self.resolver.db;
2020 Ok(match self.segments.peek().unwrap() {
2021 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
2022 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
2023 if !allow_generic_args {
2024 return Err(self
2025 .diagnostics
2026 .report(generics_stable_ptr, UnexpectedGenericArgs));
2027 }
2028 let identifier = generic_segment.ident(db);
2029 match self.determine_base(&identifier)? {
2030 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2031 ResolvedBase::Crate(_) => {
2032 return Err(self
2034 .diagnostics
2035 .report(generics_stable_ptr, UnexpectedGenericArgs));
2036 }
2037 ResolvedBase::StatementEnvironment(generic_item) => generic_item,
2038 ResolvedBase::FoundThroughGlobalUse {
2039 item_info: inner_module_item, ..
2040 } => {
2041 self.resolver.insert_used_use(inner_module_item.item_id);
2042 let generic_item =
2043 ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2044 self.resolver.resolved_items.mark_generic(
2045 db,
2046 &self.segments.next().unwrap(),
2047 generic_item,
2048 )
2049 }
2050 ResolvedBase::Ambiguous(module_items) => {
2051 return Err(self
2052 .diagnostics
2053 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2054 }
2055 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2056 return Err(self.diagnostics.report(
2057 identifier.stable_ptr(db),
2058 ItemNotVisible(module_item_id, containing_modules),
2059 ));
2060 }
2061 }
2062 }
2063 syntax::node::ast::PathSegment::Simple(simple_segment) => {
2064 let identifier = simple_segment.ident(db);
2065 match self.determine_base(&identifier)? {
2066 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2068 ResolvedBase::Crate(crate_id) => self.resolver.resolved_items.mark_generic(
2069 db,
2070 &self.segments.next().unwrap(),
2071 ResolvedGenericItem::Module(ModuleId::CrateRoot(crate_id)),
2072 ),
2073 ResolvedBase::StatementEnvironment(generic_item) => self
2074 .resolver
2075 .resolved_items
2076 .mark_generic(db, &self.segments.next().unwrap(), generic_item),
2077 ResolvedBase::FoundThroughGlobalUse {
2078 item_info: inner_module_item, ..
2079 } => {
2080 self.resolver.insert_used_use(inner_module_item.item_id);
2081 let generic_item =
2082 ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2083 self.resolver.resolved_items.mark_generic(
2084 db,
2085 &self.segments.next().unwrap(),
2086 generic_item,
2087 )
2088 }
2089 ResolvedBase::Ambiguous(module_items) => {
2090 return Err(self
2091 .diagnostics
2092 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2093 }
2094 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2095 return Err(self.diagnostics.report(
2096 identifier.stable_ptr(db),
2097 ItemNotVisible(module_item_id, containing_modules),
2098 ));
2099 }
2100 }
2101 }
2102 syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
2104 })
2105 }
2106
2107 fn try_handle_super_segments(
2111 &mut self,
2112 mut mark: impl FnMut(
2113 &mut ResolvedItems<'db>,
2114 &'db dyn Database,
2115 &syntax::node::ast::PathSegment<'db>,
2116 ModuleId<'db>,
2117 ),
2118 ) -> Option<Maybe<ModuleId<'db>>> {
2119 let db = self.resolver.db;
2120 let mut curr = None;
2121 for segment in self.segments.peeking_take_while(|segment| match segment {
2122 ast::PathSegment::WithGenericArgs(_) | ast::PathSegment::Missing(_) => false,
2123 ast::PathSegment::Simple(simple) => simple.identifier(db).long(db) == SUPER_KW,
2124 }) {
2125 let module_id = match curr {
2126 Some(module_id) => module_id,
2127 None => {
2128 if let Some(module_id) =
2129 self.resolver.try_get_active_module_id(&self.macro_info)
2130 {
2131 module_id
2132 } else {
2133 return Some(Err(self
2134 .diagnostics
2135 .report(segment.stable_ptr(db), SuperUsedInMacroCallTopLevel)));
2136 }
2137 }
2138 };
2139 match module_id {
2140 ModuleId::CrateRoot(_) => {
2141 return Some(Err(self
2142 .diagnostics
2143 .report(segment.stable_ptr(db), SuperUsedInRootModule)));
2144 }
2145 ModuleId::Submodule(submodule_id) => {
2146 let parent = submodule_id.parent_module(db);
2147 mark(&mut self.resolver.resolved_items, db, &segment, parent);
2148 curr = Some(parent);
2149 }
2150 ModuleId::MacroCall { .. } => {
2151 return Some(Err(self
2152 .diagnostics
2153 .report(segment.stable_ptr(db), SuperUsedInMacroCallTopLevel)));
2154 }
2155 }
2156 }
2157 curr.map(Ok)
2158 }
2159
2160 fn module_inner_item(
2162 &mut self,
2163 module_id: &ModuleId<'db>,
2164 ident: SmolStrId<'db>,
2165 identifier: &TerminalIdentifier<'db>,
2166 ) -> Maybe<ModuleItemInfo<'db>> {
2167 let db = self.resolver.db;
2168 self.resolver.resolve_item_in_module_ex(*module_id, ident).map_err(|err| {
2169 let err = match err {
2171 PathNotFound(_) if self.segments.len() == 0 => {
2172 PathNotFound(self.expected_item_type)
2173 }
2174 _ => err,
2175 };
2176 self.diagnostics.report(identifier.stable_ptr(db), err)
2177 })
2178 }
2179
2180 fn next_concrete(
2182 &mut self,
2183 containing_item: &ResolvedConcreteItem<'db>,
2184 segment: &ast::PathSegment<'db>,
2185 ) -> Maybe<ResolvedConcreteItem<'db>> {
2186 let db = self.resolver.db;
2187 let identifier = &segment.identifier_ast(db);
2188 let generic_args_syntax = segment.generic_args(db);
2189
2190 let ident = identifier.text(db);
2191
2192 if identifier.text(db).long(db) == SELF_TYPE_KW {
2193 return Err(self.diagnostics.report(identifier.stable_ptr(db), SelfMustBeFirst));
2194 }
2195
2196 match containing_item {
2197 ResolvedConcreteItem::Module(module_id) => {
2198 if ident.long(db) == SUPER_KW {
2201 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2202 }
2203 let inner_item_info = self.module_inner_item(module_id, ident, identifier)?;
2204
2205 self.specialize_generic_inner_item(*module_id, segment, identifier, inner_item_info)
2206 }
2207 ResolvedConcreteItem::Type(ty) => {
2208 if let TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_enum_id)) = ty.long(db) {
2209 let enum_id = concrete_enum_id.enum_id(db);
2210 let variants = db.enum_variants(enum_id).map_err(|_| {
2211 self.diagnostics.report(identifier.stable_ptr(db), UnknownEnum)
2212 })?;
2213 let variant_id = variants.get(&ident).ok_or_else(|| {
2214 self.diagnostics.report(
2215 identifier.stable_ptr(db),
2216 NoSuchVariant { enum_id, variant_name: ident },
2217 )
2218 })?;
2219 let variant = db.variant_semantic(enum_id, *variant_id)?;
2220 let concrete_variant = db.concrete_enum_variant(*concrete_enum_id, &variant)?;
2221 Ok(ResolvedConcreteItem::Variant(concrete_variant))
2222 } else {
2223 Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath))
2224 }
2225 }
2226 ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
2227 let impl_id = ImplLongId::SelfImpl(*concrete_trait_id).intern(db);
2228 let Some(trait_item_id) =
2229 db.trait_item_by_name(concrete_trait_id.trait_id(db), ident)?
2230 else {
2231 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2232 };
2233 if let Ok(Some(trait_item_info)) =
2234 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2235 {
2236 self.resolver.validate_feature_constraints(
2237 self.diagnostics,
2238 identifier,
2239 &trait_item_info,
2240 );
2241 }
2242 Ok(match trait_item_id {
2243 TraitItemId::Function(trait_function_id) => {
2244 ResolvedConcreteItem::Function(self.resolver.specialize_function(
2245 self.diagnostics,
2246 identifier.stable_ptr(db).untyped(),
2247 GenericFunctionId::Impl(ImplGenericFunctionId {
2248 impl_id,
2249 function: trait_function_id,
2250 }),
2251 &generic_args_syntax.unwrap_or_default(),
2252 )?)
2253 }
2254 TraitItemId::Type(trait_type_id) => ResolvedConcreteItem::Type(
2255 TypeLongId::ImplType(ImplTypeId::new(impl_id, trait_type_id, db))
2256 .intern(db),
2257 ),
2258 TraitItemId::Constant(trait_constant_id) => ResolvedConcreteItem::Constant(
2259 ConstValue::ImplConstant(ImplConstantId::new(
2260 impl_id,
2261 trait_constant_id,
2262 db,
2263 ))
2264 .intern(db),
2265 ),
2266 TraitItemId::Impl(trait_impl_id) => ResolvedConcreteItem::Impl(
2267 ImplLongId::ImplImpl(ImplImplId::new(impl_id, trait_impl_id, db))
2268 .intern(db),
2269 ),
2270 })
2271 }
2272 ResolvedConcreteItem::Trait(concrete_trait_id) => {
2273 let Some(trait_item_id) =
2274 db.trait_item_by_name(concrete_trait_id.trait_id(db), ident)?
2275 else {
2276 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2277 };
2278
2279 if let Ok(Some(trait_item_info)) =
2280 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2281 {
2282 self.resolver.validate_feature_constraints(
2283 self.diagnostics,
2284 identifier,
2285 &trait_item_info,
2286 );
2287 }
2288
2289 match trait_item_id {
2290 TraitItemId::Function(trait_function_id) => {
2291 let concrete_trait_function = ConcreteTraitGenericFunctionLongId::new(
2292 db,
2293 *concrete_trait_id,
2294 trait_function_id,
2295 )
2296 .intern(db);
2297 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2298 let impl_lookup_context =
2299 self.resolver.impl_lookup_context_ex(&self.macro_info);
2300 let generic_function = GenericFunctionId::Impl(
2301 self.resolver.inference().infer_trait_generic_function(
2302 concrete_trait_function,
2303 impl_lookup_context,
2304 Some(identifier_stable_ptr),
2305 ),
2306 );
2307
2308 Ok(ResolvedConcreteItem::Function(self.resolver.specialize_function(
2309 self.diagnostics,
2310 identifier_stable_ptr,
2311 generic_function,
2312 &generic_args_syntax.unwrap_or_default(),
2313 )?))
2314 }
2315 TraitItemId::Type(trait_type_id) => {
2316 let concrete_trait_type = ConcreteTraitTypeId::new_from_data(
2317 db,
2318 *concrete_trait_id,
2319 trait_type_id,
2320 );
2321
2322 let impl_lookup_context =
2323 self.resolver.impl_lookup_context_ex(&self.macro_info);
2324 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2325 let ty = self.resolver.inference().infer_trait_type(
2326 concrete_trait_type,
2327 impl_lookup_context,
2328 Some(identifier_stable_ptr),
2329 );
2330 Ok(ResolvedConcreteItem::Type(
2331 self.resolver.inference().rewrite(ty).no_err(),
2332 ))
2333 }
2334 TraitItemId::Constant(trait_constant_id) => {
2335 let concrete_trait_constant = ConcreteTraitConstantLongId::new(
2336 db,
2337 *concrete_trait_id,
2338 trait_constant_id,
2339 )
2340 .intern(db);
2341
2342 let impl_lookup_context =
2343 self.resolver.impl_lookup_context_ex(&self.macro_info);
2344 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2345 let imp_constant_id = self.resolver.inference().infer_trait_constant(
2346 concrete_trait_constant,
2347 impl_lookup_context,
2348 Some(identifier_stable_ptr),
2349 );
2350 self.resolver.inference().solve().ok();
2354
2355 Ok(ResolvedConcreteItem::Constant(
2356 ConstValue::ImplConstant(imp_constant_id).intern(db),
2357 ))
2358 }
2359 TraitItemId::Impl(trait_impl_id) => {
2360 let concrete_trait_impl = ConcreteTraitImplLongId::new_from_data(
2361 db,
2362 *concrete_trait_id,
2363 trait_impl_id,
2364 )
2365 .intern(db);
2366
2367 let impl_lookup_context =
2368 self.resolver.impl_lookup_context_ex(&self.macro_info);
2369 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2370 let impl_impl_id = self.resolver.inference().infer_trait_impl(
2371 concrete_trait_impl,
2372 impl_lookup_context,
2373 Some(identifier_stable_ptr),
2374 );
2375 self.resolver.inference().solve().ok();
2379
2380 Ok(ResolvedConcreteItem::Impl(
2381 ImplLongId::ImplImpl(impl_impl_id).intern(db),
2382 ))
2383 }
2384 }
2385 }
2386 ResolvedConcreteItem::Impl(impl_id) => {
2387 let concrete_trait_id = db.impl_concrete_trait(*impl_id)?;
2388 let trait_id = concrete_trait_id.trait_id(db);
2389 let Some(trait_item_id) = db.trait_item_by_name(trait_id, ident)? else {
2390 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2391 };
2392 if let Ok(Some(trait_item_info)) =
2393 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2394 {
2395 self.resolver.validate_feature_constraints(
2396 self.diagnostics,
2397 identifier,
2398 &trait_item_info,
2399 );
2400 }
2401 if let ImplLongId::Concrete(concrete_impl) = impl_id.long(db) {
2402 let impl_def_id: ImplDefId<'_> = concrete_impl.impl_def_id(db);
2403
2404 if let Ok(Some(impl_item_info)) = db.impl_item_info_by_name(impl_def_id, ident)
2405 {
2406 self.resolver.validate_feature_constraints(
2407 self.diagnostics,
2408 identifier,
2409 &impl_item_info,
2410 );
2411 }
2412 }
2413
2414 match trait_item_id {
2415 TraitItemId::Function(trait_function_id) => {
2416 let generic_function_id = GenericFunctionId::Impl(ImplGenericFunctionId {
2417 impl_id: *impl_id,
2418 function: trait_function_id,
2419 });
2420
2421 Ok(ResolvedConcreteItem::Function(self.resolver.specialize_function(
2422 self.diagnostics,
2423 identifier.stable_ptr(db).untyped(),
2424 generic_function_id,
2425 &generic_args_syntax.unwrap_or_default(),
2426 )?))
2427 }
2428 TraitItemId::Type(trait_type_id) => {
2429 let impl_type_id = ImplTypeId::new(*impl_id, trait_type_id, db);
2430 let ty = self
2431 .resolver
2432 .inference()
2433 .reduce_impl_ty(impl_type_id)
2434 .unwrap_or_else(|_| TypeLongId::ImplType(impl_type_id).intern(db));
2435 Ok(ResolvedConcreteItem::Type(ty))
2436 }
2437 TraitItemId::Constant(trait_constant_id) => {
2438 let impl_constant_id = ImplConstantId::new(*impl_id, trait_constant_id, db);
2439
2440 let constant = self
2441 .resolver
2442 .inference()
2443 .reduce_impl_constant(impl_constant_id)
2444 .unwrap_or_else(|_| {
2445 ConstValue::ImplConstant(impl_constant_id).intern(db)
2446 });
2447
2448 Ok(ResolvedConcreteItem::Constant(constant))
2449 }
2450 TraitItemId::Impl(trait_impl_id) => {
2451 let impl_impl_id = ImplImplId::new(*impl_id, trait_impl_id, db);
2452 let imp = self
2453 .resolver
2454 .inference()
2455 .reduce_impl_impl(impl_impl_id)
2456 .unwrap_or_else(|_| ImplLongId::ImplImpl(impl_impl_id).intern(db));
2457
2458 Ok(ResolvedConcreteItem::Impl(imp))
2459 }
2460 }
2461 }
2462 ResolvedConcreteItem::Function(function_id) if ident.long(db) == "Coupon" => {
2463 if !are_coupons_enabled(db, self.resolver.active_module_id(&self.macro_info)) {
2464 self.diagnostics.report(identifier.stable_ptr(db), CouponsDisabled);
2465 }
2466 if matches!(
2467 function_id.get_concrete(db).generic_function,
2468 GenericFunctionId::Extern(_)
2469 ) {
2470 return Err(self
2471 .diagnostics
2472 .report(identifier.stable_ptr(db), CouponForExternFunctionNotAllowed));
2473 }
2474 Ok(ResolvedConcreteItem::Type(TypeLongId::Coupon(*function_id).intern(db)))
2475 }
2476 _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2477 }
2478 }
2479
2480 fn next_generic(
2482 &mut self,
2483 containing_item: &ResolvedGenericItem<'db>,
2484 segment: &ast::PathSegment<'db>,
2485 ) -> Maybe<ResolvedGenericItem<'db>> {
2486 let db = self.resolver.db;
2487 let identifier = segment.identifier_ast(db);
2488 let ident = identifier.text(db);
2489 match containing_item {
2490 ResolvedGenericItem::Module(module_id) => {
2491 let inner_item_info = self.module_inner_item(module_id, ident, &identifier)?;
2492
2493 self.validate_module_item_usability(*module_id, &identifier, &inner_item_info);
2494 self.resolver.insert_used_use(inner_item_info.item_id);
2495 ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)
2496 }
2497 ResolvedGenericItem::GenericType(GenericTypeId::Enum(enum_id)) => {
2498 let variants = db.enum_variants(*enum_id)?;
2499 let variant_id = variants.get(&ident).ok_or_else(|| {
2500 self.diagnostics.report(
2501 identifier.stable_ptr(db),
2502 NoSuchVariant { enum_id: *enum_id, variant_name: ident },
2503 )
2504 })?;
2505 let variant = db.variant_semantic(*enum_id, *variant_id)?;
2506 Ok(ResolvedGenericItem::Variant(variant))
2507 }
2508 _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2509 }
2510 }
2511
2512 fn determine_base(
2515 &mut self,
2516 identifier: &ast::TerminalIdentifier<'db>,
2517 ) -> Maybe<ResolvedBase<'db>> {
2518 let db = self.resolver.db;
2519 let ident = identifier.text(db);
2520 if let ResolutionContext::Statement(ref mut env) = self.resolution_context
2521 && let Some(item) = get_statement_item_by_name(env, ident)
2522 {
2523 return Ok(ResolvedBase::StatementEnvironment(item));
2524 }
2525
2526 let Some(module_id) = self.resolver.try_get_active_module_id(&self.macro_info) else {
2527 let item_type = if self.segments.len() == 1 {
2528 self.expected_item_type
2529 } else {
2530 NotFoundItemType::Identifier
2531 };
2532 return Err(self
2533 .diagnostics
2534 .report(identifier.stable_ptr(db), PathNotFound(item_type)));
2535 };
2536 if let Some(info) = self.resolver.resolve_item_in_module_or_expanded_macro(module_id, ident)
2538 && !matches!(self.resolution_context, ResolutionContext::ModuleItem(id) if id == info.item_id)
2539 {
2540 return Ok(ResolvedBase::Module(module_id));
2541 }
2542
2543 if ident.long(db) == CRATE_KW {
2545 return Ok(ResolvedBase::Crate(self.resolver.active_owning_crate_id(&self.macro_info)));
2546 }
2547 if let Some(dep) = self
2550 .resolver
2551 .active_settings(&self.macro_info)
2552 .dependencies
2553 .get(ident.long(db).as_str())
2554 {
2555 let dep_crate_id =
2556 CrateLongId::Real { name: ident, discriminator: dep.discriminator.clone() }
2557 .intern(db);
2558 let configs = db.crate_configs();
2559 if !configs.contains_key(&dep_crate_id) {
2560 let get_long_id = |crate_id: CrateId<'db>| crate_id.long(db);
2561 panic!(
2562 "Invalid crate dependency: {:?}\nconfigured crates: {:#?}",
2563 get_long_id(dep_crate_id),
2564 configs.keys().cloned().map(get_long_id).collect_vec()
2565 );
2566 }
2567
2568 return Ok(ResolvedBase::Crate(dep_crate_id));
2569 }
2570 if ident.long(db) == CORELIB_CRATE_NAME {
2572 return Ok(ResolvedBase::Crate(CrateId::core(db)));
2573 }
2574 if ident.long(db) == STARKNET_CRATE_NAME {
2576 return Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)));
2578 }
2579 match self.resolver.resolve_path_using_use_star(module_id, ident) {
2581 UseStarResult::UniquePathFound(inner_module_item) => {
2582 return Ok(ResolvedBase::FoundThroughGlobalUse {
2583 item_info: inner_module_item,
2584 containing_module: module_id,
2585 });
2586 }
2587 UseStarResult::AmbiguousPath(module_items) => {
2588 return Ok(ResolvedBase::Ambiguous(module_items));
2589 }
2590 UseStarResult::PathNotFound => {}
2591 UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
2592 let prelude = self.resolver.prelude_submodule_ex(&self.macro_info);
2593 if let Ok(Some(_)) = db.module_item_by_name(prelude, ident) {
2594 return Ok(ResolvedBase::Module(prelude));
2595 }
2596 return Ok(ResolvedBase::ItemNotVisible(module_item_id, containing_modules));
2597 }
2598 }
2599 Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)))
2600 }
2601 fn validate_module_item_usability(
2604 &mut self,
2605 containing_module_id: ModuleId<'db>,
2606 identifier: &ast::TerminalIdentifier<'db>,
2607 item_info: &ModuleItemInfo<'db>,
2608 ) {
2609 if !self.resolver.is_item_visible_ex(
2610 containing_module_id,
2611 item_info,
2612 self.resolver.active_module_id(&self.macro_info),
2613 &self.macro_info,
2614 ) {
2615 self.diagnostics.report(
2616 identifier.stable_ptr(self.resolver.db),
2617 ItemNotVisible(item_info.item_id, vec![]),
2618 );
2619 }
2620
2621 self.resolver.validate_feature_constraints(self.diagnostics, identifier, item_info);
2622 }
2623}