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, MemberAccessKind, 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>, (EnrichedMember<'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
159#[derive(Debug, PartialEq, Eq, DebugWithDb, Clone, salsa::Update)]
161#[debug_db(dyn Database)]
162pub struct EnrichedMember<'db> {
163 pub kind: MemberAccessKind<'db>,
165 pub ty: TypeId<'db>,
167 pub visibility: Option<visibility::Visibility>,
170}
171
172pub struct EnrichedTypeMemberAccess<'db> {
175 pub member: EnrichedMember<'db>,
177 pub deref_functions: Vec<(FunctionId<'db>, Mutability)>,
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq, DebugWithDb)]
182#[debug_db(dyn Database)]
183enum MacroContextModifier {
184 DefSite,
186 CallSite,
188 None,
190}
191
192#[derive(Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
193#[debug_db(dyn Database)]
194pub struct ResolverData<'db> {
195 pub module_id: ModuleId<'db>,
197 generic_param_by_name: OrderedHashMap<SmolStrId<'db>, GenericParamId<'db>>,
199 pub generic_params: Vec<GenericParamId<'db>>,
201 pub type_enriched_members: OrderedHashMap<(TypeId<'db>, bool), EnrichedMembers<'db>>,
203 pub resolved_items: ResolvedItems<'db>,
205 pub inference_data: InferenceData<'db>,
207 pub trait_or_impl_ctx: TraitOrImplContext<'db>,
209 pub feature_config: FeatureConfig<'db>,
211 pub used_uses: OrderedHashSet<UseId<'db>>,
213 pub files: Vec<FileId<'db>>,
215}
216impl<'db> ResolverData<'db> {
217 pub fn new(module_id: ModuleId<'db>, inference_id: InferenceId<'db>) -> Self {
218 Self {
219 module_id,
220 generic_param_by_name: Default::default(),
221 generic_params: Default::default(),
222 type_enriched_members: Default::default(),
223 resolved_items: Default::default(),
224 inference_data: InferenceData::new(inference_id),
225 trait_or_impl_ctx: TraitOrImplContext::None,
226 feature_config: Default::default(),
227 used_uses: Default::default(),
228 files: vec![],
229 }
230 }
231 pub fn clone_with_inference_id(
232 &self,
233 db: &'db dyn Database,
234 inference_id: InferenceId<'db>,
235 ) -> Self {
236 Self {
237 module_id: self.module_id,
238 generic_param_by_name: self.generic_param_by_name.clone(),
239 generic_params: self.generic_params.clone(),
240 type_enriched_members: self.type_enriched_members.clone(),
241 resolved_items: self.resolved_items.clone(),
242 inference_data: self.inference_data.clone_with_inference_id(db, inference_id),
243 trait_or_impl_ctx: self.trait_or_impl_ctx,
244 feature_config: self.feature_config.clone(),
245 used_uses: self.used_uses.clone(),
246 files: self.files.clone(),
247 }
248 }
249}
250
251#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
253pub struct ResolverMacroData<'db> {
254 pub defsite_module_id: ModuleId<'db>,
257 pub callsite_module_id: ModuleId<'db>,
262 pub expansion_mappings: Arc<[CodeMapping]>,
265 pub parent_macro_call_data: Option<Arc<ResolverMacroData<'db>>>,
268}
269
270struct MacroResolutionInfo<'db> {
272 base: ModuleId<'db>,
274 data: Option<Arc<ResolverMacroData<'db>>>,
276 modifier: MacroContextModifier,
278}
279impl<'db> MacroResolutionInfo<'db> {
280 fn from_resolver(resolver: &Resolver<'db>) -> Self {
281 Self {
282 base: resolver.data.module_id,
283 data: resolver.macro_call_data.clone(),
284 modifier: MacroContextModifier::None,
285 }
286 }
287}
288
289pub struct Resolver<'db> {
291 db: &'db dyn Database,
292 pub data: ResolverData<'db>,
293 pub macro_call_data: Option<Arc<ResolverMacroData<'db>>>,
296 pub default_module_allowed: bool,
299 pub owning_crate_id: CrateId<'db>,
300 pub settings: CrateSettings,
301}
302impl<'db> Deref for Resolver<'db> {
303 type Target = ResolverData<'db>;
304
305 fn deref(&self) -> &Self::Target {
306 &self.data
307 }
308}
309impl DerefMut for Resolver<'_> {
310 fn deref_mut(&mut self) -> &mut Self::Target {
311 &mut self.data
312 }
313}
314impl<'db> Resolver<'db> {
315 pub fn set_feature_config(
318 &mut self,
319 element_id: &impl LanguageElementId<'db>,
320 syntax: &impl QueryAttrs<'db>,
321 diagnostics: &mut SemanticDiagnostics<'db>,
322 ) {
323 self.feature_config =
324 feature_config_from_item_and_parent_modules(self.db, element_id, syntax, diagnostics);
325 }
326
327 pub fn extend_feature_config_from_item(
331 &mut self,
332 db: &'db dyn Database,
333 crate_id: CrateId<'db>,
334 diagnostics: &mut SemanticDiagnostics<'db>,
335 item: &impl QueryAttrs<'db>,
336 ) -> FeatureConfigRestore<'db> {
337 self.data.feature_config.override_with(feature_config_from_ast_item(
338 db,
339 crate_id,
340 item,
341 diagnostics,
342 ))
343 }
344
345 pub fn restore_feature_config(&mut self, restore: FeatureConfigRestore<'db>) {
348 self.data.feature_config.restore(restore);
349 }
350}
351
352pub enum ResolutionContext<'a, 'mt> {
353 Default,
355 ModuleItem(ModuleItemId<'a>),
357 Statement(&'mt mut Environment<'a>),
359}
360
361enum UseStarResult<'db> {
363 UniquePathFound(ModuleItemInfo<'db>),
365 AmbiguousPath(Vec<ModuleItemId<'db>>),
367 PathNotFound,
369 ItemNotVisible(Option<ModuleItemId<'db>>, Vec<ModuleId<'db>>),
371}
372
373pub trait AsSegments<'db> {
375 fn to_segments(self, db: &'db dyn Database) -> Vec<ast::PathSegment<'db>>;
376 fn placeholder_marker(&self, db: &'db dyn Database) -> Option<ast::TerminalDollar<'db>>;
379 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset>;
381}
382impl<'db> AsSegments<'db> for &ast::ExprPath<'db> {
383 fn to_segments(self, db: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
384 self.segments(db).elements_vec(db)
385 }
386 fn placeholder_marker(&self, db: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
387 match self.dollar(db) {
388 ast::OptionTerminalDollar::Empty(_) => None,
389 ast::OptionTerminalDollar::TerminalDollar(dollar) => Some(dollar),
390 }
391 }
392
393 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
394 Some(self.as_syntax_node().offset(db))
395 }
396}
397impl<'db> AsSegments<'db> for Vec<ast::PathSegment<'db>> {
398 fn to_segments(self, _: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
399 self
400 }
401 fn placeholder_marker(&self, _: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
402 None
405 }
406 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
407 self.first().map(|segment| segment.as_syntax_node().offset(db))
408 }
409}
410impl<'db> AsSegments<'db> for UseAsPathSegments<'db> {
411 fn to_segments(self, _: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
412 self.segments
413 }
414
415 fn placeholder_marker(&self, _: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
416 self.is_placeholder.clone()
417 }
418
419 fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
420 if let Some(ref dollar) = self.is_placeholder {
421 Some(dollar.as_syntax_node().offset(db))
422 } else {
423 self.segments.first().map(|segment| segment.as_syntax_node().offset(db))
424 }
425 }
426}
427
428impl<'db> Resolver<'db> {
429 pub fn new(
430 db: &'db dyn Database,
431 module_id: ModuleId<'db>,
432 inference_id: InferenceId<'db>,
433 ) -> Self {
434 Self::with_data(db, ResolverData::new(module_id, inference_id))
435 }
436
437 pub fn with_data(db: &'db dyn Database, data: ResolverData<'db>) -> Self {
438 let owning_crate_id = data.module_id.owning_crate(db);
439 let macro_call_data = match data.module_id {
440 ModuleId::CrateRoot(_) | ModuleId::Submodule(_) => None,
441 ModuleId::MacroCall { id, .. } => match db.priv_macro_call_data(id) {
442 Ok(data) => Some(
443 ResolverMacroData {
444 defsite_module_id: data.defsite_module_id,
445 callsite_module_id: data.callsite_module_id,
446 expansion_mappings: data.expansion_mappings.clone(),
447 parent_macro_call_data: data.parent_macro_call_data,
448 }
449 .into(),
450 ),
451 Err(_) => None,
452 },
453 };
454 Self {
455 owning_crate_id,
456 settings: db
457 .crate_config(owning_crate_id)
458 .map(|c| c.settings.clone())
459 .unwrap_or_default(),
460 db,
461 data,
462 default_module_allowed: macro_call_data.is_some(),
463 macro_call_data,
464 }
465 }
466
467 pub fn inference(&mut self) -> Inference<'db, '_> {
468 self.data.inference_data.inference(self.db)
469 }
470
471 pub fn add_generic_param(&mut self, generic_param_id: GenericParamId<'db>) {
475 self.generic_params.push(generic_param_id);
476 if let Some(name) = generic_param_id.name(self.db) {
477 self.generic_param_by_name.insert(name, generic_param_id);
478 }
479 }
480
481 pub fn set_default_module_allowed(&mut self, default_module_allowed: bool) {
482 self.default_module_allowed = default_module_allowed;
483 }
484
485 fn active_module_id(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
488 if let Some(data) = &info.data {
489 match info.modifier {
490 MacroContextModifier::DefSite => data.defsite_module_id,
491 MacroContextModifier::CallSite => data.callsite_module_id,
492 MacroContextModifier::None => info.base,
493 }
494 } else {
495 assert_eq!(info.modifier, MacroContextModifier::None);
496 info.base
497 }
498 }
499
500 fn try_get_active_module_id(&self, info: &MacroResolutionInfo<'db>) -> Option<ModuleId<'db>> {
503 if let Some(data) = &info.data {
504 match info.modifier {
505 MacroContextModifier::DefSite => Some(data.defsite_module_id),
506 MacroContextModifier::CallSite => Some(data.callsite_module_id),
507 MacroContextModifier::None => (data.callsite_module_id != info.base
508 || self.default_module_allowed)
509 .then_some(info.base),
510 }
511 } else {
512 Some(info.base)
513 }
514 }
515
516 fn active_owning_crate_id(&self, info: &MacroResolutionInfo<'db>) -> CrateId<'db> {
519 self.active_module_id(info).owning_crate(self.db)
520 }
521
522 fn active_settings(&self, info: &MacroResolutionInfo<'db>) -> &CrateSettings {
525 self.db
526 .crate_config(self.active_owning_crate_id(info))
527 .map(|c| &c.settings)
528 .unwrap_or_else(|| default_crate_settings(self.db))
529 }
530
531 pub fn resolve_concrete_path(
535 &mut self,
536 diagnostics: &mut SemanticDiagnostics<'db>,
537 path: impl AsSegments<'db>,
538 item_type: NotFoundItemType,
539 ) -> Maybe<ResolvedConcreteItem<'db>> {
540 self.resolve_concrete_path_ex(diagnostics, path, item_type, ResolutionContext::Default)
541 }
542
543 pub fn resolve_concrete_path_ex(
546 &mut self,
547 diagnostics: &mut SemanticDiagnostics<'db>,
548 path: impl AsSegments<'db>,
549 item_type: NotFoundItemType,
550 ctx: ResolutionContext<'db, '_>,
551 ) -> Maybe<ResolvedConcreteItem<'db>> {
552 Resolution::new(self, diagnostics, path, item_type, ctx)?.full::<ResolvedConcreteItem<'db>>(
553 ResolutionCallbacks {
554 _phantom: PhantomData,
555 first: |resolution| resolution.first_concrete(),
556 next: |resolution, item, segment| resolution.next_concrete(item, segment),
557 validate: |_, _| Ok(()),
558 mark: |resolved_items: &mut ResolvedItems<'db>, db, segment, item| {
559 resolved_items.mark_concrete(db, segment, item);
560 },
561 },
562 )
563 }
564
565 pub fn resolve_generic_path(
568 &mut self,
569 diagnostics: &mut SemanticDiagnostics<'db>,
570 path: impl AsSegments<'db>,
571 item_type: NotFoundItemType,
572 ctx: ResolutionContext<'db, '_>,
573 ) -> Maybe<ResolvedGenericItem<'db>> {
574 self.resolve_generic_path_inner(diagnostics, path, item_type, false, ctx)
575 }
576
577 pub fn resolve_plugin_macro(
580 &mut self,
581 path: &ast::ExprPath<'db>,
582 ctx: ResolutionContext<'db, '_>,
583 ) -> Option<InlineMacroExprPluginId<'db>> {
584 let mut diagnostics = SemanticDiagnostics::new(self.module_id);
585 let resolution =
586 Resolution::new(self, &mut diagnostics, path, NotFoundItemType::Macro, ctx).ok()?;
587 let macro_name = resolution.segments.exactly_one().ok()?;
588 let macro_info = resolution.macro_info;
589 let crate_id = self.active_owning_crate_id(¯o_info);
590 let db = self.db;
591 db.crate_inline_macro_plugins(crate_id)
592 .get(macro_name.identifier(db).long(db).as_str())
593 .cloned()
594 }
595
596 pub fn resolve_use_path(
600 &mut self,
601 diagnostics: &mut SemanticDiagnostics<'db>,
602 use_path: ast::UsePath<'db>,
603 ctx: ResolutionContext<'db, '_>,
604 ) -> Maybe<ResolvedGenericItem<'db>> {
605 let mut segments = get_use_path_segments(self.db, use_path.clone())?;
606 if let Some(last) = segments.segments.last()
608 && last.identifier(self.db).long(self.db) == SELF_PARAM_KW
609 {
610 segments.segments.pop();
611 if segments.segments.is_empty() {
612 return Err(diagnostics.report(use_path.stable_ptr(self.db), UseSelfEmptyPath));
613 }
614 if use_path.as_syntax_node().parent_kind(self.db).unwrap() != SyntaxKind::UsePathList {
616 diagnostics.report(use_path.stable_ptr(self.db), UseSelfNonMulti);
617 }
618 }
619 self.resolve_generic_path(diagnostics, segments, NotFoundItemType::Identifier, ctx)
620 }
621
622 pub fn resolve_generic_path_with_args(
625 &mut self,
626 diagnostics: &mut SemanticDiagnostics<'db>,
627 path: impl AsSegments<'db>,
628 item_type: NotFoundItemType,
629 ctx: ResolutionContext<'db, '_>,
630 ) -> Maybe<ResolvedGenericItem<'db>> {
631 self.resolve_generic_path_inner(diagnostics, path, item_type, true, ctx)
632 }
633
634 fn resolve_generic_path_inner(
639 &mut self,
640 diagnostics: &mut SemanticDiagnostics<'db>,
641 path: impl AsSegments<'db>,
642 item_type: NotFoundItemType,
643 allow_generic_args: bool,
644 ctx: ResolutionContext<'db, '_>,
645 ) -> Maybe<ResolvedGenericItem<'db>> {
646 let validate = |diagnostics: &mut SemanticDiagnostics<'db>,
647 segment: &ast::PathSegment<'db>| {
648 match segment {
649 ast::PathSegment::WithGenericArgs(generic_args) if !allow_generic_args => {
650 Err(diagnostics.report(generic_args.stable_ptr(self.db), UnexpectedGenericArgs))
651 }
652 _ => Ok(()),
653 }
654 };
655 Resolution::new(self, diagnostics, path, item_type, ctx)?.full::<ResolvedGenericItem<'_>>(
656 ResolutionCallbacks {
657 _phantom: PhantomData,
658 first: |resolution| resolution.first_generic(allow_generic_args),
659 next: |resolution, item, segment| resolution.next_generic(item, segment),
660 validate,
661 mark: |resolved_items, db, segment, item| {
662 resolved_items.mark_generic(db, segment, item);
663 },
664 },
665 )
666 }
667
668 fn specialize_generic_module_item(
670 &mut self,
671 diagnostics: &mut SemanticDiagnostics<'db>,
672 identifier: &syntax::node::ast::TerminalIdentifier<'db>,
673 generic_item: ResolvedGenericItem<'db>,
674 generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
675 ) -> Maybe<ResolvedConcreteItem<'db>> {
676 let db: &'db dyn Database = self.db;
677 Ok(match generic_item {
678 ResolvedGenericItem::GenericConstant(id) => {
679 ResolvedConcreteItem::Constant(db.constant_const_value(id)?)
680 }
681 ResolvedGenericItem::Module(module_id) => {
682 if generic_args_syntax.is_some() {
683 return Err(
684 diagnostics.report(identifier.stable_ptr(db), UnexpectedGenericArgs)
685 );
686 }
687 ResolvedConcreteItem::Module(module_id)
688 }
689 ResolvedGenericItem::GenericFunction(generic_function) => {
690 ResolvedConcreteItem::Function(self.specialize_function(
691 diagnostics,
692 identifier.stable_ptr(db).untyped(),
693 generic_function,
694 &generic_args_syntax.unwrap_or_default(),
695 )?)
696 }
697 ResolvedGenericItem::GenericType(generic_type) => {
698 ResolvedConcreteItem::Type(self.specialize_type(
699 diagnostics,
700 identifier.stable_ptr(db).untyped(),
701 generic_type,
702 &generic_args_syntax.unwrap_or_default(),
703 )?)
704 }
705 ResolvedGenericItem::GenericTypeAlias(module_type_alias_id) => {
706 let ty = self.db.module_type_alias_resolved_type(module_type_alias_id)?;
707 let generic_params =
708 self.db.module_type_alias_generic_params(module_type_alias_id)?;
709 let generic_args = self.resolve_generic_args(
710 diagnostics,
711 GenericSubstitution::default(),
712 &generic_params,
713 &generic_args_syntax.unwrap_or_default(),
714 identifier.stable_ptr(db).untyped(),
715 )?;
716 ResolvedConcreteItem::Type(
717 GenericSubstitution::new(&generic_params, &generic_args).substitute(db, ty)?,
718 )
719 }
720 ResolvedGenericItem::GenericImplAlias(impl_alias_id) => {
721 let impl_id = db.impl_alias_resolved_impl(impl_alias_id)?;
722 let generic_params = db.impl_alias_generic_params(impl_alias_id)?;
723 let generic_args = self.resolve_generic_args(
724 diagnostics,
725 GenericSubstitution::default(),
726 &generic_params,
727 &generic_args_syntax.unwrap_or_default(),
728 identifier.stable_ptr(db).untyped(),
729 )?;
730 ResolvedConcreteItem::Impl(
731 GenericSubstitution::new(&generic_params, &generic_args)
732 .substitute(db, impl_id)?,
733 )
734 }
735 ResolvedGenericItem::Trait(trait_id) => {
736 ResolvedConcreteItem::Trait(self.specialize_trait(
737 diagnostics,
738 identifier.stable_ptr(db).untyped(),
739 trait_id,
740 &generic_args_syntax.unwrap_or_default(),
741 )?)
742 }
743 ResolvedGenericItem::Impl(impl_def_id) => ResolvedConcreteItem::Impl(
744 ImplLongId::Concrete(self.specialize_impl(
745 diagnostics,
746 identifier.stable_ptr(db).untyped(),
747 impl_def_id,
748 &generic_args_syntax.unwrap_or_default(),
749 )?)
750 .intern(self.db),
751 ),
752 ResolvedGenericItem::Macro(macro_declaration_id) => {
753 ResolvedConcreteItem::Macro(macro_declaration_id)
754 }
755 ResolvedGenericItem::Variant(var) => {
756 ResolvedConcreteItem::Variant(self.specialize_variant(
757 diagnostics,
758 identifier.stable_ptr(db).untyped(),
759 var.id,
760 &generic_args_syntax.unwrap_or_default(),
761 )?)
762 }
763 ResolvedGenericItem::Variable(_) => panic!("Variable is not a module item."),
764 ResolvedGenericItem::TraitItem(id) => {
765 panic!("`{}` is not a module item.", id.full_path(db))
766 }
767 })
768 }
769
770 fn resolve_path_using_use_star(
772 &mut self,
773 module_id: ModuleId<'db>,
774 ident: SmolStrId<'db>,
775 ) -> UseStarResult<'db> {
776 let mut item_info = None;
777 let mut module_items_found: OrderedHashSet<ModuleItemId<'_>> = OrderedHashSet::default();
778 let mut non_pub_module_items_found: OrderedHashSet<ModuleItemId<'_>> =
779 OrderedHashSet::default();
780 let mut non_pub_containing_modules = vec![];
781 for (item_module_id, info) in self.db.module_imported_modules((), module_id).iter() {
782 if *item_module_id == module_id {
784 continue;
785 }
786 if let Some(inner_item_info) =
787 self.resolve_item_in_module_or_expanded_macro(*item_module_id, ident)
788 {
789 if info.user_modules.iter().any(|user_module_id| {
790 self.is_item_visible(*item_module_id, &inner_item_info, *user_module_id)
791 }) {
792 item_info = Some(inner_item_info.clone());
793 module_items_found.insert(inner_item_info.item_id);
794 } else {
795 non_pub_containing_modules.push(*item_module_id);
796 non_pub_module_items_found.insert(inner_item_info.item_id);
797 }
798 }
799 }
800 if module_items_found.len() > 1 {
801 return UseStarResult::AmbiguousPath(module_items_found.into_iter().collect());
802 }
803 match item_info {
804 Some(item_info) => UseStarResult::UniquePathFound(item_info),
805 None => match non_pub_module_items_found.into_iter().exactly_one() {
806 Ok(item) => UseStarResult::ItemNotVisible(Some(item), non_pub_containing_modules),
807 Err(err) if err.len() == 0 => UseStarResult::PathNotFound,
808 Err(_) => UseStarResult::ItemNotVisible(None, non_pub_containing_modules),
809 },
810 }
811 }
812
813 pub fn resolve_item_in_module(
818 &mut self,
819 module_id: ModuleId<'db>,
820 ident: SmolStrId<'db>,
821 ) -> Option<ModuleItemInfo<'db>> {
822 self.resolve_item_in_module_ex(module_id, ident).ok()
823 }
824
825 fn resolve_item_in_module_ex(
830 &mut self,
831 module_id: ModuleId<'db>,
832 ident: SmolStrId<'db>,
833 ) -> Result<ModuleItemInfo<'db>, SemanticDiagnosticKind<'db>> {
834 if let Some(info) = self.resolve_item_in_module_or_expanded_macro(module_id, ident) {
835 return Ok(info);
836 }
837 match self.resolve_path_using_use_star(module_id, ident) {
838 UseStarResult::UniquePathFound(info) => Ok(info),
839 UseStarResult::AmbiguousPath(items) => Err(AmbiguousPath(items)),
840 UseStarResult::PathNotFound => Err(PathNotFound(NotFoundItemType::Identifier)),
841 UseStarResult::ItemNotVisible(item, modules) => Err(ItemNotVisible(item, modules)),
842 }
843 }
844
845 fn resolve_item_in_module_or_expanded_macro(
847 &mut self,
848 module_id: ModuleId<'db>,
849 ident: SmolStrId<'db>,
850 ) -> Option<ModuleItemInfo<'db>> {
851 if let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
852 self.insert_used_use(info.item_id);
853 return Some(info);
854 }
855 let mut stack = vec![(module_id, false)];
856 loop {
857 let (module_id, expose) = stack.pop()?;
858 if expose && let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
859 self.insert_used_use(info.item_id);
860 return Some(info);
861 }
862 if let Ok(macro_calls) = self.db.module_macro_calls_ids(module_id) {
863 for macro_call in macro_calls {
864 if let Ok(macro_module_id) = self.db.macro_call_module_id(*macro_call) {
865 let expose = expose
866 || matches!(
867 macro_module_id,
868 ModuleId::MacroCall { is_expose: true, .. }
869 );
870 stack.push((macro_module_id, expose));
871 }
872 }
873 }
874 }
875 }
876
877 pub fn determine_base_item_in_local_scope(
879 &mut self,
880 identifier: &ast::TerminalIdentifier<'db>,
881 ) -> Option<ResolvedConcreteItem<'db>> {
882 let db = self.db;
883 let ident = identifier.text(db);
884
885 if let Some(generic_param_id) = self.data.generic_param_by_name.get(&ident) {
887 let item = match generic_param_id.kind(self.db) {
888 GenericKind::Type => ResolvedConcreteItem::Type(
889 TypeLongId::GenericParameter(*generic_param_id).intern(self.db),
890 ),
891 GenericKind::Const => ResolvedConcreteItem::Constant(
892 ConstValue::Generic(*generic_param_id).intern(self.db),
893 ),
894 GenericKind::Impl => ResolvedConcreteItem::Impl(
895 ImplLongId::GenericParameter(*generic_param_id).intern(self.db),
896 ),
897 GenericKind::NegImpl => return None,
898 };
899 return Some(item);
900 }
901 None
904 }
905
906 pub fn prelude_submodule(&self) -> ModuleId<'db> {
907 self.prelude_submodule_ex(&MacroResolutionInfo::from_resolver(self))
908 }
909
910 fn prelude_submodule_ex(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
912 let active_settings = self.active_settings(info);
913 self.db.get_prelude_submodule(active_settings).unwrap_or_else(|| {
914 panic!(
915 "expected prelude submodule `{}` not found in `core::prelude`.",
916 active_settings.edition.prelude_submodule_name(self.db).long(self.db)
917 )
918 })
919 }
920
921 fn specialize_trait(
923 &mut self,
924 diagnostics: &mut SemanticDiagnostics<'db>,
925 stable_ptr: SyntaxStablePtrId<'db>,
926 trait_id: TraitId<'db>,
927 generic_args: &[ast::GenericArg<'db>],
928 ) -> Maybe<ConcreteTraitId<'db>> {
929 let generic_params = self
931 .db
932 .trait_generic_params(trait_id)
933 .map_err(|_| diagnostics.report(stable_ptr, UnknownTrait))?;
934 let generic_args = self.resolve_generic_args(
935 diagnostics,
936 GenericSubstitution::default(),
937 generic_params,
938 generic_args,
939 stable_ptr,
940 )?;
941
942 Ok(ConcreteTraitLongId { trait_id, generic_args }.intern(self.db))
943 }
944
945 fn specialize_impl(
947 &mut self,
948 diagnostics: &mut SemanticDiagnostics<'db>,
949 stable_ptr: SyntaxStablePtrId<'db>,
950 impl_def_id: ImplDefId<'db>,
951 generic_args: &[ast::GenericArg<'db>],
952 ) -> Maybe<ConcreteImplId<'db>> {
953 let generic_params = self
955 .db
956 .impl_def_generic_params(impl_def_id)
957 .map_err(|_| diagnostics.report(stable_ptr, UnknownImpl))?;
958 let generic_args = self.resolve_generic_args(
959 diagnostics,
960 GenericSubstitution::default(),
961 generic_params,
962 generic_args,
963 stable_ptr,
964 )?;
965
966 Ok(ConcreteImplLongId { impl_def_id, generic_args }.intern(self.db))
967 }
968
969 fn specialize_variant(
971 &mut self,
972 diagnostics: &mut SemanticDiagnostics<'db>,
973 stable_ptr: SyntaxStablePtrId<'db>,
974 variant_id: VariantId<'db>,
975 generic_args: &[ast::GenericArg<'db>],
976 ) -> Maybe<ConcreteVariant<'db>> {
977 let concrete_enum_id = ConcreteEnumLongId {
978 enum_id: variant_id.enum_id(self.db),
979 generic_args: self.resolve_generic_args(
980 diagnostics,
981 GenericSubstitution::default(),
982 self.db.enum_generic_params(variant_id.enum_id(self.db))?,
983 generic_args,
984 stable_ptr,
985 )?,
986 }
987 .intern(self.db);
988 self.db.concrete_enum_variant(
989 concrete_enum_id,
990 &self.db.variant_semantic(variant_id.enum_id(self.db), variant_id)?,
991 )
992 }
993
994 pub fn specialize_function(
996 &mut self,
997 diagnostics: &mut SemanticDiagnostics<'db>,
998 stable_ptr: SyntaxStablePtrId<'db>,
999 generic_function: GenericFunctionId<'db>,
1000 generic_args: &[ast::GenericArg<'db>],
1001 ) -> Maybe<FunctionId<'db>> {
1002 let generic_params = generic_function.generic_params(self.db)?;
1004 let generic_args = self.resolve_generic_args(
1005 diagnostics,
1006 GenericSubstitution::default(),
1007 generic_params,
1008 generic_args,
1009 stable_ptr,
1010 )?;
1011
1012 Ok(FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }
1013 .intern(self.db))
1014 }
1015
1016 pub fn specialize_type(
1018 &mut self,
1019 diagnostics: &mut SemanticDiagnostics<'db>,
1020 stable_ptr: SyntaxStablePtrId<'db>,
1021 generic_type: GenericTypeId<'db>,
1022 generic_args: &[ast::GenericArg<'db>],
1023 ) -> Maybe<TypeId<'db>> {
1024 let generic_params = self
1025 .db
1026 .generic_type_generic_params(generic_type)
1027 .map_err(|_| diagnostics.report(stable_ptr, UnknownType))?;
1028 let generic_args = self.resolve_generic_args(
1029 diagnostics,
1030 GenericSubstitution::default(),
1031 generic_params,
1032 generic_args,
1033 stable_ptr,
1034 )?;
1035
1036 Ok(TypeLongId::Concrete(ConcreteTypeId::new(self.db, generic_type, generic_args))
1037 .intern(self.db))
1038 }
1039
1040 pub fn impl_lookup_context(&self) -> ImplLookupContextId<'db> {
1042 self.impl_lookup_context_ex(&MacroResolutionInfo::from_resolver(self))
1043 }
1044
1045 fn impl_lookup_context_ex(&self, info: &MacroResolutionInfo<'db>) -> ImplLookupContextId<'db> {
1048 let mut lookup_context = ImplLookupContext::new(
1049 self.active_module_id(info),
1050 self.generic_params.clone(),
1051 self.db,
1052 );
1053
1054 if let TraitOrImplContext::Impl(impl_def_id) = &self.trait_or_impl_ctx {
1055 let Ok(generic_params) = self.db.impl_def_generic_params(*impl_def_id) else {
1056 return lookup_context.intern(self.db);
1057 };
1058 let generic_args = generic_params_to_args(generic_params, self.db);
1059 let impl_id: ConcreteImplId<'_> =
1060 ConcreteImplLongId { impl_def_id: *impl_def_id, generic_args }.intern(self.db);
1061 lookup_context.insert_impl(ImplLongId::Concrete(impl_id).intern(self.db), self.db);
1062 }
1063 lookup_context.intern(self.db)
1064 }
1065
1066 pub fn resolve_generic_args(
1070 &mut self,
1071 diagnostics: &mut SemanticDiagnostics<'db>,
1072 mut substitution: GenericSubstitution<'db>,
1073 generic_params: &[GenericParam<'db>],
1074 generic_args_syntax: &[ast::GenericArg<'db>],
1075 stable_ptr: SyntaxStablePtrId<'db>,
1076 ) -> Maybe<Vec<GenericArgumentId<'db>>> {
1077 let mut resolved_args = vec![];
1078 let arg_syntax_per_param = self.get_arg_syntax_per_param(
1079 diagnostics,
1080 &generic_params.iter().map(|generic_param| generic_param.id()).collect_vec(),
1081 generic_args_syntax,
1082 )?;
1083
1084 for generic_param in generic_params {
1085 let generic_param = substitution.substitute(self.db, generic_param.clone())?;
1086 let generic_arg = self.resolve_generic_arg(
1087 &generic_param,
1088 arg_syntax_per_param
1089 .get(&generic_param.id())
1090 .filter(|expr| !matches!(expr, ast::Expr::Underscore(_))),
1091 stable_ptr,
1092 diagnostics,
1093 )?;
1094 resolved_args.push(generic_arg);
1095 substitution.insert(generic_param.id(), generic_arg);
1096 }
1097
1098 Ok(resolved_args)
1099 }
1100
1101 pub fn get_arg_syntax_per_param(
1103 &self,
1104 diagnostics: &mut SemanticDiagnostics<'db>,
1105 generic_params: &[GenericParamId<'db>],
1106 generic_args_syntax: &[ast::GenericArg<'db>],
1107 ) -> Maybe<UnorderedHashMap<GenericParamId<'db>, ast::Expr<'db>>> {
1108 let db = self.db;
1109 let mut arg_syntax_per_param =
1110 UnorderedHashMap::<GenericParamId<'_>, ast::Expr<'_>>::default();
1111 let mut last_named_arg_index = None;
1112 let generic_param_by_name = generic_params
1113 .iter()
1114 .enumerate()
1115 .filter_map(|(i, param)| Some((param.name(self.db)?, (i, param))))
1116 .collect::<UnorderedHashMap<_, _>>();
1117 for (idx, generic_arg_syntax) in generic_args_syntax.iter().enumerate() {
1118 match generic_arg_syntax {
1119 ast::GenericArg::Named(arg_syntax) => {
1120 let name = arg_syntax.name(db).text(db);
1121 let Some((index, generic_param_id)) = generic_param_by_name.get(&name) else {
1122 return Err(diagnostics
1123 .report(arg_syntax.stable_ptr(db), UnknownGenericParam(name)));
1124 };
1125 if let Some(prev_index) = last_named_arg_index
1126 && prev_index > index
1127 {
1128 return Err(diagnostics
1129 .report(arg_syntax.stable_ptr(db), GenericArgOutOfOrder(name)));
1130 }
1131 last_named_arg_index = Some(index);
1132 if arg_syntax_per_param
1133 .insert(**generic_param_id, arg_syntax.value(db))
1134 .is_some()
1135 {
1136 return Err(diagnostics
1137 .report(arg_syntax.stable_ptr(db), GenericArgDuplicate(name)));
1138 }
1139 }
1140 ast::GenericArg::Unnamed(arg_syntax) => {
1141 if last_named_arg_index.is_some() {
1142 return Err(diagnostics
1143 .report(arg_syntax.stable_ptr(db), PositionalGenericAfterNamed));
1144 }
1145 let generic_param = generic_params.get(idx).ok_or_else(|| {
1146 diagnostics.report(
1147 arg_syntax.stable_ptr(db),
1148 TooManyGenericArguments {
1149 expected: generic_params.len(),
1150 actual: generic_args_syntax.len(),
1151 },
1152 )
1153 })?;
1154 assert_eq!(
1155 arg_syntax_per_param.insert(*generic_param, arg_syntax.value(db)),
1156 None,
1157 "Unexpected duplication in ordered params."
1158 );
1159 }
1160 }
1161 }
1162 Ok(arg_syntax_per_param)
1163 }
1164
1165 fn resolve_generic_arg(
1169 &mut self,
1170 generic_param: &GenericParam<'db>,
1171 generic_arg_syntax_opt: Option<&ast::Expr<'db>>,
1172 stable_ptr: SyntaxStablePtrId<'db>,
1173 diagnostics: &mut SemanticDiagnostics<'db>,
1174 ) -> Result<GenericArgumentId<'db>, cairo_lang_diagnostics::DiagnosticAdded> {
1175 let Some(generic_arg_syntax) = generic_arg_syntax_opt else {
1176 let lookup_context = self.impl_lookup_context();
1177 let inference = &mut self.data.inference_data.inference(self.db);
1178 return inference
1179 .infer_generic_arg(generic_param, lookup_context, Some(stable_ptr))
1180 .map_err(|err_set| {
1181 inference.report_on_pending_error(err_set, diagnostics, stable_ptr)
1182 });
1183 };
1184 let db = self.db;
1185 Ok(match generic_param {
1186 GenericParam::Type(_) => {
1187 GenericArgumentId::Type(resolve_type(db, diagnostics, self, generic_arg_syntax))
1188 }
1189 GenericParam::Const(const_param) => {
1190 let mut ctx = ComputationContext::new_global(db, diagnostics, self);
1194 let value = compute_expr_semantic(&mut ctx, generic_arg_syntax);
1195 GenericArgumentId::Constant(resolve_const_expr_and_evaluate(
1196 db,
1197 &mut ctx,
1198 &value,
1199 generic_arg_syntax.stable_ptr(db).untyped(),
1200 const_param.ty,
1201 false,
1202 ))
1203 }
1204
1205 GenericParam::Impl(param) => {
1206 let expr_path = try_extract_matches!(generic_arg_syntax, ast::Expr::Path)
1207 .ok_or_else(|| {
1208 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1209 })?;
1210 let resolved_impl = match self.resolve_concrete_path(
1211 diagnostics,
1212 expr_path,
1213 NotFoundItemType::Impl,
1214 )? {
1215 ResolvedConcreteItem::Impl(resolved_impl) => resolved_impl,
1216 ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
1217 ImplLongId::SelfImpl(concrete_trait_id).intern(self.db)
1218 }
1219 _ => {
1220 return Err(
1221 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1222 );
1223 }
1224 };
1225 let impl_def_concrete_trait = self.db.impl_concrete_trait(resolved_impl)?;
1226 let expected_concrete_trait = param.concrete_trait?;
1227 if let Err(err_set) = self
1228 .inference()
1229 .conform_traits(impl_def_concrete_trait, expected_concrete_trait)
1230 {
1231 let diag_added = diagnostics.report(
1232 generic_arg_syntax.stable_ptr(db),
1233 TraitMismatch {
1234 expected_trt: expected_concrete_trait,
1235 actual_trt: impl_def_concrete_trait,
1236 },
1237 );
1238 self.inference().consume_reported_error(err_set, diag_added);
1239 } else {
1240 for (trait_ty, ty1) in param.type_constraints.iter() {
1241 let ty0 = TypeLongId::ImplType(ImplTypeId::new(
1242 resolved_impl,
1243 *trait_ty,
1244 self.db,
1245 ))
1246 .intern(self.db);
1247 let _ = self.inference().conform_ty(ty0, *ty1).map_err(|err_set| {
1248 self.inference().report_on_pending_error(
1249 err_set,
1250 diagnostics,
1251 stable_ptr,
1252 )
1253 });
1254 }
1255 }
1256 GenericArgumentId::Impl(resolved_impl)
1257 }
1258 GenericParam::NegImpl(_) => {
1259 return Err(
1260 diagnostics.report(generic_arg_syntax.stable_ptr(db), ArgPassedToNegativeImpl)
1261 );
1262 }
1263 })
1264 }
1265
1266 pub fn ignore_visibility_checks(&self, module_id: ModuleId<'db>) -> bool {
1269 self.ignore_visibility_checks_ex(module_id, &MacroResolutionInfo::from_resolver(self))
1270 }
1271
1272 fn ignore_visibility_checks_ex(
1275 &self,
1276 module_id: ModuleId<'db>,
1277 info: &MacroResolutionInfo<'db>,
1278 ) -> bool {
1279 let module_crate = module_id.owning_crate(self.db);
1280 let module_edition =
1281 self.db.crate_config(module_crate).map(|c| c.settings.edition).unwrap_or_default();
1282 module_edition.ignore_visibility()
1283 || self.active_settings(info).edition.ignore_visibility()
1284 && module_crate == self.db.core_crate()
1285 }
1286
1287 pub fn validate_feature_constraints<T: HasFeatureKind<'db>>(
1292 &self,
1293 diagnostics: &mut SemanticDiagnostics<'db>,
1294 identifier: &ast::TerminalIdentifier<'db>,
1295 item_info: &T,
1296 ) {
1297 let db = self.db;
1298 match item_info.feature_kind() {
1299 FeatureKind::Unstable { feature, note }
1300 if !self.data.feature_config.allowed_features.contains(feature) =>
1301 {
1302 diagnostics.report(
1303 identifier.stable_ptr(db),
1304 UnstableFeature { feature_name: *feature, note: *note },
1305 );
1306 }
1307 FeatureKind::Deprecated { feature, note }
1308 if !self
1309 .data
1310 .feature_config
1311 .allowed_lints
1312 .contains(&SmolStrId::from(self.db, DEPRECATED_ATTR))
1313 && !self.data.feature_config.allowed_features.contains(feature) =>
1314 {
1315 diagnostics.report(
1316 identifier.stable_ptr(db),
1317 DeprecatedFeature { feature_name: *feature, note: *note },
1318 );
1319 }
1320 FeatureKind::Internal { feature, note }
1321 if !self.data.feature_config.allowed_features.contains(feature) =>
1322 {
1323 diagnostics.report(
1324 identifier.stable_ptr(db),
1325 InternalFeature { feature_name: *feature, note: *note },
1326 );
1327 }
1328 _ => {}
1329 }
1330 }
1331
1332 pub fn is_item_visible(
1334 &self,
1335 containing_module_id: ModuleId<'db>,
1336 item_info: &ModuleItemInfo<'db>,
1337 user_module: ModuleId<'db>,
1338 ) -> bool {
1339 self.is_item_visible_ex(
1340 containing_module_id,
1341 item_info,
1342 user_module,
1343 &MacroResolutionInfo::from_resolver(self),
1344 )
1345 }
1346
1347 fn is_item_visible_ex(
1349 &self,
1350 mut containing_module_id: ModuleId<'db>, item_info: &ModuleItemInfo<'db>,
1352 user_module: ModuleId<'db>,
1353 info: &MacroResolutionInfo<'db>,
1354 ) -> bool {
1355 let db = self.db;
1356 if containing_module_id == user_module {
1357 return true;
1358 }
1359 while let ModuleId::MacroCall { id, .. } = containing_module_id {
1360 containing_module_id = id.parent_module(self.db);
1361 }
1362 self.ignore_visibility_checks_ex(containing_module_id, info)
1363 || visibility::peek_visible_in(
1364 db,
1365 item_info.visibility,
1366 containing_module_id,
1367 user_module,
1368 )
1369 }
1370
1371 pub fn insert_used_use(&mut self, item_id: ModuleItemId<'db>) {
1373 if let ModuleItemId::Use(use_id) = item_id {
1374 self.data.used_uses.insert(use_id);
1375 }
1376 }
1377
1378 fn handle_same_impl_trait(
1384 &mut self,
1385 diagnostics: &mut SemanticDiagnostics<'db>,
1386 specialized_item: &mut ResolvedConcreteItem<'db>,
1387 generic_args_syntax_slice: &[ast::GenericArg<'db>],
1388 segment_stable_ptr: SyntaxStablePtrId<'db>,
1389 ) {
1390 match *specialized_item {
1391 ResolvedConcreteItem::Trait(current_segment_concrete_trait) => {
1392 match self.trait_or_impl_ctx {
1393 TraitOrImplContext::None => {}
1394 TraitOrImplContext::Trait(ctx_trait) => {
1395 if self
1396 .warn_trait_in_same_trait(
1397 diagnostics,
1398 current_segment_concrete_trait.trait_id(self.db),
1399 generic_args_syntax_slice,
1400 ctx_trait,
1401 segment_stable_ptr,
1402 )
1403 .is_err()
1404 {
1405 *specialized_item =
1406 ResolvedConcreteItem::SelfTrait(current_segment_concrete_trait);
1407 }
1408 }
1409 TraitOrImplContext::Impl(ctx_impl_def_id) => {
1410 self.warn_trait_in_its_impl(
1411 diagnostics,
1412 current_segment_concrete_trait,
1413 ctx_impl_def_id,
1414 segment_stable_ptr,
1415 )
1416 .ok();
1417 }
1418 };
1419 }
1420 ResolvedConcreteItem::Impl(current_segment_impl_id) => {
1421 if let TraitOrImplContext::Impl(ctx_impl) = self.trait_or_impl_ctx {
1422 let current_segment_concrete_impl_id = extract_matches!(
1425 current_segment_impl_id.long(self.db),
1426 ImplLongId::Concrete
1427 );
1428 self.warn_impl_in_same_impl(
1429 diagnostics,
1430 current_segment_concrete_impl_id.impl_def_id(self.db),
1431 generic_args_syntax_slice,
1432 ctx_impl,
1433 segment_stable_ptr,
1434 )
1435 .ok();
1436 }
1437 }
1438 _ => {}
1439 };
1440 }
1441
1442 fn warn_impl_in_same_impl(
1445 &mut self,
1446 diagnostics: &mut SemanticDiagnostics<'db>,
1447 current_segment_impl_def_id: ImplDefId<'db>,
1448 current_segment_generic_args: &[ast::GenericArg<'db>],
1449 ctx_impl: ImplDefId<'db>,
1450 segment_stable_ptr: SyntaxStablePtrId<'db>,
1451 ) -> Maybe<()> {
1452 if current_segment_impl_def_id != ctx_impl {
1453 return Ok(());
1454 }
1455
1456 let generic_params = self.db.impl_def_generic_params(ctx_impl)?;
1457 self.compare_segment_args_to_params(
1458 diagnostics,
1459 current_segment_generic_args,
1460 generic_params,
1461 segment_stable_ptr,
1462 ImplInImplMustBeExplicit,
1463 ImplItemForbiddenInTheImpl,
1464 )
1465 }
1466
1467 fn warn_trait_in_its_impl(
1470 &mut self,
1471 diagnostics: &mut SemanticDiagnostics<'db>,
1472 current_segment_concrete_trait_id: ConcreteTraitId<'db>,
1473 impl_ctx: ImplDefId<'db>,
1474 segment_stable_ptr: SyntaxStablePtrId<'db>,
1475 ) -> Maybe<()> {
1476 let ctx_impl_trait = self.db.impl_def_trait(impl_ctx)?;
1477 if current_segment_concrete_trait_id.trait_id(self.db) != ctx_impl_trait {
1478 return Ok(());
1479 }
1480
1481 let ctx_impl_concrete_trait = self.db.impl_def_concrete_trait(impl_ctx)?;
1482 if ctx_impl_concrete_trait.generic_args(self.db)
1483 == current_segment_concrete_trait_id.generic_args(self.db)
1484 {
1485 return Err(diagnostics.report(segment_stable_ptr, TraitItemForbiddenInItsImpl));
1486 }
1487 Ok(())
1488 }
1489
1490 fn warn_trait_in_same_trait(
1493 &mut self,
1494 diagnostics: &mut SemanticDiagnostics<'db>,
1495 current_segment_trait_id: TraitId<'db>,
1496 current_segment_generic_args: &[ast::GenericArg<'db>],
1497 ctx_trait: TraitId<'db>,
1498 segment_stable_ptr: SyntaxStablePtrId<'db>,
1499 ) -> Maybe<()> {
1500 if current_segment_trait_id != ctx_trait {
1501 return Ok(());
1502 }
1503
1504 let generic_params = self.db.trait_generic_params(ctx_trait)?;
1505 self.compare_segment_args_to_params(
1506 diagnostics,
1507 current_segment_generic_args,
1508 generic_params,
1509 segment_stable_ptr,
1510 TraitInTraitMustBeExplicit,
1511 TraitItemForbiddenInTheTrait,
1512 )
1513 }
1514
1515 fn compare_segment_args_to_params(
1522 &mut self,
1523 diagnostics: &mut SemanticDiagnostics<'db>,
1524 current_segment_generic_args: &[ast::GenericArg<'db>],
1525 generic_params: &[GenericParam<'db>],
1526 segment_stable_ptr: SyntaxStablePtrId<'db>,
1527 must_be_explicit_error: SemanticDiagnosticKind<'db>,
1528 item_forbidden_in_itself_explicit_error: SemanticDiagnosticKind<'db>,
1529 ) -> Maybe<()> {
1530 if current_segment_generic_args.len() < generic_params.len() {
1533 return Err(diagnostics.report(segment_stable_ptr, must_be_explicit_error));
1534 }
1535 let resolved_args = self.resolve_generic_args(
1536 diagnostics,
1537 GenericSubstitution::default(),
1538 generic_params,
1539 current_segment_generic_args,
1540 segment_stable_ptr,
1541 )?;
1542
1543 if generic_params
1544 .iter()
1545 .zip_eq(resolved_args.iter())
1546 .all(|(gparam, garg)| gparam.as_arg(self.db) == *garg)
1547 {
1548 return Err(
1549 diagnostics.report(segment_stable_ptr, item_forbidden_in_itself_explicit_error)
1550 );
1551 }
1552 Ok(())
1553 }
1554
1555 fn specialize_generic_statement_arg(
1557 &mut self,
1558 diagnostics: &mut SemanticDiagnostics<'db>,
1559 segment: &ast::PathSegment<'db>,
1560 identifier: &ast::TerminalIdentifier<'db>,
1561 inner_generic_item: ResolvedGenericItem<'db>,
1562 generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
1563 ) -> Maybe<ResolvedConcreteItem<'db>> {
1564 let segment_stable_ptr = segment.stable_ptr(self.db).untyped();
1565 let mut specialized_item = self.specialize_generic_module_item(
1566 diagnostics,
1567 identifier,
1568 inner_generic_item,
1569 generic_args_syntax.clone(),
1570 )?;
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 Ok(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(Option<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 let inner_generic_item =
1845 self.resolve_module_item_as_generic(module_id, identifier, &inner_item_info)?;
1846 let mut specialized_item = self.resolver.specialize_generic_module_item(
1847 self.diagnostics,
1848 identifier,
1849 inner_generic_item.clone(),
1850 generic_args_syntax.clone(),
1851 )?;
1852 self.resolver
1853 .data
1854 .resolved_items
1855 .generic
1856 .insert(identifier.stable_ptr(db), inner_generic_item);
1857 self.resolver.handle_same_impl_trait(
1858 self.diagnostics,
1859 &mut specialized_item,
1860 &generic_args_syntax.unwrap_or_default(),
1861 segment_stable_ptr,
1862 );
1863 Ok(specialized_item)
1864 }
1865
1866 fn first_concrete(&mut self) -> Maybe<ResolvedConcreteItem<'db>> {
1868 if let Some(base_module) =
1869 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
1870 resolved_items.mark_concrete(db, segment, ResolvedConcreteItem::Module(module_id));
1871 })
1872 {
1873 return Ok(ResolvedConcreteItem::Module(base_module?));
1874 }
1875
1876 let db = self.resolver.db;
1877 Ok(match self.segments.peek().unwrap() {
1878 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
1879 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
1880 let identifier = generic_segment.ident(db);
1881 match self.determine_base(&identifier)? {
1883 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1884 ResolvedBase::Crate(_) => {
1885 return Err(self
1887 .diagnostics
1888 .report(generics_stable_ptr, UnexpectedGenericArgs));
1889 }
1890 ResolvedBase::StatementEnvironment(generic_item) => {
1891 let segment = self.segments.next().unwrap();
1892 let concrete_item = self.resolver.specialize_generic_statement_arg(
1893 self.diagnostics,
1894 &segment,
1895 &identifier,
1896 generic_item,
1897 segment.generic_args(db),
1898 )?;
1899 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1900 }
1901 ResolvedBase::FoundThroughGlobalUse {
1902 item_info: inner_module_item,
1903 containing_module: module_id,
1904 } => {
1905 let segment = self.segments.next().unwrap();
1906
1907 let concrete_item = self.specialize_generic_inner_item(
1908 module_id,
1909 &segment,
1910 &identifier,
1911 inner_module_item,
1912 )?;
1913 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1914 }
1915 ResolvedBase::Ambiguous(module_items) => {
1916 return Err(self
1917 .diagnostics
1918 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1919 }
1920 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1921 return Err(self.diagnostics.report(
1922 identifier.stable_ptr(db),
1923 ItemNotVisible(module_item_id, containing_modules),
1924 ));
1925 }
1926 }
1927 }
1928 syntax::node::ast::PathSegment::Simple(simple_segment) => {
1929 let identifier = simple_segment.ident(db);
1930
1931 if let Some(resolved_item) = resolve_self_segment(
1932 db,
1933 self.diagnostics,
1934 &identifier,
1935 &self.resolver.data.trait_or_impl_ctx,
1936 ) {
1937 return Ok(self.resolver.resolved_items.mark_concrete(
1939 db,
1940 &self.segments.next().unwrap(),
1941 resolved_item?,
1942 ));
1943 }
1944
1945 if let Some(local_item) =
1946 self.resolver.determine_base_item_in_local_scope(&identifier)
1947 {
1948 self.resolver.resolved_items.mark_concrete(
1949 db,
1950 &self.segments.next().unwrap(),
1951 local_item,
1952 )
1953 } else {
1954 match self.determine_base(&identifier)? {
1955 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1957 ResolvedBase::Crate(crate_id) => {
1958 self.resolver.resolved_items.mark_concrete(
1959 db,
1960 &self.segments.next().unwrap(),
1961 ResolvedConcreteItem::Module(ModuleId::CrateRoot(crate_id)),
1962 )
1963 }
1964 ResolvedBase::StatementEnvironment(generic_item) => {
1965 let segment = self.segments.next().unwrap();
1966
1967 let concrete_item = self.resolver.specialize_generic_statement_arg(
1968 self.diagnostics,
1969 &segment,
1970 &identifier,
1971 generic_item,
1972 segment.generic_args(db),
1973 )?;
1974 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1975 }
1976 ResolvedBase::FoundThroughGlobalUse {
1977 item_info: inner_module_item,
1978 containing_module: module_id,
1979 } => {
1980 let segment = self.segments.next().unwrap();
1981 let concrete_item = self.specialize_generic_inner_item(
1982 module_id,
1983 &segment,
1984 &identifier,
1985 inner_module_item,
1986 )?;
1987 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1988 }
1989 ResolvedBase::Ambiguous(module_items) => {
1990 return Err(self
1991 .diagnostics
1992 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1993 }
1994 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1995 return Err(self.diagnostics.report(
1996 identifier.stable_ptr(db),
1997 ItemNotVisible(module_item_id, containing_modules),
1998 ));
1999 }
2000 }
2001 }
2002 }
2003 })
2004 }
2005 fn first_generic(&mut self, allow_generic_args: bool) -> Maybe<ResolvedGenericItem<'db>> {
2008 if let Some(base_module) =
2009 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
2010 resolved_items.mark_generic(db, segment, ResolvedGenericItem::Module(module_id));
2011 })
2012 {
2013 return Ok(ResolvedGenericItem::Module(base_module?));
2014 }
2015 let db = self.resolver.db;
2016 Ok(match self.segments.peek().unwrap() {
2017 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
2018 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
2019 if !allow_generic_args {
2020 return Err(self
2021 .diagnostics
2022 .report(generics_stable_ptr, UnexpectedGenericArgs));
2023 }
2024 let identifier = generic_segment.ident(db);
2025 match self.determine_base(&identifier)? {
2026 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2027 ResolvedBase::Crate(_) => {
2028 return Err(self
2030 .diagnostics
2031 .report(generics_stable_ptr, UnexpectedGenericArgs));
2032 }
2033 ResolvedBase::StatementEnvironment(generic_item) => generic_item,
2034 ResolvedBase::FoundThroughGlobalUse {
2035 item_info: inner_module_item,
2036 containing_module,
2037 } => {
2038 let generic_item = self.resolve_module_item_as_generic(
2039 containing_module,
2040 &identifier,
2041 &inner_module_item,
2042 )?;
2043 self.resolver.resolved_items.mark_generic(
2044 db,
2045 &self.segments.next().unwrap(),
2046 generic_item,
2047 )
2048 }
2049 ResolvedBase::Ambiguous(module_items) => {
2050 return Err(self
2051 .diagnostics
2052 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2053 }
2054 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2055 return Err(self.diagnostics.report(
2056 identifier.stable_ptr(db),
2057 ItemNotVisible(module_item_id, containing_modules),
2058 ));
2059 }
2060 }
2061 }
2062 syntax::node::ast::PathSegment::Simple(simple_segment) => {
2063 let identifier = simple_segment.ident(db);
2064 match self.determine_base(&identifier)? {
2065 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2067 ResolvedBase::Crate(crate_id) => self.resolver.resolved_items.mark_generic(
2068 db,
2069 &self.segments.next().unwrap(),
2070 ResolvedGenericItem::Module(ModuleId::CrateRoot(crate_id)),
2071 ),
2072 ResolvedBase::StatementEnvironment(generic_item) => self
2073 .resolver
2074 .resolved_items
2075 .mark_generic(db, &self.segments.next().unwrap(), generic_item),
2076 ResolvedBase::FoundThroughGlobalUse {
2077 item_info: inner_module_item,
2078 containing_module,
2079 } => {
2080 let generic_item = self.resolve_module_item_as_generic(
2081 containing_module,
2082 &identifier,
2083 &inner_module_item,
2084 )?;
2085 self.resolver.resolved_items.mark_generic(
2086 db,
2087 &self.segments.next().unwrap(),
2088 generic_item,
2089 )
2090 }
2091 ResolvedBase::Ambiguous(module_items) => {
2092 return Err(self
2093 .diagnostics
2094 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2095 }
2096 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2097 return Err(self.diagnostics.report(
2098 identifier.stable_ptr(db),
2099 ItemNotVisible(module_item_id, containing_modules),
2100 ));
2101 }
2102 }
2103 }
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(_) => 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 ident.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.resolve_module_item_as_generic(*module_id, &identifier, &inner_item_info)
2494 }
2495 ResolvedGenericItem::GenericType(GenericTypeId::Enum(enum_id)) => {
2496 let variants = db.enum_variants(*enum_id)?;
2497 let variant_id = variants.get(&ident).ok_or_else(|| {
2498 self.diagnostics.report(
2499 identifier.stable_ptr(db),
2500 NoSuchVariant { enum_id: *enum_id, variant_name: ident },
2501 )
2502 })?;
2503 let variant = db.variant_semantic(*enum_id, *variant_id)?;
2504 Ok(ResolvedGenericItem::Variant(variant))
2505 }
2506 _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2507 }
2508 }
2509
2510 fn determine_base(
2513 &mut self,
2514 identifier: &ast::TerminalIdentifier<'db>,
2515 ) -> Maybe<ResolvedBase<'db>> {
2516 let db = self.resolver.db;
2517 let ident = identifier.text(db);
2518 if let ResolutionContext::Statement(ref mut env) = self.resolution_context
2519 && let Some(item) = get_statement_item_by_name(env, ident)
2520 {
2521 return Ok(ResolvedBase::StatementEnvironment(item));
2522 }
2523
2524 let Some(module_id) = self.resolver.try_get_active_module_id(&self.macro_info) else {
2525 let item_type = if self.segments.len() == 1 {
2526 self.expected_item_type
2527 } else {
2528 NotFoundItemType::Identifier
2529 };
2530 return Err(self
2531 .diagnostics
2532 .report(identifier.stable_ptr(db), PathNotFound(item_type)));
2533 };
2534 if let Some(info) = self.resolver.resolve_item_in_module_or_expanded_macro(module_id, ident)
2536 && !matches!(self.resolution_context, ResolutionContext::ModuleItem(id) if id == info.item_id)
2537 {
2538 return Ok(ResolvedBase::Module(module_id));
2539 }
2540
2541 if ident.long(db) == CRATE_KW {
2543 return Ok(ResolvedBase::Crate(self.resolver.active_owning_crate_id(&self.macro_info)));
2544 }
2545 if let Some(dep) = self
2548 .resolver
2549 .active_settings(&self.macro_info)
2550 .dependencies
2551 .get(ident.long(db).as_str())
2552 {
2553 let dep_crate_id =
2554 CrateLongId::Real { name: ident, discriminator: dep.discriminator.clone() }
2555 .intern(db);
2556 let configs = db.crate_configs();
2557 if !configs.contains_key(&dep_crate_id) {
2558 let get_long_id = |crate_id: CrateId<'db>| crate_id.long(db);
2559 panic!(
2560 "Invalid crate dependency: {:?}\nconfigured crates: {:#?}",
2561 get_long_id(dep_crate_id),
2562 configs.keys().cloned().map(get_long_id).collect_vec()
2563 );
2564 }
2565
2566 return Ok(ResolvedBase::Crate(dep_crate_id));
2567 }
2568 if ident.long(db) == CORELIB_CRATE_NAME {
2570 return Ok(ResolvedBase::Crate(CrateId::core(db)));
2571 }
2572 if ident.long(db) == STARKNET_CRATE_NAME {
2574 return Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)));
2576 }
2577 match self.resolver.resolve_path_using_use_star(module_id, ident) {
2579 UseStarResult::UniquePathFound(inner_module_item) => {
2580 return Ok(ResolvedBase::FoundThroughGlobalUse {
2581 item_info: inner_module_item,
2582 containing_module: module_id,
2583 });
2584 }
2585 UseStarResult::AmbiguousPath(module_items) => {
2586 return Ok(ResolvedBase::Ambiguous(module_items));
2587 }
2588 UseStarResult::PathNotFound => {}
2589 UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
2590 let prelude = self.resolver.prelude_submodule_ex(&self.macro_info);
2591 if let Ok(Some(_)) = db.module_item_by_name(prelude, ident) {
2592 return Ok(ResolvedBase::Module(prelude));
2593 }
2594 return Ok(ResolvedBase::ItemNotVisible(module_item_id, containing_modules));
2595 }
2596 }
2597 Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)))
2598 }
2599
2600 fn resolve_module_item_as_generic(
2608 &mut self,
2609 containing_module: ModuleId<'db>,
2610 identifier: &ast::TerminalIdentifier<'db>,
2611 item_info: &ModuleItemInfo<'db>,
2612 ) -> Maybe<ResolvedGenericItem<'db>> {
2613 let Self { resolver, diagnostics, macro_info, .. } = self;
2614 let active_module = resolver.active_module_id(macro_info);
2615 if !resolver.is_item_visible_ex(containing_module, item_info, active_module, macro_info) {
2616 let stable_ptr = identifier.stable_ptr(resolver.db);
2617 diagnostics.report(stable_ptr, ItemNotVisible(Some(item_info.item_id), vec![]));
2618 }
2619
2620 resolver.validate_feature_constraints(diagnostics, identifier, item_info);
2621 resolver.insert_used_use(item_info.item_id);
2622 ResolvedGenericItem::from_module_item(resolver.db, item_info.item_id)
2623 }
2624}