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