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::default();
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 fn resolve_item_in_module_or_expanded_macro(
813 &mut self,
814 module_id: ModuleId<'db>,
815 ident: SmolStrId<'db>,
816 ) -> Option<ModuleItemInfo<'db>> {
817 if let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
818 self.insert_used_use(info.item_id);
819 return Some(info);
820 }
821 let mut stack = vec![(module_id, false)];
822 loop {
823 let (module_id, expose) = stack.pop()?;
824 if expose && let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
825 self.insert_used_use(info.item_id);
826 return Some(info);
827 }
828 if let Ok(macro_calls) = self.db.module_macro_calls_ids(module_id) {
829 for macro_call in macro_calls {
830 if let Ok(macro_module_id) = self.db.macro_call_module_id(*macro_call) {
831 let expose = expose
832 || matches!(
833 macro_module_id,
834 ModuleId::MacroCall { is_expose: true, .. }
835 );
836 stack.push((macro_module_id, expose));
837 }
838 }
839 }
840 }
841 }
842
843 pub fn determine_base_item_in_local_scope(
845 &mut self,
846 identifier: &ast::TerminalIdentifier<'db>,
847 ) -> Option<ResolvedConcreteItem<'db>> {
848 let db = self.db;
849 let ident = identifier.text(db);
850
851 if let Some(generic_param_id) = self.data.generic_param_by_name.get(&ident) {
853 let item = match generic_param_id.kind(self.db) {
854 GenericKind::Type => ResolvedConcreteItem::Type(
855 TypeLongId::GenericParameter(*generic_param_id).intern(self.db),
856 ),
857 GenericKind::Const => ResolvedConcreteItem::Constant(
858 ConstValue::Generic(*generic_param_id).intern(self.db),
859 ),
860 GenericKind::Impl => ResolvedConcreteItem::Impl(
861 ImplLongId::GenericParameter(*generic_param_id).intern(self.db),
862 ),
863 GenericKind::NegImpl => return None,
864 };
865 return Some(item);
866 }
867 None
870 }
871
872 pub fn prelude_submodule(&self) -> ModuleId<'db> {
873 self.prelude_submodule_ex(&MacroResolutionInfo::from_resolver(self))
874 }
875
876 fn prelude_submodule_ex(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
878 let active_settings = self.active_settings(info);
879 self.db.get_prelude_submodule(active_settings).unwrap_or_else(|| {
880 panic!(
881 "expected prelude submodule `{}` not found in `core::prelude`.",
882 active_settings.edition.prelude_submodule_name(self.db).long(self.db)
883 )
884 })
885 }
886
887 fn specialize_trait(
889 &mut self,
890 diagnostics: &mut SemanticDiagnostics<'db>,
891 stable_ptr: SyntaxStablePtrId<'db>,
892 trait_id: TraitId<'db>,
893 generic_args: &[ast::GenericArg<'db>],
894 ) -> Maybe<ConcreteTraitId<'db>> {
895 let generic_params = self
897 .db
898 .trait_generic_params(trait_id)
899 .map_err(|_| diagnostics.report(stable_ptr, UnknownTrait))?;
900 let generic_args = self.resolve_generic_args(
901 diagnostics,
902 GenericSubstitution::default(),
903 generic_params,
904 generic_args,
905 stable_ptr,
906 )?;
907
908 Ok(ConcreteTraitLongId { trait_id, generic_args }.intern(self.db))
909 }
910
911 fn specialize_impl(
913 &mut self,
914 diagnostics: &mut SemanticDiagnostics<'db>,
915 stable_ptr: SyntaxStablePtrId<'db>,
916 impl_def_id: ImplDefId<'db>,
917 generic_args: &[ast::GenericArg<'db>],
918 ) -> Maybe<ConcreteImplId<'db>> {
919 let generic_params = self
921 .db
922 .impl_def_generic_params(impl_def_id)
923 .map_err(|_| diagnostics.report(stable_ptr, UnknownImpl))?;
924 let generic_args = self.resolve_generic_args(
925 diagnostics,
926 GenericSubstitution::default(),
927 generic_params,
928 generic_args,
929 stable_ptr,
930 )?;
931
932 Ok(ConcreteImplLongId { impl_def_id, generic_args }.intern(self.db))
933 }
934
935 fn specialize_variant(
937 &mut self,
938 diagnostics: &mut SemanticDiagnostics<'db>,
939 stable_ptr: SyntaxStablePtrId<'db>,
940 variant_id: VariantId<'db>,
941 generic_args: &[ast::GenericArg<'db>],
942 ) -> Maybe<ConcreteVariant<'db>> {
943 let concrete_enum_id = ConcreteEnumLongId {
944 enum_id: variant_id.enum_id(self.db),
945 generic_args: self.resolve_generic_args(
946 diagnostics,
947 GenericSubstitution::default(),
948 self.db.enum_generic_params(variant_id.enum_id(self.db))?,
949 generic_args,
950 stable_ptr,
951 )?,
952 }
953 .intern(self.db);
954 self.db.concrete_enum_variant(
955 concrete_enum_id,
956 &self.db.variant_semantic(variant_id.enum_id(self.db), variant_id)?,
957 )
958 }
959
960 pub fn specialize_function(
962 &mut self,
963 diagnostics: &mut SemanticDiagnostics<'db>,
964 stable_ptr: SyntaxStablePtrId<'db>,
965 generic_function: GenericFunctionId<'db>,
966 generic_args: &[ast::GenericArg<'db>],
967 ) -> Maybe<FunctionId<'db>> {
968 let generic_params = generic_function.generic_params(self.db)?;
970 let generic_args = self.resolve_generic_args(
971 diagnostics,
972 GenericSubstitution::default(),
973 generic_params,
974 generic_args,
975 stable_ptr,
976 )?;
977
978 Ok(FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }
979 .intern(self.db))
980 }
981
982 pub fn specialize_type(
984 &mut self,
985 diagnostics: &mut SemanticDiagnostics<'db>,
986 stable_ptr: SyntaxStablePtrId<'db>,
987 generic_type: GenericTypeId<'db>,
988 generic_args: &[ast::GenericArg<'db>],
989 ) -> Maybe<TypeId<'db>> {
990 let generic_params = self
991 .db
992 .generic_type_generic_params(generic_type)
993 .map_err(|_| diagnostics.report(stable_ptr, UnknownType))?;
994 let generic_args = self.resolve_generic_args(
995 diagnostics,
996 GenericSubstitution::default(),
997 generic_params,
998 generic_args,
999 stable_ptr,
1000 )?;
1001
1002 Ok(TypeLongId::Concrete(ConcreteTypeId::new(self.db, generic_type, generic_args))
1003 .intern(self.db))
1004 }
1005
1006 pub fn impl_lookup_context(&self) -> ImplLookupContextId<'db> {
1008 self.impl_lookup_context_ex(&MacroResolutionInfo::from_resolver(self))
1009 }
1010
1011 fn impl_lookup_context_ex(&self, info: &MacroResolutionInfo<'db>) -> ImplLookupContextId<'db> {
1014 let mut lookup_context = ImplLookupContext::new(
1015 self.active_module_id(info),
1016 self.generic_params.clone(),
1017 self.db,
1018 );
1019
1020 if let TraitOrImplContext::Impl(impl_def_id) = &self.trait_or_impl_ctx {
1021 let Ok(generic_params) = self.db.impl_def_generic_params(*impl_def_id) else {
1022 return lookup_context.intern(self.db);
1023 };
1024 let generic_args = generic_params_to_args(generic_params, self.db);
1025 let impl_id: ConcreteImplId<'_> =
1026 ConcreteImplLongId { impl_def_id: *impl_def_id, generic_args }.intern(self.db);
1027 lookup_context.insert_impl(ImplLongId::Concrete(impl_id).intern(self.db), self.db);
1028 }
1029 lookup_context.intern(self.db)
1030 }
1031
1032 pub fn resolve_generic_args(
1036 &mut self,
1037 diagnostics: &mut SemanticDiagnostics<'db>,
1038 mut substitution: GenericSubstitution<'db>,
1039 generic_params: &[GenericParam<'db>],
1040 generic_args_syntax: &[ast::GenericArg<'db>],
1041 stable_ptr: SyntaxStablePtrId<'db>,
1042 ) -> Maybe<Vec<GenericArgumentId<'db>>> {
1043 let mut resolved_args = vec![];
1044 let arg_syntax_per_param = self.get_arg_syntax_per_param(
1045 diagnostics,
1046 &generic_params.iter().map(|generic_param| generic_param.id()).collect_vec(),
1047 generic_args_syntax,
1048 )?;
1049
1050 for generic_param in generic_params {
1051 let generic_param = substitution.substitute(self.db, generic_param.clone())?;
1052 let generic_arg = self.resolve_generic_arg(
1053 &generic_param,
1054 arg_syntax_per_param
1055 .get(&generic_param.id())
1056 .filter(|expr| !matches!(expr, ast::Expr::Underscore(_))),
1057 stable_ptr,
1058 diagnostics,
1059 )?;
1060 resolved_args.push(generic_arg);
1061 substitution.insert(generic_param.id(), generic_arg);
1062 }
1063
1064 Ok(resolved_args)
1065 }
1066
1067 pub fn get_arg_syntax_per_param(
1069 &self,
1070 diagnostics: &mut SemanticDiagnostics<'db>,
1071 generic_params: &[GenericParamId<'db>],
1072 generic_args_syntax: &[ast::GenericArg<'db>],
1073 ) -> Maybe<UnorderedHashMap<GenericParamId<'db>, ast::Expr<'db>>> {
1074 let db = self.db;
1075 let mut arg_syntax_per_param =
1076 UnorderedHashMap::<GenericParamId<'_>, ast::Expr<'_>>::default();
1077 let mut last_named_arg_index = None;
1078 let generic_param_by_name = generic_params
1079 .iter()
1080 .enumerate()
1081 .filter_map(|(i, param)| Some((param.name(self.db)?, (i, param))))
1082 .collect::<UnorderedHashMap<_, _>>();
1083 for (idx, generic_arg_syntax) in generic_args_syntax.iter().enumerate() {
1084 match generic_arg_syntax {
1085 ast::GenericArg::Named(arg_syntax) => {
1086 let name = arg_syntax.name(db).text(db);
1087 let Some((index, generic_param_id)) = generic_param_by_name.get(&name) else {
1088 return Err(diagnostics
1089 .report(arg_syntax.stable_ptr(db), UnknownGenericParam(name)));
1090 };
1091 if let Some(prev_index) = last_named_arg_index
1092 && prev_index > index
1093 {
1094 return Err(diagnostics
1095 .report(arg_syntax.stable_ptr(db), GenericArgOutOfOrder(name)));
1096 }
1097 last_named_arg_index = Some(index);
1098 if arg_syntax_per_param
1099 .insert(**generic_param_id, arg_syntax.value(db))
1100 .is_some()
1101 {
1102 return Err(diagnostics
1103 .report(arg_syntax.stable_ptr(db), GenericArgDuplicate(name)));
1104 }
1105 }
1106 ast::GenericArg::Unnamed(arg_syntax) => {
1107 if last_named_arg_index.is_some() {
1108 return Err(diagnostics
1109 .report(arg_syntax.stable_ptr(db), PositionalGenericAfterNamed));
1110 }
1111 let generic_param = generic_params.get(idx).ok_or_else(|| {
1112 diagnostics.report(
1113 arg_syntax.stable_ptr(db),
1114 TooManyGenericArguments {
1115 expected: generic_params.len(),
1116 actual: generic_args_syntax.len(),
1117 },
1118 )
1119 })?;
1120 assert_eq!(
1121 arg_syntax_per_param.insert(*generic_param, arg_syntax.value(db)),
1122 None,
1123 "Unexpected duplication in ordered params."
1124 );
1125 }
1126 }
1127 }
1128 Ok(arg_syntax_per_param)
1129 }
1130
1131 fn resolve_generic_arg(
1135 &mut self,
1136 generic_param: &GenericParam<'db>,
1137 generic_arg_syntax_opt: Option<&ast::Expr<'db>>,
1138 stable_ptr: SyntaxStablePtrId<'db>,
1139 diagnostics: &mut SemanticDiagnostics<'db>,
1140 ) -> Result<GenericArgumentId<'db>, cairo_lang_diagnostics::DiagnosticAdded> {
1141 let Some(generic_arg_syntax) = generic_arg_syntax_opt else {
1142 let lookup_context = self.impl_lookup_context();
1143 let inference = &mut self.data.inference_data.inference(self.db);
1144 return inference
1145 .infer_generic_arg(generic_param, lookup_context, Some(stable_ptr))
1146 .map_err(|err_set| {
1147 inference.report_on_pending_error(err_set, diagnostics, stable_ptr)
1148 });
1149 };
1150 let db = self.db;
1151 Ok(match generic_param {
1152 GenericParam::Type(_) => {
1153 GenericArgumentId::Type(resolve_type(db, diagnostics, self, generic_arg_syntax))
1154 }
1155 GenericParam::Const(const_param) => {
1156 let mut ctx = ComputationContext::new_global(db, diagnostics, self);
1160 let value = compute_expr_semantic(&mut ctx, generic_arg_syntax);
1161 GenericArgumentId::Constant(resolve_const_expr_and_evaluate(
1162 db,
1163 &mut ctx,
1164 &value,
1165 generic_arg_syntax.stable_ptr(db).untyped(),
1166 const_param.ty,
1167 false,
1168 ))
1169 }
1170
1171 GenericParam::Impl(param) => {
1172 let expr_path = try_extract_matches!(generic_arg_syntax, ast::Expr::Path)
1173 .ok_or_else(|| {
1174 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1175 })?;
1176 let resolved_impl = match self.resolve_concrete_path(
1177 diagnostics,
1178 expr_path,
1179 NotFoundItemType::Impl,
1180 )? {
1181 ResolvedConcreteItem::Impl(resolved_impl) => resolved_impl,
1182 ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
1183 ImplLongId::SelfImpl(concrete_trait_id).intern(self.db)
1184 }
1185 _ => {
1186 return Err(
1187 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1188 );
1189 }
1190 };
1191 let impl_def_concrete_trait = self.db.impl_concrete_trait(resolved_impl)?;
1192 let expected_concrete_trait = param.concrete_trait?;
1193 if let Err(err_set) = self
1194 .inference()
1195 .conform_traits(impl_def_concrete_trait, expected_concrete_trait)
1196 {
1197 let diag_added = diagnostics.report(
1198 generic_arg_syntax.stable_ptr(db),
1199 TraitMismatch {
1200 expected_trt: expected_concrete_trait,
1201 actual_trt: impl_def_concrete_trait,
1202 },
1203 );
1204 self.inference().consume_reported_error(err_set, diag_added);
1205 } else {
1206 for (trait_ty, ty1) in param.type_constraints.iter() {
1207 let ty0 = TypeLongId::ImplType(ImplTypeId::new(
1208 resolved_impl,
1209 *trait_ty,
1210 self.db,
1211 ))
1212 .intern(self.db);
1213 let _ = self.inference().conform_ty(ty0, *ty1).map_err(|err_set| {
1214 self.inference().report_on_pending_error(
1215 err_set,
1216 diagnostics,
1217 stable_ptr,
1218 )
1219 });
1220 }
1221 }
1222 GenericArgumentId::Impl(resolved_impl)
1223 }
1224 GenericParam::NegImpl(_) => {
1225 return Err(
1226 diagnostics.report(generic_arg_syntax.stable_ptr(db), ArgPassedToNegativeImpl)
1227 );
1228 }
1229 })
1230 }
1231
1232 pub fn ignore_visibility_checks(&self, module_id: ModuleId<'db>) -> bool {
1235 self.ignore_visibility_checks_ex(module_id, &MacroResolutionInfo::from_resolver(self))
1236 }
1237
1238 fn ignore_visibility_checks_ex(
1241 &self,
1242 module_id: ModuleId<'db>,
1243 info: &MacroResolutionInfo<'db>,
1244 ) -> bool {
1245 let module_crate = module_id.owning_crate(self.db);
1246 let module_edition =
1247 self.db.crate_config(module_crate).map(|c| c.settings.edition).unwrap_or_default();
1248 module_edition.ignore_visibility()
1249 || self.active_settings(info).edition.ignore_visibility()
1250 && module_crate == self.db.core_crate()
1251 }
1252
1253 pub fn validate_feature_constraints<T: HasFeatureKind<'db>>(
1258 &self,
1259 diagnostics: &mut SemanticDiagnostics<'db>,
1260 identifier: &ast::TerminalIdentifier<'db>,
1261 item_info: &T,
1262 ) {
1263 let db = self.db;
1264 match item_info.feature_kind() {
1265 FeatureKind::Unstable { feature, note }
1266 if !self.data.feature_config.allowed_features.contains(feature) =>
1267 {
1268 diagnostics.report(
1269 identifier.stable_ptr(db),
1270 UnstableFeature { feature_name: *feature, note: *note },
1271 );
1272 }
1273 FeatureKind::Deprecated { feature, note }
1274 if !self
1275 .data
1276 .feature_config
1277 .allowed_lints
1278 .contains(&SmolStrId::from(self.db, DEPRECATED_ATTR))
1279 && !self.data.feature_config.allowed_features.contains(feature) =>
1280 {
1281 diagnostics.report(
1282 identifier.stable_ptr(db),
1283 DeprecatedFeature { feature_name: *feature, note: *note },
1284 );
1285 }
1286 FeatureKind::Internal { feature, note }
1287 if !self.data.feature_config.allowed_features.contains(feature) =>
1288 {
1289 diagnostics.report(
1290 identifier.stable_ptr(db),
1291 InternalFeature { feature_name: *feature, note: *note },
1292 );
1293 }
1294 _ => {}
1295 }
1296 }
1297
1298 pub fn is_item_visible(
1300 &self,
1301 containing_module_id: ModuleId<'db>,
1302 item_info: &ModuleItemInfo<'db>,
1303 user_module: ModuleId<'db>,
1304 ) -> bool {
1305 self.is_item_visible_ex(
1306 containing_module_id,
1307 item_info,
1308 user_module,
1309 &MacroResolutionInfo::from_resolver(self),
1310 )
1311 }
1312
1313 fn is_item_visible_ex(
1315 &self,
1316 mut containing_module_id: ModuleId<'db>, item_info: &ModuleItemInfo<'db>,
1318 user_module: ModuleId<'db>,
1319 info: &MacroResolutionInfo<'db>,
1320 ) -> bool {
1321 let db = self.db;
1322 if containing_module_id == user_module {
1323 return true;
1324 }
1325 while let ModuleId::MacroCall { id, .. } = containing_module_id {
1326 containing_module_id = id.parent_module(self.db);
1327 }
1328 self.ignore_visibility_checks_ex(containing_module_id, info)
1329 || visibility::peek_visible_in(
1330 db,
1331 item_info.visibility,
1332 containing_module_id,
1333 user_module,
1334 )
1335 }
1336
1337 pub fn insert_used_use(&mut self, item_id: ModuleItemId<'db>) {
1339 if let ModuleItemId::Use(use_id) = item_id {
1340 self.data.used_uses.insert(use_id);
1341 }
1342 }
1343
1344 fn handle_same_impl_trait(
1350 &mut self,
1351 diagnostics: &mut SemanticDiagnostics<'db>,
1352 specialized_item: &mut ResolvedConcreteItem<'db>,
1353 generic_args_syntax_slice: &[ast::GenericArg<'db>],
1354 segment_stable_ptr: SyntaxStablePtrId<'db>,
1355 ) {
1356 match *specialized_item {
1357 ResolvedConcreteItem::Trait(current_segment_concrete_trait) => {
1358 match self.trait_or_impl_ctx {
1359 TraitOrImplContext::None => {}
1360 TraitOrImplContext::Trait(ctx_trait) => {
1361 if self
1362 .warn_trait_in_same_trait(
1363 diagnostics,
1364 current_segment_concrete_trait.trait_id(self.db),
1365 generic_args_syntax_slice,
1366 ctx_trait,
1367 segment_stable_ptr,
1368 )
1369 .is_err()
1370 {
1371 *specialized_item =
1372 ResolvedConcreteItem::SelfTrait(current_segment_concrete_trait);
1373 }
1374 }
1375 TraitOrImplContext::Impl(ctx_impl_def_id) => {
1376 self.warn_trait_in_its_impl(
1377 diagnostics,
1378 current_segment_concrete_trait,
1379 ctx_impl_def_id,
1380 segment_stable_ptr,
1381 )
1382 .ok();
1383 }
1384 };
1385 }
1386 ResolvedConcreteItem::Impl(current_segment_impl_id) => {
1387 if let TraitOrImplContext::Impl(ctx_impl) = self.trait_or_impl_ctx {
1388 let current_segment_concrete_impl_id = extract_matches!(
1391 current_segment_impl_id.long(self.db),
1392 ImplLongId::Concrete
1393 );
1394 self.warn_impl_in_same_impl(
1395 diagnostics,
1396 current_segment_concrete_impl_id.impl_def_id(self.db),
1397 generic_args_syntax_slice,
1398 ctx_impl,
1399 segment_stable_ptr,
1400 )
1401 .ok();
1402 }
1403 }
1404 _ => {}
1405 };
1406 }
1407
1408 fn warn_impl_in_same_impl(
1411 &mut self,
1412 diagnostics: &mut SemanticDiagnostics<'db>,
1413 current_segment_impl_def_id: ImplDefId<'db>,
1414 current_segment_generic_args: &[ast::GenericArg<'db>],
1415 ctx_impl: ImplDefId<'db>,
1416 segment_stable_ptr: SyntaxStablePtrId<'db>,
1417 ) -> Maybe<()> {
1418 if current_segment_impl_def_id != ctx_impl {
1419 return Ok(());
1420 }
1421
1422 let generic_params = self.db.impl_def_generic_params(ctx_impl)?;
1423 self.compare_segment_args_to_params(
1424 diagnostics,
1425 current_segment_generic_args,
1426 generic_params,
1427 segment_stable_ptr,
1428 ImplInImplMustBeExplicit,
1429 ImplItemForbiddenInTheImpl,
1430 )
1431 }
1432
1433 fn warn_trait_in_its_impl(
1436 &mut self,
1437 diagnostics: &mut SemanticDiagnostics<'db>,
1438 current_segment_concrete_trait_id: ConcreteTraitId<'db>,
1439 impl_ctx: ImplDefId<'db>,
1440 segment_stable_ptr: SyntaxStablePtrId<'db>,
1441 ) -> Maybe<()> {
1442 let ctx_impl_trait = self.db.impl_def_trait(impl_ctx)?;
1443 if current_segment_concrete_trait_id.trait_id(self.db) != ctx_impl_trait {
1444 return Ok(());
1445 }
1446
1447 let ctx_impl_concrete_trait = self.db.impl_def_concrete_trait(impl_ctx)?;
1448 if ctx_impl_concrete_trait.generic_args(self.db)
1449 == current_segment_concrete_trait_id.generic_args(self.db)
1450 {
1451 return Err(diagnostics.report(segment_stable_ptr, TraitItemForbiddenInItsImpl));
1452 }
1453 Ok(())
1454 }
1455
1456 fn warn_trait_in_same_trait(
1459 &mut self,
1460 diagnostics: &mut SemanticDiagnostics<'db>,
1461 current_segment_trait_id: TraitId<'db>,
1462 current_segment_generic_args: &[ast::GenericArg<'db>],
1463 ctx_trait: TraitId<'db>,
1464 segment_stable_ptr: SyntaxStablePtrId<'db>,
1465 ) -> Maybe<()> {
1466 if current_segment_trait_id != ctx_trait {
1467 return Ok(());
1468 }
1469
1470 let generic_params = self.db.trait_generic_params(ctx_trait)?;
1471 self.compare_segment_args_to_params(
1472 diagnostics,
1473 current_segment_generic_args,
1474 generic_params,
1475 segment_stable_ptr,
1476 TraitInTraitMustBeExplicit,
1477 TraitItemForbiddenInTheTrait,
1478 )
1479 }
1480
1481 fn compare_segment_args_to_params(
1488 &mut self,
1489 diagnostics: &mut SemanticDiagnostics<'db>,
1490 current_segment_generic_args: &[ast::GenericArg<'db>],
1491 generic_params: &[GenericParam<'db>],
1492 segment_stable_ptr: SyntaxStablePtrId<'db>,
1493 must_be_explicit_error: SemanticDiagnosticKind<'db>,
1494 item_forbidden_in_itself_explicit_error: SemanticDiagnosticKind<'db>,
1495 ) -> Maybe<()> {
1496 if current_segment_generic_args.len() < generic_params.len() {
1499 return Err(diagnostics.report(segment_stable_ptr, must_be_explicit_error));
1500 }
1501 let resolved_args = self.resolve_generic_args(
1502 diagnostics,
1503 GenericSubstitution::default(),
1504 generic_params,
1505 current_segment_generic_args,
1506 segment_stable_ptr,
1507 )?;
1508
1509 if generic_params
1510 .iter()
1511 .zip_eq(resolved_args.iter())
1512 .all(|(gparam, garg)| gparam.as_arg(self.db) == *garg)
1513 {
1514 return Err(
1515 diagnostics.report(segment_stable_ptr, item_forbidden_in_itself_explicit_error)
1516 );
1517 }
1518 Ok(())
1519 }
1520
1521 fn specialize_generic_statement_arg(
1523 &mut self,
1524 diagnostics: &mut SemanticDiagnostics<'db>,
1525 segment: &ast::PathSegment<'db>,
1526 identifier: &ast::TerminalIdentifier<'db>,
1527 inner_generic_item: ResolvedGenericItem<'db>,
1528 generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
1529 ) -> ResolvedConcreteItem<'db> {
1530 let segment_stable_ptr = segment.stable_ptr(self.db).untyped();
1531 let mut specialized_item = self
1532 .specialize_generic_module_item(
1533 diagnostics,
1534 identifier,
1535 inner_generic_item,
1536 generic_args_syntax.clone(),
1537 )
1538 .unwrap();
1539 self.handle_same_impl_trait(
1540 diagnostics,
1541 &mut specialized_item,
1542 &generic_args_syntax.unwrap_or_default(),
1543 segment_stable_ptr,
1544 );
1545 specialized_item
1546 }
1547}
1548
1549fn handle_macro_context_modifier<'db>(
1562 db: &'db dyn Database,
1563 diagnostics: &mut SemanticDiagnostics<'db>,
1564 segments: &mut Peekable<std::vec::IntoIter<ast::PathSegment<'db>>>,
1565) -> Maybe<MacroContextModifier> {
1566 if segments.len() == 1 {
1567 return Err(diagnostics.report_after(
1568 segments.next().unwrap().stable_ptr(db),
1569 EmptyPathAfterResolverModifier,
1570 ));
1571 }
1572 match segments.peek() {
1573 Some(ast::PathSegment::Simple(path_segment_simple)) => {
1574 let ident = path_segment_simple.ident(db);
1575 let ident_text = ident.text(db);
1576 match ident_text.long(db).as_str() {
1577 MACRO_DEF_SITE | MACRO_CALL_SITE => {
1578 segments.next();
1579 if ident_text.long(db) == MACRO_DEF_SITE {
1580 Ok(MacroContextModifier::DefSite)
1581 } else {
1582 Ok(MacroContextModifier::CallSite)
1583 }
1584 }
1585 _ => Err(diagnostics.report(
1586 ident.stable_ptr(db),
1587 UnknownResolverModifier { modifier: ident_text },
1588 )),
1589 }
1590 }
1591 _ => {
1592 Err(skip_diagnostic())
1594 }
1595 }
1596}
1597
1598fn resolve_self_segment<'db>(
1601 db: &'db dyn Database,
1602 diagnostics: &mut SemanticDiagnostics<'db>,
1603 identifier: &ast::TerminalIdentifier<'db>,
1604 trait_or_impl_ctx: &TraitOrImplContext<'db>,
1605) -> Option<Maybe<ResolvedConcreteItem<'db>>> {
1606 require(identifier.text(db).long(db) == SELF_TYPE_KW)?;
1607 Some(resolve_actual_self_segment(db, diagnostics, identifier, trait_or_impl_ctx))
1608}
1609
1610fn resolve_actual_self_segment<'db>(
1612 db: &'db dyn Database,
1613 diagnostics: &mut SemanticDiagnostics<'db>,
1614 identifier: &ast::TerminalIdentifier<'db>,
1615 trait_or_impl_ctx: &TraitOrImplContext<'db>,
1616) -> Maybe<ResolvedConcreteItem<'db>> {
1617 match trait_or_impl_ctx {
1618 TraitOrImplContext::None => {
1619 Err(diagnostics.report(identifier.stable_ptr(db), SelfNotSupportedInContext))
1620 }
1621 TraitOrImplContext::Trait(trait_id) => {
1622 let generic_parameters = db.trait_generic_params(*trait_id)?;
1623 let concrete_trait_id = ConcreteTraitLongId {
1624 trait_id: *trait_id,
1625 generic_args: generic_params_to_args(generic_parameters, db),
1626 }
1627 .intern(db);
1628 Ok(ResolvedConcreteItem::SelfTrait(concrete_trait_id))
1629 }
1630 TraitOrImplContext::Impl(impl_def_id) => {
1631 let generic_parameters = db.impl_def_generic_params(*impl_def_id)?;
1632 let impl_id = ImplLongId::Concrete(
1633 ConcreteImplLongId {
1634 impl_def_id: *impl_def_id,
1635 generic_args: generic_params_to_args(generic_parameters, db),
1636 }
1637 .intern(db),
1638 );
1639 Ok(ResolvedConcreteItem::Impl(impl_id.intern(db)))
1640 }
1641 }
1642}
1643
1644enum ResolvedBase<'db> {
1646 Module(ModuleId<'db>),
1648 Crate(CrateId<'db>),
1650 StatementEnvironment(ResolvedGenericItem<'db>),
1652 FoundThroughGlobalUse { item_info: ModuleItemInfo<'db>, containing_module: ModuleId<'db> },
1654 Ambiguous(Vec<ModuleItemId<'db>>),
1656 ItemNotVisible(ModuleItemId<'db>, Vec<ModuleId<'db>>),
1658}
1659
1660struct ResolutionCallbacks<'db, 'a, ResolvedItem, First, Next, Validate, Mark>
1662where
1663 First: FnOnce(&mut Resolution<'db, 'a>) -> Maybe<ResolvedItem>,
1664 Next: FnMut(
1665 &mut Resolution<'db, 'a>,
1666 &ResolvedItem,
1667 &ast::PathSegment<'db>,
1668 ) -> Maybe<ResolvedItem>,
1669 Validate: FnMut(&mut SemanticDiagnostics<'db>, &ast::PathSegment<'db>) -> Maybe<()>,
1670 Mark: FnMut(
1671 &mut ResolvedItems<'db>,
1672 &'db dyn Database,
1673 &syntax::node::ast::PathSegment<'db>,
1674 ResolvedItem,
1675 ),
1676{
1677 _phantom: PhantomData<(ResolvedItem, &'db (), &'a ())>,
1679 first: First,
1681 next: Next,
1683 validate: Validate,
1686 mark: Mark,
1688}
1689
1690struct Resolution<'db, 'a> {
1692 resolver: &'a mut Resolver<'db>,
1694 diagnostics: &'a mut SemanticDiagnostics<'db>,
1696 segments: Peekable<std::vec::IntoIter<ast::PathSegment<'db>>>,
1698 expected_item_type: NotFoundItemType,
1700 resolution_context: ResolutionContext<'db, 'a>,
1702 macro_info: MacroResolutionInfo<'db>,
1704}
1705impl<'db, 'a> Resolution<'db, 'a> {
1706 fn new(
1710 resolver: &'a mut Resolver<'db>,
1711 diagnostics: &'a mut SemanticDiagnostics<'db>,
1712 path: impl AsSegments<'db>,
1713 item_type: NotFoundItemType,
1714 resolution_context: ResolutionContext<'db, 'a>,
1715 ) -> Maybe<Self> {
1716 let db = resolver.db;
1717 let placeholder_marker = path.placeholder_marker(db);
1718
1719 let mut cur_offset =
1720 ExpansionOffset::new(path.offset(db).expect("Trying to resolve an empty path."));
1721 let elements_vec = path.to_segments(db);
1722 let mut segments = elements_vec.into_iter().peekable();
1723 let mut cur_macro_call_data = resolver.macro_call_data.as_ref();
1724 let mut path_defining_module = resolver.data.module_id;
1725 while let Some(macro_call_data) = &cur_macro_call_data {
1728 let Some(new_offset) = cur_offset.mapped(¯o_call_data.expansion_mappings) else {
1729 break;
1730 };
1731 path_defining_module = macro_call_data.callsite_module_id;
1732 cur_macro_call_data = macro_call_data.parent_macro_call_data.as_ref();
1733 cur_offset = new_offset;
1734 }
1735 let macro_call_data = cur_macro_call_data.cloned();
1736
1737 let macro_context_modifier = if let Some(marker) = placeholder_marker {
1738 if macro_call_data.is_some() {
1739 handle_macro_context_modifier(db, diagnostics, &mut segments)?
1740 } else {
1741 return Err(diagnostics.report(marker.stable_ptr(db), DollarNotSupportedInContext));
1742 }
1743 } else {
1744 MacroContextModifier::None
1745 };
1746 let macro_info = MacroResolutionInfo {
1747 base: path_defining_module,
1748 data: macro_call_data,
1749 modifier: macro_context_modifier,
1750 };
1751 Ok(Resolution {
1752 resolver,
1753 diagnostics,
1754 segments,
1755 expected_item_type: item_type,
1756 resolution_context,
1757 macro_info,
1758 })
1759 }
1760
1761 fn full<ResolvedItem: Clone>(
1764 mut self,
1765 mut callbacks: ResolutionCallbacks<
1766 'db,
1767 'a,
1768 ResolvedItem,
1769 impl FnOnce(&mut Resolution<'db, 'a>) -> Maybe<ResolvedItem>,
1770 impl FnMut(
1771 &mut Resolution<'db, 'a>,
1772 &ResolvedItem,
1773 &ast::PathSegment<'db>,
1774 ) -> Maybe<ResolvedItem>,
1775 impl FnMut(&mut SemanticDiagnostics<'db>, &ast::PathSegment<'db>) -> Maybe<()>,
1776 impl FnMut(
1777 &mut ResolvedItems<'db>,
1778 &'db dyn Database,
1779 &syntax::node::ast::PathSegment<'db>,
1780 ResolvedItem,
1781 ),
1782 >,
1783 ) -> Maybe<ResolvedItem>
1784 where
1785 'db: 'a,
1786 {
1787 let mut item: ResolvedItem = (callbacks.first)(&mut self)?;
1789
1790 while let Some(segment) = self.segments.next() {
1792 (callbacks.validate)(self.diagnostics, &segment)?;
1793 item = (callbacks.next)(&mut self, &item, &segment)?;
1796 let db = self.resolver.db;
1797 (callbacks.mark)(&mut self.resolver.resolved_items, db, &segment, item.clone());
1798 }
1799 Ok(item)
1800 }
1801
1802 fn specialize_generic_inner_item(
1804 &mut self,
1805 module_id: ModuleId<'db>,
1806 segment: &ast::PathSegment<'db>,
1807 identifier: &TerminalIdentifier<'db>,
1808 inner_item_info: ModuleItemInfo<'db>,
1809 ) -> Maybe<ResolvedConcreteItem<'db>> {
1810 let db = self.resolver.db;
1811 let generic_args_syntax = segment.generic_args(db);
1812 let segment_stable_ptr = segment.stable_ptr(db).untyped();
1813 self.validate_module_item_usability(module_id, identifier, &inner_item_info);
1814 self.resolver.insert_used_use(inner_item_info.item_id);
1815 let inner_generic_item =
1816 ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)?;
1817 let mut specialized_item = self.resolver.specialize_generic_module_item(
1818 self.diagnostics,
1819 identifier,
1820 inner_generic_item.clone(),
1821 generic_args_syntax.clone(),
1822 )?;
1823 self.resolver
1824 .data
1825 .resolved_items
1826 .generic
1827 .insert(identifier.stable_ptr(db), inner_generic_item);
1828 self.resolver.handle_same_impl_trait(
1829 self.diagnostics,
1830 &mut specialized_item,
1831 &generic_args_syntax.unwrap_or_default(),
1832 segment_stable_ptr,
1833 );
1834 Ok(specialized_item)
1835 }
1836
1837 fn first_concrete(&mut self) -> Maybe<ResolvedConcreteItem<'db>> {
1839 if let Some(base_module) =
1840 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
1841 resolved_items.mark_concrete(db, segment, ResolvedConcreteItem::Module(module_id));
1842 })
1843 {
1844 return Ok(ResolvedConcreteItem::Module(base_module?));
1845 }
1846
1847 let db = self.resolver.db;
1848 Ok(match self.segments.peek().unwrap() {
1849 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
1850 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
1851 let identifier = generic_segment.ident(db);
1852 match self.determine_base(&identifier)? {
1854 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1855 ResolvedBase::Crate(_) => {
1856 return Err(self
1858 .diagnostics
1859 .report(generics_stable_ptr, UnexpectedGenericArgs));
1860 }
1861 ResolvedBase::StatementEnvironment(generic_item) => {
1862 let segment = self.segments.next().unwrap();
1863 let concrete_item = self.resolver.specialize_generic_statement_arg(
1864 self.diagnostics,
1865 &segment,
1866 &identifier,
1867 generic_item,
1868 segment.generic_args(db),
1869 );
1870 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1871 }
1872 ResolvedBase::FoundThroughGlobalUse {
1873 item_info: inner_module_item,
1874 containing_module: module_id,
1875 } => {
1876 let segment = self.segments.next().unwrap();
1877
1878 let concrete_item = self.specialize_generic_inner_item(
1879 module_id,
1880 &segment,
1881 &identifier,
1882 inner_module_item,
1883 )?;
1884 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1885 }
1886 ResolvedBase::Ambiguous(module_items) => {
1887 return Err(self
1888 .diagnostics
1889 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1890 }
1891 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1892 return Err(self.diagnostics.report(
1893 identifier.stable_ptr(db),
1894 ItemNotVisible(module_item_id, containing_modules),
1895 ));
1896 }
1897 }
1898 }
1899 syntax::node::ast::PathSegment::Simple(simple_segment) => {
1900 let identifier = simple_segment.ident(db);
1901
1902 if let Some(resolved_item) = resolve_self_segment(
1903 db,
1904 self.diagnostics,
1905 &identifier,
1906 &self.resolver.data.trait_or_impl_ctx,
1907 ) {
1908 return Ok(self.resolver.resolved_items.mark_concrete(
1910 db,
1911 &self.segments.next().unwrap(),
1912 resolved_item?,
1913 ));
1914 }
1915
1916 if let Some(local_item) =
1917 self.resolver.determine_base_item_in_local_scope(&identifier)
1918 {
1919 self.resolver.resolved_items.mark_concrete(
1920 db,
1921 &self.segments.next().unwrap(),
1922 local_item,
1923 )
1924 } else {
1925 match self.determine_base(&identifier)? {
1926 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1928 ResolvedBase::Crate(crate_id) => {
1929 self.resolver.resolved_items.mark_concrete(
1930 db,
1931 &self.segments.next().unwrap(),
1932 ResolvedConcreteItem::Module(ModuleId::CrateRoot(crate_id)),
1933 )
1934 }
1935 ResolvedBase::StatementEnvironment(generic_item) => {
1936 let segment = self.segments.next().unwrap();
1937
1938 let concrete_item = self.resolver.specialize_generic_statement_arg(
1939 self.diagnostics,
1940 &segment,
1941 &identifier,
1942 generic_item,
1943 segment.generic_args(db),
1944 );
1945 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1946 }
1947 ResolvedBase::FoundThroughGlobalUse {
1948 item_info: inner_module_item,
1949 containing_module: module_id,
1950 } => {
1951 let segment = self.segments.next().unwrap();
1952 let concrete_item = self.specialize_generic_inner_item(
1953 module_id,
1954 &segment,
1955 &identifier,
1956 inner_module_item,
1957 )?;
1958 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1959 }
1960 ResolvedBase::Ambiguous(module_items) => {
1961 return Err(self
1962 .diagnostics
1963 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1964 }
1965 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1966 return Err(self.diagnostics.report(
1967 identifier.stable_ptr(db),
1968 ItemNotVisible(module_item_id, containing_modules),
1969 ));
1970 }
1971 }
1972 }
1973 }
1974 syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
1976 })
1977 }
1978 fn first_generic(&mut self, allow_generic_args: bool) -> Maybe<ResolvedGenericItem<'db>> {
1981 if let Some(base_module) =
1982 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
1983 resolved_items.mark_generic(db, segment, ResolvedGenericItem::Module(module_id));
1984 })
1985 {
1986 return Ok(ResolvedGenericItem::Module(base_module?));
1987 }
1988 let db = self.resolver.db;
1989 Ok(match self.segments.peek().unwrap() {
1990 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
1991 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
1992 if !allow_generic_args {
1993 return Err(self
1994 .diagnostics
1995 .report(generics_stable_ptr, UnexpectedGenericArgs));
1996 }
1997 let identifier = generic_segment.ident(db);
1998 match self.determine_base(&identifier)? {
1999 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2000 ResolvedBase::Crate(_) => {
2001 return Err(self
2003 .diagnostics
2004 .report(generics_stable_ptr, UnexpectedGenericArgs));
2005 }
2006 ResolvedBase::StatementEnvironment(generic_item) => generic_item,
2007 ResolvedBase::FoundThroughGlobalUse {
2008 item_info: inner_module_item, ..
2009 } => {
2010 self.resolver.insert_used_use(inner_module_item.item_id);
2011 let generic_item =
2012 ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2013 self.resolver.resolved_items.mark_generic(
2014 db,
2015 &self.segments.next().unwrap(),
2016 generic_item,
2017 )
2018 }
2019 ResolvedBase::Ambiguous(module_items) => {
2020 return Err(self
2021 .diagnostics
2022 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2023 }
2024 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2025 return Err(self.diagnostics.report(
2026 identifier.stable_ptr(db),
2027 ItemNotVisible(module_item_id, containing_modules),
2028 ));
2029 }
2030 }
2031 }
2032 syntax::node::ast::PathSegment::Simple(simple_segment) => {
2033 let identifier = simple_segment.ident(db);
2034 match self.determine_base(&identifier)? {
2035 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2037 ResolvedBase::Crate(crate_id) => self.resolver.resolved_items.mark_generic(
2038 db,
2039 &self.segments.next().unwrap(),
2040 ResolvedGenericItem::Module(ModuleId::CrateRoot(crate_id)),
2041 ),
2042 ResolvedBase::StatementEnvironment(generic_item) => self
2043 .resolver
2044 .resolved_items
2045 .mark_generic(db, &self.segments.next().unwrap(), generic_item),
2046 ResolvedBase::FoundThroughGlobalUse {
2047 item_info: inner_module_item, ..
2048 } => {
2049 self.resolver.insert_used_use(inner_module_item.item_id);
2050 let generic_item =
2051 ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2052 self.resolver.resolved_items.mark_generic(
2053 db,
2054 &self.segments.next().unwrap(),
2055 generic_item,
2056 )
2057 }
2058 ResolvedBase::Ambiguous(module_items) => {
2059 return Err(self
2060 .diagnostics
2061 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2062 }
2063 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2064 return Err(self.diagnostics.report(
2065 identifier.stable_ptr(db),
2066 ItemNotVisible(module_item_id, containing_modules),
2067 ));
2068 }
2069 }
2070 }
2071 syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
2073 })
2074 }
2075
2076 fn try_handle_super_segments(
2080 &mut self,
2081 mut mark: impl FnMut(
2082 &mut ResolvedItems<'db>,
2083 &'db dyn Database,
2084 &syntax::node::ast::PathSegment<'db>,
2085 ModuleId<'db>,
2086 ),
2087 ) -> Option<Maybe<ModuleId<'db>>> {
2088 let db = self.resolver.db;
2089 let mut curr = None;
2090 for segment in self.segments.peeking_take_while(|segment| match segment {
2091 ast::PathSegment::WithGenericArgs(_) | ast::PathSegment::Missing(_) => false,
2092 ast::PathSegment::Simple(simple) => simple.identifier(db).long(db) == SUPER_KW,
2093 }) {
2094 let module_id = match curr {
2095 Some(module_id) => module_id,
2096 None => {
2097 if let Some(module_id) =
2098 self.resolver.try_get_active_module_id(&self.macro_info)
2099 {
2100 module_id
2101 } else {
2102 return Some(Err(self
2103 .diagnostics
2104 .report(segment.stable_ptr(db), SuperUsedInMacroCallTopLevel)));
2105 }
2106 }
2107 };
2108 match module_id {
2109 ModuleId::CrateRoot(_) => {
2110 return Some(Err(self
2111 .diagnostics
2112 .report(segment.stable_ptr(db), SuperUsedInRootModule)));
2113 }
2114 ModuleId::Submodule(submodule_id) => {
2115 let parent = submodule_id.parent_module(db);
2116 mark(&mut self.resolver.resolved_items, db, &segment, parent);
2117 curr = Some(parent);
2118 }
2119 ModuleId::MacroCall { .. } => {
2120 return Some(Err(self
2121 .diagnostics
2122 .report(segment.stable_ptr(db), SuperUsedInMacroCallTopLevel)));
2123 }
2124 }
2125 }
2126 curr.map(Ok)
2127 }
2128
2129 fn module_inner_item(
2131 &mut self,
2132 module_id: &ModuleId<'db>,
2133 ident: SmolStrId<'db>,
2134 identifier: &TerminalIdentifier<'db>,
2135 ) -> Maybe<ModuleItemInfo<'db>> {
2136 let db = self.resolver.db;
2137 if let Some(info) =
2138 self.resolver.resolve_item_in_module_or_expanded_macro(*module_id, ident)
2139 {
2140 return Ok(info);
2141 }
2142 match self.resolver.resolve_path_using_use_star(*module_id, ident) {
2143 UseStarResult::UniquePathFound(item_info) => Ok(item_info),
2144 UseStarResult::AmbiguousPath(module_items) => {
2145 Err(self.diagnostics.report(identifier.stable_ptr(db), AmbiguousPath(module_items)))
2146 }
2147 UseStarResult::PathNotFound => {
2148 let item_type = if self.segments.len() == 0 {
2149 self.expected_item_type
2150 } else {
2151 NotFoundItemType::Identifier
2152 };
2153 Err(self.diagnostics.report(identifier.stable_ptr(db), PathNotFound(item_type)))
2154 }
2155 UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
2156 Err(self.diagnostics.report(
2157 identifier.stable_ptr(db),
2158 ItemNotVisible(module_item_id, containing_modules),
2159 ))
2160 }
2161 }
2162 }
2163
2164 fn next_concrete(
2166 &mut self,
2167 containing_item: &ResolvedConcreteItem<'db>,
2168 segment: &ast::PathSegment<'db>,
2169 ) -> Maybe<ResolvedConcreteItem<'db>> {
2170 let db = self.resolver.db;
2171 let identifier = &segment.identifier_ast(db);
2172 let generic_args_syntax = segment.generic_args(db);
2173
2174 let ident = identifier.text(db);
2175
2176 if identifier.text(db).long(db) == SELF_TYPE_KW {
2177 return Err(self.diagnostics.report(identifier.stable_ptr(db), SelfMustBeFirst));
2178 }
2179
2180 match containing_item {
2181 ResolvedConcreteItem::Module(module_id) => {
2182 if ident.long(db) == SUPER_KW {
2185 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2186 }
2187 let inner_item_info = self.module_inner_item(module_id, ident, identifier)?;
2188
2189 self.specialize_generic_inner_item(*module_id, segment, identifier, inner_item_info)
2190 }
2191 ResolvedConcreteItem::Type(ty) => {
2192 if let TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_enum_id)) = ty.long(db) {
2193 let enum_id = concrete_enum_id.enum_id(db);
2194 let variants = db.enum_variants(enum_id).map_err(|_| {
2195 self.diagnostics.report(identifier.stable_ptr(db), UnknownEnum)
2196 })?;
2197 let variant_id = variants.get(&ident).ok_or_else(|| {
2198 self.diagnostics.report(
2199 identifier.stable_ptr(db),
2200 NoSuchVariant { enum_id, variant_name: ident },
2201 )
2202 })?;
2203 let variant = db.variant_semantic(enum_id, *variant_id)?;
2204 let concrete_variant = db.concrete_enum_variant(*concrete_enum_id, &variant)?;
2205 Ok(ResolvedConcreteItem::Variant(concrete_variant))
2206 } else {
2207 Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath))
2208 }
2209 }
2210 ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
2211 let impl_id = ImplLongId::SelfImpl(*concrete_trait_id).intern(db);
2212 let Some(trait_item_id) =
2213 db.trait_item_by_name(concrete_trait_id.trait_id(db), ident)?
2214 else {
2215 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2216 };
2217 if let Ok(Some(trait_item_info)) =
2218 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2219 {
2220 self.resolver.validate_feature_constraints(
2221 self.diagnostics,
2222 identifier,
2223 &trait_item_info,
2224 );
2225 }
2226 Ok(match trait_item_id {
2227 TraitItemId::Function(trait_function_id) => {
2228 ResolvedConcreteItem::Function(self.resolver.specialize_function(
2229 self.diagnostics,
2230 identifier.stable_ptr(db).untyped(),
2231 GenericFunctionId::Impl(ImplGenericFunctionId {
2232 impl_id,
2233 function: trait_function_id,
2234 }),
2235 &generic_args_syntax.unwrap_or_default(),
2236 )?)
2237 }
2238 TraitItemId::Type(trait_type_id) => ResolvedConcreteItem::Type(
2239 TypeLongId::ImplType(ImplTypeId::new(impl_id, trait_type_id, db))
2240 .intern(db),
2241 ),
2242 TraitItemId::Constant(trait_constant_id) => ResolvedConcreteItem::Constant(
2243 ConstValue::ImplConstant(ImplConstantId::new(
2244 impl_id,
2245 trait_constant_id,
2246 db,
2247 ))
2248 .intern(db),
2249 ),
2250 TraitItemId::Impl(trait_impl_id) => ResolvedConcreteItem::Impl(
2251 ImplLongId::ImplImpl(ImplImplId::new(impl_id, trait_impl_id, db))
2252 .intern(db),
2253 ),
2254 })
2255 }
2256 ResolvedConcreteItem::Trait(concrete_trait_id) => {
2257 let Some(trait_item_id) =
2258 db.trait_item_by_name(concrete_trait_id.trait_id(db), ident)?
2259 else {
2260 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2261 };
2262
2263 if let Ok(Some(trait_item_info)) =
2264 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2265 {
2266 self.resolver.validate_feature_constraints(
2267 self.diagnostics,
2268 identifier,
2269 &trait_item_info,
2270 );
2271 }
2272
2273 match trait_item_id {
2274 TraitItemId::Function(trait_function_id) => {
2275 let concrete_trait_function = ConcreteTraitGenericFunctionLongId::new(
2276 db,
2277 *concrete_trait_id,
2278 trait_function_id,
2279 )
2280 .intern(db);
2281 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2282 let impl_lookup_context =
2283 self.resolver.impl_lookup_context_ex(&self.macro_info);
2284 let generic_function = GenericFunctionId::Impl(
2285 self.resolver.inference().infer_trait_generic_function(
2286 concrete_trait_function,
2287 impl_lookup_context,
2288 Some(identifier_stable_ptr),
2289 ),
2290 );
2291
2292 Ok(ResolvedConcreteItem::Function(self.resolver.specialize_function(
2293 self.diagnostics,
2294 identifier_stable_ptr,
2295 generic_function,
2296 &generic_args_syntax.unwrap_or_default(),
2297 )?))
2298 }
2299 TraitItemId::Type(trait_type_id) => {
2300 let concrete_trait_type = ConcreteTraitTypeId::new_from_data(
2301 db,
2302 *concrete_trait_id,
2303 trait_type_id,
2304 );
2305
2306 let impl_lookup_context =
2307 self.resolver.impl_lookup_context_ex(&self.macro_info);
2308 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2309 let ty = self.resolver.inference().infer_trait_type(
2310 concrete_trait_type,
2311 impl_lookup_context,
2312 Some(identifier_stable_ptr),
2313 );
2314 Ok(ResolvedConcreteItem::Type(
2315 self.resolver.inference().rewrite(ty).no_err(),
2316 ))
2317 }
2318 TraitItemId::Constant(trait_constant_id) => {
2319 let concrete_trait_constant = ConcreteTraitConstantLongId::new(
2320 db,
2321 *concrete_trait_id,
2322 trait_constant_id,
2323 )
2324 .intern(db);
2325
2326 let impl_lookup_context =
2327 self.resolver.impl_lookup_context_ex(&self.macro_info);
2328 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2329 let imp_constant_id = self.resolver.inference().infer_trait_constant(
2330 concrete_trait_constant,
2331 impl_lookup_context,
2332 Some(identifier_stable_ptr),
2333 );
2334 self.resolver.inference().solve().ok();
2338
2339 Ok(ResolvedConcreteItem::Constant(
2340 ConstValue::ImplConstant(imp_constant_id).intern(db),
2341 ))
2342 }
2343 TraitItemId::Impl(trait_impl_id) => {
2344 let concrete_trait_impl = ConcreteTraitImplLongId::new_from_data(
2345 db,
2346 *concrete_trait_id,
2347 trait_impl_id,
2348 )
2349 .intern(db);
2350
2351 let impl_lookup_context =
2352 self.resolver.impl_lookup_context_ex(&self.macro_info);
2353 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2354 let impl_impl_id = self.resolver.inference().infer_trait_impl(
2355 concrete_trait_impl,
2356 impl_lookup_context,
2357 Some(identifier_stable_ptr),
2358 );
2359 self.resolver.inference().solve().ok();
2363
2364 Ok(ResolvedConcreteItem::Impl(
2365 ImplLongId::ImplImpl(impl_impl_id).intern(db),
2366 ))
2367 }
2368 }
2369 }
2370 ResolvedConcreteItem::Impl(impl_id) => {
2371 let concrete_trait_id = db.impl_concrete_trait(*impl_id)?;
2372 let trait_id = concrete_trait_id.trait_id(db);
2373 let Some(trait_item_id) = db.trait_item_by_name(trait_id, ident)? else {
2374 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2375 };
2376 if let Ok(Some(trait_item_info)) =
2377 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2378 {
2379 self.resolver.validate_feature_constraints(
2380 self.diagnostics,
2381 identifier,
2382 &trait_item_info,
2383 );
2384 }
2385 if let ImplLongId::Concrete(concrete_impl) = impl_id.long(db) {
2386 let impl_def_id: ImplDefId<'_> = concrete_impl.impl_def_id(db);
2387
2388 if let Ok(Some(impl_item_info)) = db.impl_item_info_by_name(impl_def_id, ident)
2389 {
2390 self.resolver.validate_feature_constraints(
2391 self.diagnostics,
2392 identifier,
2393 &impl_item_info,
2394 );
2395 }
2396 }
2397
2398 match trait_item_id {
2399 TraitItemId::Function(trait_function_id) => {
2400 let generic_function_id = GenericFunctionId::Impl(ImplGenericFunctionId {
2401 impl_id: *impl_id,
2402 function: trait_function_id,
2403 });
2404
2405 Ok(ResolvedConcreteItem::Function(self.resolver.specialize_function(
2406 self.diagnostics,
2407 identifier.stable_ptr(db).untyped(),
2408 generic_function_id,
2409 &generic_args_syntax.unwrap_or_default(),
2410 )?))
2411 }
2412 TraitItemId::Type(trait_type_id) => {
2413 let impl_type_id = ImplTypeId::new(*impl_id, trait_type_id, db);
2414 let ty = self
2415 .resolver
2416 .inference()
2417 .reduce_impl_ty(impl_type_id)
2418 .unwrap_or_else(|_| TypeLongId::ImplType(impl_type_id).intern(db));
2419 Ok(ResolvedConcreteItem::Type(ty))
2420 }
2421 TraitItemId::Constant(trait_constant_id) => {
2422 let impl_constant_id = ImplConstantId::new(*impl_id, trait_constant_id, db);
2423
2424 let constant = self
2425 .resolver
2426 .inference()
2427 .reduce_impl_constant(impl_constant_id)
2428 .unwrap_or_else(|_| {
2429 ConstValue::ImplConstant(impl_constant_id).intern(db)
2430 });
2431
2432 Ok(ResolvedConcreteItem::Constant(constant))
2433 }
2434 TraitItemId::Impl(trait_impl_id) => {
2435 let impl_impl_id = ImplImplId::new(*impl_id, trait_impl_id, db);
2436 let imp = self
2437 .resolver
2438 .inference()
2439 .reduce_impl_impl(impl_impl_id)
2440 .unwrap_or_else(|_| ImplLongId::ImplImpl(impl_impl_id).intern(db));
2441
2442 Ok(ResolvedConcreteItem::Impl(imp))
2443 }
2444 }
2445 }
2446 ResolvedConcreteItem::Function(function_id) if ident.long(db) == "Coupon" => {
2447 if !are_coupons_enabled(db, self.resolver.active_module_id(&self.macro_info)) {
2448 self.diagnostics.report(identifier.stable_ptr(db), CouponsDisabled);
2449 }
2450 if matches!(
2451 function_id.get_concrete(db).generic_function,
2452 GenericFunctionId::Extern(_)
2453 ) {
2454 return Err(self
2455 .diagnostics
2456 .report(identifier.stable_ptr(db), CouponForExternFunctionNotAllowed));
2457 }
2458 Ok(ResolvedConcreteItem::Type(TypeLongId::Coupon(*function_id).intern(db)))
2459 }
2460 _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2461 }
2462 }
2463
2464 fn next_generic(
2466 &mut self,
2467 containing_item: &ResolvedGenericItem<'db>,
2468 segment: &ast::PathSegment<'db>,
2469 ) -> Maybe<ResolvedGenericItem<'db>> {
2470 let db = self.resolver.db;
2471 let identifier = segment.identifier_ast(db);
2472 let ident = identifier.text(db);
2473 match containing_item {
2474 ResolvedGenericItem::Module(module_id) => {
2475 let inner_item_info = self.module_inner_item(module_id, ident, &identifier)?;
2476
2477 self.validate_module_item_usability(*module_id, &identifier, &inner_item_info);
2478 self.resolver.insert_used_use(inner_item_info.item_id);
2479 ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)
2480 }
2481 ResolvedGenericItem::GenericType(GenericTypeId::Enum(enum_id)) => {
2482 let variants = db.enum_variants(*enum_id)?;
2483 let variant_id = variants.get(&ident).ok_or_else(|| {
2484 self.diagnostics.report(
2485 identifier.stable_ptr(db),
2486 NoSuchVariant { enum_id: *enum_id, variant_name: ident },
2487 )
2488 })?;
2489 let variant = db.variant_semantic(*enum_id, *variant_id)?;
2490 Ok(ResolvedGenericItem::Variant(variant))
2491 }
2492 _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2493 }
2494 }
2495
2496 fn determine_base(
2499 &mut self,
2500 identifier: &ast::TerminalIdentifier<'db>,
2501 ) -> Maybe<ResolvedBase<'db>> {
2502 let db = self.resolver.db;
2503 let ident = identifier.text(db);
2504 if let ResolutionContext::Statement(ref mut env) = self.resolution_context
2505 && let Some(item) = get_statement_item_by_name(env, ident)
2506 {
2507 return Ok(ResolvedBase::StatementEnvironment(item));
2508 }
2509
2510 let Some(module_id) = self.resolver.try_get_active_module_id(&self.macro_info) else {
2511 let item_type = if self.segments.len() == 1 {
2512 self.expected_item_type
2513 } else {
2514 NotFoundItemType::Identifier
2515 };
2516 return Err(self
2517 .diagnostics
2518 .report(identifier.stable_ptr(db), PathNotFound(item_type)));
2519 };
2520 if let Some(info) = self.resolver.resolve_item_in_module_or_expanded_macro(module_id, ident)
2522 && !matches!(self.resolution_context, ResolutionContext::ModuleItem(id) if id == info.item_id)
2523 {
2524 return Ok(ResolvedBase::Module(module_id));
2525 }
2526
2527 if ident.long(db) == CRATE_KW {
2529 return Ok(ResolvedBase::Crate(self.resolver.active_owning_crate_id(&self.macro_info)));
2530 }
2531 if let Some(dep) = self
2534 .resolver
2535 .active_settings(&self.macro_info)
2536 .dependencies
2537 .get(ident.long(db).as_str())
2538 {
2539 let dep_crate_id =
2540 CrateLongId::Real { name: ident, discriminator: dep.discriminator.clone() }
2541 .intern(db);
2542 let configs = db.crate_configs();
2543 if !configs.contains_key(&dep_crate_id) {
2544 let get_long_id = |crate_id: CrateId<'db>| crate_id.long(db);
2545 panic!(
2546 "Invalid crate dependency: {:?}\nconfigured crates: {:#?}",
2547 get_long_id(dep_crate_id),
2548 configs.keys().cloned().map(get_long_id).collect_vec()
2549 );
2550 }
2551
2552 return Ok(ResolvedBase::Crate(dep_crate_id));
2553 }
2554 if ident.long(db) == CORELIB_CRATE_NAME {
2556 return Ok(ResolvedBase::Crate(CrateId::core(db)));
2557 }
2558 if ident.long(db) == STARKNET_CRATE_NAME {
2560 return Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)));
2562 }
2563 match self.resolver.resolve_path_using_use_star(module_id, ident) {
2565 UseStarResult::UniquePathFound(inner_module_item) => {
2566 return Ok(ResolvedBase::FoundThroughGlobalUse {
2567 item_info: inner_module_item,
2568 containing_module: module_id,
2569 });
2570 }
2571 UseStarResult::AmbiguousPath(module_items) => {
2572 return Ok(ResolvedBase::Ambiguous(module_items));
2573 }
2574 UseStarResult::PathNotFound => {}
2575 UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
2576 let prelude = self.resolver.prelude_submodule_ex(&self.macro_info);
2577 if let Ok(Some(_)) = db.module_item_by_name(prelude, ident) {
2578 return Ok(ResolvedBase::Module(prelude));
2579 }
2580 return Ok(ResolvedBase::ItemNotVisible(module_item_id, containing_modules));
2581 }
2582 }
2583 Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)))
2584 }
2585 fn validate_module_item_usability(
2588 &mut self,
2589 containing_module_id: ModuleId<'db>,
2590 identifier: &ast::TerminalIdentifier<'db>,
2591 item_info: &ModuleItemInfo<'db>,
2592 ) {
2593 if !self.resolver.is_item_visible_ex(
2594 containing_module_id,
2595 item_info,
2596 self.resolver.active_module_id(&self.macro_info),
2597 &self.macro_info,
2598 ) {
2599 self.diagnostics.report(
2600 identifier.stable_ptr(self.resolver.db),
2601 ItemNotVisible(item_info.item_id, vec![]),
2602 );
2603 }
2604
2605 self.resolver.validate_feature_constraints(self.diagnostics, identifier, item_info);
2606 }
2607}