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_kind(self.db).unwrap() != SyntaxKind::UsePathList {
575 diagnostics.report(use_path.stable_ptr(self.db), UseSelfNonMulti);
576 }
577 segments.segments.pop();
578 }
579 if segments.segments.is_empty() {
580 return Err(diagnostics.report(use_path.stable_ptr(self.db), UseSelfEmptyPath));
581 }
582 self.resolve_generic_path(diagnostics, segments, NotFoundItemType::Identifier, ctx)
583 }
584
585 pub fn resolve_generic_path_with_args(
588 &mut self,
589 diagnostics: &mut SemanticDiagnostics<'db>,
590 path: impl AsSegments<'db>,
591 item_type: NotFoundItemType,
592 ctx: ResolutionContext<'db, '_>,
593 ) -> Maybe<ResolvedGenericItem<'db>> {
594 self.resolve_generic_path_inner(diagnostics, path, item_type, true, ctx)
595 }
596
597 fn resolve_generic_path_inner(
602 &mut self,
603 diagnostics: &mut SemanticDiagnostics<'db>,
604 path: impl AsSegments<'db>,
605 item_type: NotFoundItemType,
606 allow_generic_args: bool,
607 ctx: ResolutionContext<'db, '_>,
608 ) -> Maybe<ResolvedGenericItem<'db>> {
609 let validate = |diagnostics: &mut SemanticDiagnostics<'db>,
610 segment: &ast::PathSegment<'db>| {
611 match segment {
612 ast::PathSegment::WithGenericArgs(generic_args) if !allow_generic_args => {
613 Err(diagnostics.report(generic_args.stable_ptr(self.db), UnexpectedGenericArgs))
614 }
615 _ => Ok(()),
616 }
617 };
618 Resolution::new(self, diagnostics, path, item_type, ctx)?.full::<ResolvedGenericItem<'_>>(
619 ResolutionCallbacks {
620 _phantom: PhantomData,
621 first: |resolution| resolution.first_generic(allow_generic_args),
622 next: |resolution, item, segment| resolution.next_generic(item, segment),
623 validate,
624 mark: |resolved_items, db, segment, item| {
625 resolved_items.mark_generic(db, segment, item);
626 },
627 },
628 )
629 }
630
631 fn specialize_generic_module_item(
633 &mut self,
634 diagnostics: &mut SemanticDiagnostics<'db>,
635 identifier: &syntax::node::ast::TerminalIdentifier<'db>,
636 generic_item: ResolvedGenericItem<'db>,
637 generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
638 ) -> Maybe<ResolvedConcreteItem<'db>> {
639 let db: &'db dyn Database = self.db;
640 Ok(match generic_item {
641 ResolvedGenericItem::GenericConstant(id) => {
642 ResolvedConcreteItem::Constant(db.constant_const_value(id)?)
643 }
644 ResolvedGenericItem::Module(module_id) => {
645 if generic_args_syntax.is_some() {
646 return Err(
647 diagnostics.report(identifier.stable_ptr(db), UnexpectedGenericArgs)
648 );
649 }
650 ResolvedConcreteItem::Module(module_id)
651 }
652 ResolvedGenericItem::GenericFunction(generic_function) => {
653 ResolvedConcreteItem::Function(self.specialize_function(
654 diagnostics,
655 identifier.stable_ptr(db).untyped(),
656 generic_function,
657 &generic_args_syntax.unwrap_or_default(),
658 )?)
659 }
660 ResolvedGenericItem::GenericType(generic_type) => {
661 ResolvedConcreteItem::Type(self.specialize_type(
662 diagnostics,
663 identifier.stable_ptr(db).untyped(),
664 generic_type,
665 &generic_args_syntax.unwrap_or_default(),
666 )?)
667 }
668 ResolvedGenericItem::GenericTypeAlias(module_type_alias_id) => {
669 let ty = self.db.module_type_alias_resolved_type(module_type_alias_id)?;
670 let generic_params =
671 self.db.module_type_alias_generic_params(module_type_alias_id)?;
672 let generic_args = self.resolve_generic_args(
673 diagnostics,
674 GenericSubstitution::default(),
675 &generic_params,
676 &generic_args_syntax.unwrap_or_default(),
677 identifier.stable_ptr(db).untyped(),
678 )?;
679 ResolvedConcreteItem::Type(
680 GenericSubstitution::new(&generic_params, &generic_args).substitute(db, ty)?,
681 )
682 }
683 ResolvedGenericItem::GenericImplAlias(impl_alias_id) => {
684 let impl_id = db.impl_alias_resolved_impl(impl_alias_id)?;
685 let generic_params = db.impl_alias_generic_params(impl_alias_id)?;
686 let generic_args = self.resolve_generic_args(
687 diagnostics,
688 GenericSubstitution::default(),
689 &generic_params,
690 &generic_args_syntax.unwrap_or_default(),
691 identifier.stable_ptr(db).untyped(),
692 )?;
693 ResolvedConcreteItem::Impl(
694 GenericSubstitution::new(&generic_params, &generic_args)
695 .substitute(db, impl_id)?,
696 )
697 }
698 ResolvedGenericItem::Trait(trait_id) => {
699 ResolvedConcreteItem::Trait(self.specialize_trait(
700 diagnostics,
701 identifier.stable_ptr(db).untyped(),
702 trait_id,
703 &generic_args_syntax.unwrap_or_default(),
704 )?)
705 }
706 ResolvedGenericItem::Impl(impl_def_id) => ResolvedConcreteItem::Impl(
707 ImplLongId::Concrete(self.specialize_impl(
708 diagnostics,
709 identifier.stable_ptr(db).untyped(),
710 impl_def_id,
711 &generic_args_syntax.unwrap_or_default(),
712 )?)
713 .intern(self.db),
714 ),
715 ResolvedGenericItem::Macro(macro_declaration_id) => {
716 ResolvedConcreteItem::Macro(macro_declaration_id)
717 }
718 ResolvedGenericItem::Variant(var) => {
719 ResolvedConcreteItem::Variant(self.specialize_variant(
720 diagnostics,
721 identifier.stable_ptr(db).untyped(),
722 var.id,
723 &generic_args_syntax.unwrap_or_default(),
724 )?)
725 }
726 ResolvedGenericItem::Variable(_) => panic!("Variable is not a module item."),
727 ResolvedGenericItem::TraitItem(id) => {
728 panic!("`{}` is not a module item.", id.full_path(db))
729 }
730 })
731 }
732
733 fn resolve_path_using_use_star(
735 &mut self,
736 module_id: ModuleId<'db>,
737 ident: SmolStrId<'db>,
738 ) -> UseStarResult<'db> {
739 let mut item_info = None;
740 let mut module_items_found: OrderedHashSet<ModuleItemId<'_>> = OrderedHashSet::default();
741 let mut other_containing_modules = vec![];
742 for (item_module_id, info) in self.db.module_imported_modules((), module_id).iter() {
743 if *item_module_id == module_id {
745 continue;
746 }
747 if let Some(inner_item_info) =
748 self.resolve_item_in_module_or_expanded_macro(*item_module_id, ident)
749 {
750 if info.user_modules.iter().any(|user_module_id| {
751 self.is_item_visible(*item_module_id, &inner_item_info, *user_module_id)
752 }) {
753 item_info = Some(inner_item_info.clone());
754 module_items_found.insert(inner_item_info.item_id);
755 } else {
756 other_containing_modules.push(*item_module_id);
757 }
758 }
759 }
760 if module_items_found.len() > 1 {
761 return UseStarResult::AmbiguousPath(module_items_found.iter().cloned().collect());
762 }
763 match item_info {
764 Some(item_info) => UseStarResult::UniquePathFound(item_info),
765 None => {
766 for item_module_id in &other_containing_modules {
767 if let Some(inner_item_info) =
768 self.resolve_item_in_module_or_expanded_macro(*item_module_id, ident)
769 {
770 item_info = Some(inner_item_info.clone());
771 module_items_found.insert(inner_item_info.item_id);
772 }
773 }
774 if let Some(item_info) = item_info {
775 if module_items_found.len() > 1 {
776 UseStarResult::AmbiguousPath(module_items_found.iter().cloned().collect())
777 } else {
778 UseStarResult::ItemNotVisible(item_info.item_id, other_containing_modules)
779 }
780 } else {
781 UseStarResult::PathNotFound
782 }
783 }
784 }
785 }
786
787 fn resolve_item_in_module_or_expanded_macro(
789 &mut self,
790 module_id: ModuleId<'db>,
791 ident: SmolStrId<'db>,
792 ) -> Option<ModuleItemInfo<'db>> {
793 if let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
794 self.insert_used_use(info.item_id);
795 return Some(info);
796 }
797 let mut stack = vec![(module_id, false)];
798 loop {
799 let (module_id, expose) = stack.pop()?;
800 if expose && let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
801 self.insert_used_use(info.item_id);
802 return Some(info);
803 }
804 if let Ok(macro_calls) = self.db.module_macro_calls_ids(module_id) {
805 for macro_call in macro_calls {
806 if let Ok(macro_module_id) = self.db.macro_call_module_id(*macro_call) {
807 let expose = expose
808 || matches!(
809 macro_module_id,
810 ModuleId::MacroCall { is_expose: true, .. }
811 );
812 stack.push((macro_module_id, expose));
813 }
814 }
815 }
816 }
817 }
818
819 pub fn determine_base_item_in_local_scope(
821 &mut self,
822 identifier: &ast::TerminalIdentifier<'db>,
823 ) -> Option<ResolvedConcreteItem<'db>> {
824 let db = self.db;
825 let ident = identifier.text(db);
826
827 if let Some(generic_param_id) = self.data.generic_param_by_name.get(&ident) {
829 let item = match generic_param_id.kind(self.db) {
830 GenericKind::Type => ResolvedConcreteItem::Type(
831 TypeLongId::GenericParameter(*generic_param_id).intern(self.db),
832 ),
833 GenericKind::Const => ResolvedConcreteItem::Constant(
834 ConstValue::Generic(*generic_param_id).intern(self.db),
835 ),
836 GenericKind::Impl => ResolvedConcreteItem::Impl(
837 ImplLongId::GenericParameter(*generic_param_id).intern(self.db),
838 ),
839 GenericKind::NegImpl => return None,
840 };
841 return Some(item);
842 }
843 None
846 }
847
848 pub fn prelude_submodule(&self) -> ModuleId<'db> {
849 self.prelude_submodule_ex(&MacroResolutionInfo::from_resolver(self))
850 }
851
852 fn prelude_submodule_ex(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
854 let active_settings = self.active_settings(info);
855 let prelude_submodule_name = active_settings.edition.prelude_submodule_name(self.db);
856 let core_prelude_submodule = core_submodule(self.db, SmolStrId::from(self.db, "prelude"));
857 get_submodule(self.db, core_prelude_submodule, prelude_submodule_name).unwrap_or_else(
858 || {
859 panic!(
860 "expected prelude submodule `{}` not found in `core::prelude`.",
861 prelude_submodule_name.long(self.db)
862 )
863 },
864 )
865 }
866
867 fn specialize_trait(
869 &mut self,
870 diagnostics: &mut SemanticDiagnostics<'db>,
871 stable_ptr: SyntaxStablePtrId<'db>,
872 trait_id: TraitId<'db>,
873 generic_args: &[ast::GenericArg<'db>],
874 ) -> Maybe<ConcreteTraitId<'db>> {
875 let generic_params = self
877 .db
878 .trait_generic_params(trait_id)
879 .map_err(|_| diagnostics.report(stable_ptr, UnknownTrait))?;
880 let generic_args = self.resolve_generic_args(
881 diagnostics,
882 GenericSubstitution::default(),
883 generic_params,
884 generic_args,
885 stable_ptr,
886 )?;
887
888 Ok(ConcreteTraitLongId { trait_id, generic_args }.intern(self.db))
889 }
890
891 fn specialize_impl(
893 &mut self,
894 diagnostics: &mut SemanticDiagnostics<'db>,
895 stable_ptr: SyntaxStablePtrId<'db>,
896 impl_def_id: ImplDefId<'db>,
897 generic_args: &[ast::GenericArg<'db>],
898 ) -> Maybe<ConcreteImplId<'db>> {
899 let generic_params = self
901 .db
902 .impl_def_generic_params(impl_def_id)
903 .map_err(|_| diagnostics.report(stable_ptr, UnknownImpl))?;
904 let generic_args = self.resolve_generic_args(
905 diagnostics,
906 GenericSubstitution::default(),
907 generic_params,
908 generic_args,
909 stable_ptr,
910 )?;
911
912 Ok(ConcreteImplLongId { impl_def_id, generic_args }.intern(self.db))
913 }
914
915 fn specialize_variant(
917 &mut self,
918 diagnostics: &mut SemanticDiagnostics<'db>,
919 stable_ptr: SyntaxStablePtrId<'db>,
920 variant_id: VariantId<'db>,
921 generic_args: &[ast::GenericArg<'db>],
922 ) -> Maybe<ConcreteVariant<'db>> {
923 let concrete_enum_id = ConcreteEnumLongId {
924 enum_id: variant_id.enum_id(self.db),
925 generic_args: self.resolve_generic_args(
926 diagnostics,
927 GenericSubstitution::default(),
928 self.db.enum_generic_params(variant_id.enum_id(self.db))?,
929 generic_args,
930 stable_ptr,
931 )?,
932 }
933 .intern(self.db);
934 self.db.concrete_enum_variant(
935 concrete_enum_id,
936 &self.db.variant_semantic(variant_id.enum_id(self.db), variant_id)?,
937 )
938 }
939
940 pub fn specialize_function(
942 &mut self,
943 diagnostics: &mut SemanticDiagnostics<'db>,
944 stable_ptr: SyntaxStablePtrId<'db>,
945 generic_function: GenericFunctionId<'db>,
946 generic_args: &[ast::GenericArg<'db>],
947 ) -> Maybe<FunctionId<'db>> {
948 let generic_params = generic_function.generic_params(self.db)?;
950 let generic_args = self.resolve_generic_args(
951 diagnostics,
952 GenericSubstitution::default(),
953 generic_params,
954 generic_args,
955 stable_ptr,
956 )?;
957
958 Ok(FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }
959 .intern(self.db))
960 }
961
962 pub fn specialize_type(
964 &mut self,
965 diagnostics: &mut SemanticDiagnostics<'db>,
966 stable_ptr: SyntaxStablePtrId<'db>,
967 generic_type: GenericTypeId<'db>,
968 generic_args: &[ast::GenericArg<'db>],
969 ) -> Maybe<TypeId<'db>> {
970 let generic_params = self
971 .db
972 .generic_type_generic_params(generic_type)
973 .map_err(|_| diagnostics.report(stable_ptr, UnknownType))?;
974 let generic_args = self.resolve_generic_args(
975 diagnostics,
976 GenericSubstitution::default(),
977 generic_params,
978 generic_args,
979 stable_ptr,
980 )?;
981
982 Ok(TypeLongId::Concrete(ConcreteTypeId::new(self.db, generic_type, generic_args))
983 .intern(self.db))
984 }
985
986 pub fn impl_lookup_context(&self) -> ImplLookupContextId<'db> {
988 self.impl_lookup_context_ex(&MacroResolutionInfo::from_resolver(self))
989 }
990
991 fn impl_lookup_context_ex(&self, info: &MacroResolutionInfo<'db>) -> ImplLookupContextId<'db> {
994 let mut lookup_context = ImplLookupContext::new(
995 self.active_module_id(info),
996 self.generic_params.clone(),
997 self.db,
998 );
999
1000 if let TraitOrImplContext::Impl(impl_def_id) = &self.trait_or_impl_ctx {
1001 let Ok(generic_params) = self.db.impl_def_generic_params(*impl_def_id) else {
1002 return lookup_context.intern(self.db);
1003 };
1004 let generic_args = generic_params_to_args(generic_params, self.db);
1005 let impl_id: ConcreteImplId<'_> =
1006 ConcreteImplLongId { impl_def_id: *impl_def_id, generic_args }.intern(self.db);
1007 lookup_context.insert_impl(ImplLongId::Concrete(impl_id).intern(self.db), self.db);
1008 }
1009 lookup_context.intern(self.db)
1010 }
1011
1012 pub fn resolve_generic_args(
1016 &mut self,
1017 diagnostics: &mut SemanticDiagnostics<'db>,
1018 mut substitution: GenericSubstitution<'db>,
1019 generic_params: &[GenericParam<'db>],
1020 generic_args_syntax: &[ast::GenericArg<'db>],
1021 stable_ptr: SyntaxStablePtrId<'db>,
1022 ) -> Maybe<Vec<GenericArgumentId<'db>>> {
1023 let mut resolved_args = vec![];
1024 let arg_syntax_per_param = self.get_arg_syntax_per_param(
1025 diagnostics,
1026 &generic_params.iter().map(|generic_param| generic_param.id()).collect_vec(),
1027 generic_args_syntax,
1028 )?;
1029
1030 for generic_param in generic_params {
1031 let generic_param = substitution.substitute(self.db, generic_param.clone())?;
1032 let generic_arg = self.resolve_generic_arg(
1033 &generic_param,
1034 arg_syntax_per_param
1035 .get(&generic_param.id())
1036 .and_then(|arg_syntax| {
1037 if let ast::GenericArgValue::Expr(expr) = arg_syntax {
1038 Some(expr.expr(self.db))
1039 } else {
1040 None
1041 }
1042 })
1043 .as_ref(),
1044 stable_ptr,
1045 diagnostics,
1046 )?;
1047 resolved_args.push(generic_arg);
1048 substitution.insert(generic_param.id(), generic_arg);
1049 }
1050
1051 Ok(resolved_args)
1052 }
1053
1054 pub fn get_arg_syntax_per_param(
1056 &self,
1057 diagnostics: &mut SemanticDiagnostics<'db>,
1058 generic_params: &[GenericParamId<'db>],
1059 generic_args_syntax: &[ast::GenericArg<'db>],
1060 ) -> Maybe<UnorderedHashMap<GenericParamId<'db>, ast::GenericArgValue<'db>>> {
1061 let db = self.db;
1062 let mut arg_syntax_per_param =
1063 UnorderedHashMap::<GenericParamId<'_>, ast::GenericArgValue<'_>>::default();
1064 let mut last_named_arg_index = None;
1065 let generic_param_by_name = generic_params
1066 .iter()
1067 .enumerate()
1068 .filter_map(|(i, param)| Some((param.name(self.db)?, (i, param))))
1069 .collect::<UnorderedHashMap<_, _>>();
1070 for (idx, generic_arg_syntax) in generic_args_syntax.iter().enumerate() {
1071 match generic_arg_syntax {
1072 ast::GenericArg::Named(arg_syntax) => {
1073 let name = arg_syntax.name(db).text(db);
1074 let Some((index, generic_param_id)) = generic_param_by_name.get(&name) else {
1075 return Err(diagnostics
1076 .report(arg_syntax.stable_ptr(db), UnknownGenericParam(name)));
1077 };
1078 if let Some(prev_index) = last_named_arg_index
1079 && prev_index > index
1080 {
1081 return Err(diagnostics
1082 .report(arg_syntax.stable_ptr(db), GenericArgOutOfOrder(name)));
1083 }
1084 last_named_arg_index = Some(index);
1085 if arg_syntax_per_param
1086 .insert(**generic_param_id, arg_syntax.value(db))
1087 .is_some()
1088 {
1089 return Err(diagnostics
1090 .report(arg_syntax.stable_ptr(db), GenericArgDuplicate(name)));
1091 }
1092 }
1093 ast::GenericArg::Unnamed(arg_syntax) => {
1094 if last_named_arg_index.is_some() {
1095 return Err(diagnostics
1096 .report(arg_syntax.stable_ptr(db), PositionalGenericAfterNamed));
1097 }
1098 let generic_param = generic_params.get(idx).ok_or_else(|| {
1099 diagnostics.report(
1100 arg_syntax.stable_ptr(db),
1101 TooManyGenericArguments {
1102 expected: generic_params.len(),
1103 actual: generic_args_syntax.len(),
1104 },
1105 )
1106 })?;
1107 assert_eq!(
1108 arg_syntax_per_param.insert(*generic_param, arg_syntax.value(db)),
1109 None,
1110 "Unexpected duplication in ordered params."
1111 );
1112 }
1113 }
1114 }
1115 Ok(arg_syntax_per_param)
1116 }
1117
1118 fn resolve_generic_arg(
1122 &mut self,
1123 generic_param: &GenericParam<'db>,
1124 generic_arg_syntax_opt: Option<&ast::Expr<'db>>,
1125 stable_ptr: SyntaxStablePtrId<'db>,
1126 diagnostics: &mut SemanticDiagnostics<'db>,
1127 ) -> Result<GenericArgumentId<'db>, cairo_lang_diagnostics::DiagnosticAdded> {
1128 let Some(generic_arg_syntax) = generic_arg_syntax_opt else {
1129 let lookup_context = self.impl_lookup_context();
1130 let inference = &mut self.data.inference_data.inference(self.db);
1131 return inference
1132 .infer_generic_arg(generic_param, lookup_context, Some(stable_ptr))
1133 .map_err(|err_set| {
1134 inference.report_on_pending_error(err_set, diagnostics, stable_ptr)
1135 });
1136 };
1137 let db = self.db;
1138 Ok(match generic_param {
1139 GenericParam::Type(_) => {
1140 GenericArgumentId::Type(resolve_type(db, diagnostics, self, generic_arg_syntax))
1141 }
1142 GenericParam::Const(const_param) => {
1143 let mut ctx = ComputationContext::new_global(db, diagnostics, self);
1147 let value = compute_expr_semantic(&mut ctx, generic_arg_syntax);
1148 GenericArgumentId::Constant(resolve_const_expr_and_evaluate(
1149 db,
1150 &mut ctx,
1151 &value,
1152 generic_arg_syntax.stable_ptr(db).untyped(),
1153 const_param.ty,
1154 false,
1155 ))
1156 }
1157
1158 GenericParam::Impl(param) => {
1159 let expr_path = try_extract_matches!(generic_arg_syntax, ast::Expr::Path)
1160 .ok_or_else(|| {
1161 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1162 })?;
1163 let resolved_impl = match self.resolve_concrete_path(
1164 diagnostics,
1165 expr_path,
1166 NotFoundItemType::Impl,
1167 )? {
1168 ResolvedConcreteItem::Impl(resolved_impl) => resolved_impl,
1169 ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
1170 ImplLongId::SelfImpl(concrete_trait_id).intern(self.db)
1171 }
1172 _ => {
1173 return Err(
1174 diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1175 );
1176 }
1177 };
1178 let impl_def_concrete_trait = self.db.impl_concrete_trait(resolved_impl)?;
1179 let expected_concrete_trait = param.concrete_trait?;
1180 if let Err(err_set) = self
1181 .inference()
1182 .conform_traits(impl_def_concrete_trait, expected_concrete_trait)
1183 {
1184 let diag_added = diagnostics.report(
1185 generic_arg_syntax.stable_ptr(db),
1186 TraitMismatch {
1187 expected_trt: expected_concrete_trait,
1188 actual_trt: impl_def_concrete_trait,
1189 },
1190 );
1191 self.inference().consume_reported_error(err_set, diag_added);
1192 } else {
1193 for (trait_ty, ty1) in param.type_constraints.iter() {
1194 let ty0 = TypeLongId::ImplType(ImplTypeId::new(
1195 resolved_impl,
1196 *trait_ty,
1197 self.db,
1198 ))
1199 .intern(self.db);
1200 let _ = self.inference().conform_ty(ty0, *ty1).map_err(|err_set| {
1201 self.inference().report_on_pending_error(
1202 err_set,
1203 diagnostics,
1204 stable_ptr,
1205 )
1206 });
1207 }
1208 }
1209 GenericArgumentId::Impl(resolved_impl)
1210 }
1211 GenericParam::NegImpl(_) => {
1212 return Err(
1213 diagnostics.report(generic_arg_syntax.stable_ptr(db), ArgPassedToNegativeImpl)
1214 );
1215 }
1216 })
1217 }
1218
1219 pub fn ignore_visibility_checks(&self, module_id: ModuleId<'db>) -> bool {
1222 self.ignore_visibility_checks_ex(module_id, &MacroResolutionInfo::from_resolver(self))
1223 }
1224
1225 fn ignore_visibility_checks_ex(
1228 &self,
1229 module_id: ModuleId<'db>,
1230 info: &MacroResolutionInfo<'db>,
1231 ) -> bool {
1232 let module_crate = module_id.owning_crate(self.db);
1233 let module_edition =
1234 self.db.crate_config(module_crate).map(|c| c.settings.edition).unwrap_or_default();
1235 module_edition.ignore_visibility()
1236 || self.active_settings(info).edition.ignore_visibility()
1237 && module_crate == self.db.core_crate()
1238 }
1239
1240 pub fn validate_feature_constraints<T: HasFeatureKind<'db>>(
1245 &self,
1246 diagnostics: &mut SemanticDiagnostics<'db>,
1247 identifier: &ast::TerminalIdentifier<'db>,
1248 item_info: &T,
1249 ) {
1250 let db = self.db;
1251 match item_info.feature_kind() {
1252 FeatureKind::Unstable { feature, note }
1253 if !self.data.feature_config.allowed_features.contains(feature) =>
1254 {
1255 diagnostics.report(
1256 identifier.stable_ptr(db),
1257 UnstableFeature { feature_name: *feature, note: *note },
1258 );
1259 }
1260 FeatureKind::Deprecated { feature, note }
1261 if !self
1262 .data
1263 .feature_config
1264 .allowed_lints
1265 .contains(&SmolStrId::from(self.db, DEPRECATED_ATTR))
1266 && !self.data.feature_config.allowed_features.contains(feature) =>
1267 {
1268 diagnostics.report(
1269 identifier.stable_ptr(db),
1270 DeprecatedFeature { feature_name: *feature, note: *note },
1271 );
1272 }
1273 FeatureKind::Internal { feature, note }
1274 if !self.data.feature_config.allowed_features.contains(feature) =>
1275 {
1276 diagnostics.report(
1277 identifier.stable_ptr(db),
1278 InternalFeature { feature_name: *feature, note: *note },
1279 );
1280 }
1281 _ => {}
1282 }
1283 }
1284
1285 pub fn is_item_visible(
1287 &self,
1288 containing_module_id: ModuleId<'db>,
1289 item_info: &ModuleItemInfo<'db>,
1290 user_module: ModuleId<'db>,
1291 ) -> bool {
1292 self.is_item_visible_ex(
1293 containing_module_id,
1294 item_info,
1295 user_module,
1296 &MacroResolutionInfo::from_resolver(self),
1297 )
1298 }
1299
1300 fn is_item_visible_ex(
1302 &self,
1303 mut containing_module_id: ModuleId<'db>, item_info: &ModuleItemInfo<'db>,
1305 user_module: ModuleId<'db>,
1306 info: &MacroResolutionInfo<'db>,
1307 ) -> bool {
1308 let db = self.db;
1309 if containing_module_id == user_module {
1310 return true;
1311 }
1312 while let ModuleId::MacroCall { id, .. } = containing_module_id {
1313 containing_module_id = id.parent_module(self.db);
1314 }
1315 self.ignore_visibility_checks_ex(containing_module_id, info)
1316 || visibility::peek_visible_in(
1317 db,
1318 item_info.visibility,
1319 containing_module_id,
1320 user_module,
1321 )
1322 }
1323
1324 pub fn insert_used_use(&mut self, item_id: ModuleItemId<'db>) {
1326 if let ModuleItemId::Use(use_id) = item_id {
1327 self.data.used_uses.insert(use_id);
1328 }
1329 }
1330
1331 fn handle_same_impl_trait(
1337 &mut self,
1338 diagnostics: &mut SemanticDiagnostics<'db>,
1339 specialized_item: &mut ResolvedConcreteItem<'db>,
1340 generic_args_syntax_slice: &[ast::GenericArg<'db>],
1341 segment_stable_ptr: SyntaxStablePtrId<'db>,
1342 ) {
1343 match *specialized_item {
1344 ResolvedConcreteItem::Trait(current_segment_concrete_trait) => {
1345 match self.trait_or_impl_ctx {
1346 TraitOrImplContext::None => {}
1347 TraitOrImplContext::Trait(ctx_trait) => {
1348 if self
1349 .warn_trait_in_same_trait(
1350 diagnostics,
1351 current_segment_concrete_trait.trait_id(self.db),
1352 generic_args_syntax_slice,
1353 ctx_trait,
1354 segment_stable_ptr,
1355 )
1356 .is_err()
1357 {
1358 *specialized_item =
1359 ResolvedConcreteItem::SelfTrait(current_segment_concrete_trait);
1360 }
1361 }
1362 TraitOrImplContext::Impl(ctx_impl_def_id) => {
1363 self.warn_trait_in_its_impl(
1364 diagnostics,
1365 current_segment_concrete_trait,
1366 ctx_impl_def_id,
1367 segment_stable_ptr,
1368 )
1369 .ok();
1370 }
1371 };
1372 }
1373 ResolvedConcreteItem::Impl(current_segment_impl_id) => {
1374 if let TraitOrImplContext::Impl(ctx_impl) = self.trait_or_impl_ctx {
1375 let current_segment_concrete_impl_id = extract_matches!(
1378 current_segment_impl_id.long(self.db),
1379 ImplLongId::Concrete
1380 );
1381 self.warn_impl_in_same_impl(
1382 diagnostics,
1383 current_segment_concrete_impl_id.impl_def_id(self.db),
1384 generic_args_syntax_slice,
1385 ctx_impl,
1386 segment_stable_ptr,
1387 )
1388 .ok();
1389 }
1390 }
1391 _ => {}
1392 };
1393 }
1394
1395 fn warn_impl_in_same_impl(
1398 &mut self,
1399 diagnostics: &mut SemanticDiagnostics<'db>,
1400 current_segment_impl_def_id: ImplDefId<'db>,
1401 current_segment_generic_args: &[ast::GenericArg<'db>],
1402 ctx_impl: ImplDefId<'db>,
1403 segment_stable_ptr: SyntaxStablePtrId<'db>,
1404 ) -> Maybe<()> {
1405 if current_segment_impl_def_id != ctx_impl {
1406 return Ok(());
1407 }
1408
1409 let generic_params = self.db.impl_def_generic_params(ctx_impl)?;
1410 self.compare_segment_args_to_params(
1411 diagnostics,
1412 current_segment_generic_args,
1413 generic_params,
1414 segment_stable_ptr,
1415 ImplInImplMustBeExplicit,
1416 ImplItemForbiddenInTheImpl,
1417 )
1418 }
1419
1420 fn warn_trait_in_its_impl(
1423 &mut self,
1424 diagnostics: &mut SemanticDiagnostics<'db>,
1425 current_segment_concrete_trait_id: ConcreteTraitId<'db>,
1426 impl_ctx: ImplDefId<'db>,
1427 segment_stable_ptr: SyntaxStablePtrId<'db>,
1428 ) -> Maybe<()> {
1429 let ctx_impl_trait = self.db.impl_def_trait(impl_ctx)?;
1430 if current_segment_concrete_trait_id.trait_id(self.db) != ctx_impl_trait {
1431 return Ok(());
1432 }
1433
1434 let ctx_impl_concrete_trait = self.db.impl_def_concrete_trait(impl_ctx)?;
1435 if ctx_impl_concrete_trait.generic_args(self.db)
1436 == current_segment_concrete_trait_id.generic_args(self.db)
1437 {
1438 return Err(diagnostics.report(segment_stable_ptr, TraitItemForbiddenInItsImpl));
1439 }
1440 Ok(())
1441 }
1442
1443 fn warn_trait_in_same_trait(
1446 &mut self,
1447 diagnostics: &mut SemanticDiagnostics<'db>,
1448 current_segment_trait_id: TraitId<'db>,
1449 current_segment_generic_args: &[ast::GenericArg<'db>],
1450 ctx_trait: TraitId<'db>,
1451 segment_stable_ptr: SyntaxStablePtrId<'db>,
1452 ) -> Maybe<()> {
1453 if current_segment_trait_id != ctx_trait {
1454 return Ok(());
1455 }
1456
1457 let generic_params = self.db.trait_generic_params(ctx_trait)?;
1458 self.compare_segment_args_to_params(
1459 diagnostics,
1460 current_segment_generic_args,
1461 generic_params,
1462 segment_stable_ptr,
1463 TraitInTraitMustBeExplicit,
1464 TraitItemForbiddenInTheTrait,
1465 )
1466 }
1467
1468 fn compare_segment_args_to_params(
1475 &mut self,
1476 diagnostics: &mut SemanticDiagnostics<'db>,
1477 current_segment_generic_args: &[ast::GenericArg<'db>],
1478 generic_params: &[GenericParam<'db>],
1479 segment_stable_ptr: SyntaxStablePtrId<'db>,
1480 must_be_explicit_error: SemanticDiagnosticKind<'db>,
1481 item_forbidden_in_itself_explicit_error: SemanticDiagnosticKind<'db>,
1482 ) -> Maybe<()> {
1483 if current_segment_generic_args.len() < generic_params.len() {
1486 return Err(diagnostics.report(segment_stable_ptr, must_be_explicit_error));
1487 }
1488 let resolved_args = self.resolve_generic_args(
1489 diagnostics,
1490 GenericSubstitution::default(),
1491 generic_params,
1492 current_segment_generic_args,
1493 segment_stable_ptr,
1494 )?;
1495
1496 if generic_params
1497 .iter()
1498 .zip_eq(resolved_args.iter())
1499 .all(|(gparam, garg)| gparam.as_arg(self.db) == *garg)
1500 {
1501 return Err(
1502 diagnostics.report(segment_stable_ptr, item_forbidden_in_itself_explicit_error)
1503 );
1504 }
1505 Ok(())
1506 }
1507
1508 fn specialize_generic_statement_arg(
1510 &mut self,
1511 diagnostics: &mut SemanticDiagnostics<'db>,
1512 segment: &ast::PathSegment<'db>,
1513 identifier: &ast::TerminalIdentifier<'db>,
1514 inner_generic_item: ResolvedGenericItem<'db>,
1515 generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
1516 ) -> ResolvedConcreteItem<'db> {
1517 let segment_stable_ptr = segment.stable_ptr(self.db).untyped();
1518 let mut specialized_item = self
1519 .specialize_generic_module_item(
1520 diagnostics,
1521 identifier,
1522 inner_generic_item,
1523 generic_args_syntax.clone(),
1524 )
1525 .unwrap();
1526 self.handle_same_impl_trait(
1527 diagnostics,
1528 &mut specialized_item,
1529 &generic_args_syntax.unwrap_or_default(),
1530 segment_stable_ptr,
1531 );
1532 specialized_item
1533 }
1534}
1535
1536fn handle_macro_context_modifier<'db>(
1549 db: &'db dyn Database,
1550 diagnostics: &mut SemanticDiagnostics<'db>,
1551 segments: &mut Peekable<std::vec::IntoIter<ast::PathSegment<'db>>>,
1552) -> Maybe<MacroContextModifier> {
1553 if segments.len() == 1 {
1554 return Err(diagnostics.report_after(
1555 segments.next().unwrap().stable_ptr(db),
1556 EmptyPathAfterResolverModifier,
1557 ));
1558 }
1559 match segments.peek() {
1560 Some(ast::PathSegment::Simple(path_segment_simple)) => {
1561 let ident = path_segment_simple.ident(db);
1562 let ident_text = ident.text(db);
1563 match ident_text.long(db).as_str() {
1564 MACRO_DEF_SITE | MACRO_CALL_SITE => {
1565 segments.next();
1566 if ident_text.long(db) == MACRO_DEF_SITE {
1567 Ok(MacroContextModifier::DefSite)
1568 } else {
1569 Ok(MacroContextModifier::CallSite)
1570 }
1571 }
1572 _ => Err(diagnostics.report(
1573 ident.stable_ptr(db),
1574 UnknownResolverModifier { modifier: ident_text },
1575 )),
1576 }
1577 }
1578 _ => {
1579 Err(skip_diagnostic())
1581 }
1582 }
1583}
1584
1585fn resolve_self_segment<'db>(
1588 db: &'db dyn Database,
1589 diagnostics: &mut SemanticDiagnostics<'db>,
1590 identifier: &ast::TerminalIdentifier<'db>,
1591 trait_or_impl_ctx: &TraitOrImplContext<'db>,
1592) -> Option<Maybe<ResolvedConcreteItem<'db>>> {
1593 require(identifier.text(db).long(db) == SELF_TYPE_KW)?;
1594 Some(resolve_actual_self_segment(db, diagnostics, identifier, trait_or_impl_ctx))
1595}
1596
1597fn resolve_actual_self_segment<'db>(
1599 db: &'db dyn Database,
1600 diagnostics: &mut SemanticDiagnostics<'db>,
1601 identifier: &ast::TerminalIdentifier<'db>,
1602 trait_or_impl_ctx: &TraitOrImplContext<'db>,
1603) -> Maybe<ResolvedConcreteItem<'db>> {
1604 match trait_or_impl_ctx {
1605 TraitOrImplContext::None => {
1606 Err(diagnostics.report(identifier.stable_ptr(db), SelfNotSupportedInContext))
1607 }
1608 TraitOrImplContext::Trait(trait_id) => {
1609 let generic_parameters = db.trait_generic_params(*trait_id)?;
1610 let concrete_trait_id = ConcreteTraitLongId {
1611 trait_id: *trait_id,
1612 generic_args: generic_params_to_args(generic_parameters, db),
1613 }
1614 .intern(db);
1615 Ok(ResolvedConcreteItem::SelfTrait(concrete_trait_id))
1616 }
1617 TraitOrImplContext::Impl(impl_def_id) => {
1618 let generic_parameters = db.impl_def_generic_params(*impl_def_id)?;
1619 let impl_id = ImplLongId::Concrete(
1620 ConcreteImplLongId {
1621 impl_def_id: *impl_def_id,
1622 generic_args: generic_params_to_args(generic_parameters, db),
1623 }
1624 .intern(db),
1625 );
1626 Ok(ResolvedConcreteItem::Impl(impl_id.intern(db)))
1627 }
1628 }
1629}
1630
1631enum ResolvedBase<'db> {
1633 Module(ModuleId<'db>),
1635 Crate(CrateId<'db>),
1637 StatementEnvironment(ResolvedGenericItem<'db>),
1639 FoundThroughGlobalUse { item_info: ModuleItemInfo<'db>, containing_module: ModuleId<'db> },
1641 Ambiguous(Vec<ModuleItemId<'db>>),
1643 ItemNotVisible(ModuleItemId<'db>, Vec<ModuleId<'db>>),
1645}
1646
1647struct ResolutionCallbacks<'db, 'a, ResolvedItem, First, Next, Validate, Mark>
1649where
1650 First: FnOnce(&mut Resolution<'db, 'a>) -> Maybe<ResolvedItem>,
1651 Next: FnMut(
1652 &mut Resolution<'db, 'a>,
1653 &ResolvedItem,
1654 &ast::PathSegment<'db>,
1655 ) -> Maybe<ResolvedItem>,
1656 Validate: FnMut(&mut SemanticDiagnostics<'db>, &ast::PathSegment<'db>) -> Maybe<()>,
1657 Mark: FnMut(
1658 &mut ResolvedItems<'db>,
1659 &'db dyn Database,
1660 &syntax::node::ast::PathSegment<'db>,
1661 ResolvedItem,
1662 ),
1663{
1664 _phantom: PhantomData<(ResolvedItem, &'db (), &'a ())>,
1666 first: First,
1668 next: Next,
1670 validate: Validate,
1673 mark: Mark,
1675}
1676
1677struct Resolution<'db, 'a> {
1679 resolver: &'a mut Resolver<'db>,
1681 diagnostics: &'a mut SemanticDiagnostics<'db>,
1683 segments: Peekable<std::vec::IntoIter<ast::PathSegment<'db>>>,
1685 expected_item_type: NotFoundItemType,
1687 resolution_context: ResolutionContext<'db, 'a>,
1689 macro_info: MacroResolutionInfo<'db>,
1691}
1692impl<'db, 'a> Resolution<'db, 'a> {
1693 fn new(
1697 resolver: &'a mut Resolver<'db>,
1698 diagnostics: &'a mut SemanticDiagnostics<'db>,
1699 path: impl AsSegments<'db>,
1700 item_type: NotFoundItemType,
1701 resolution_context: ResolutionContext<'db, 'a>,
1702 ) -> Maybe<Self> {
1703 let db = resolver.db;
1704 let placeholder_marker = path.placeholder_marker(db);
1705
1706 let mut cur_offset =
1707 ExpansionOffset::new(path.offset(db).expect("Trying to resolve an empty path."));
1708 let elements_vec = path.to_segments(db);
1709 let mut segments = elements_vec.into_iter().peekable();
1710 let mut cur_macro_call_data = resolver.macro_call_data.as_ref();
1711 let mut path_defining_module = resolver.data.module_id;
1712 while let Some(macro_call_data) = &cur_macro_call_data {
1715 let Some(new_offset) = cur_offset.mapped(¯o_call_data.expansion_mappings) else {
1716 break;
1717 };
1718 path_defining_module = macro_call_data.callsite_module_id;
1719 cur_macro_call_data = macro_call_data.parent_macro_call_data.as_ref();
1720 cur_offset = new_offset;
1721 }
1722 let macro_call_data = cur_macro_call_data.cloned();
1723
1724 let macro_context_modifier = if let Some(marker) = placeholder_marker {
1725 if macro_call_data.is_some() {
1726 handle_macro_context_modifier(db, diagnostics, &mut segments)?
1727 } else {
1728 return Err(diagnostics.report(marker.stable_ptr(db), DollarNotSupportedInContext));
1729 }
1730 } else {
1731 MacroContextModifier::None
1732 };
1733 let macro_info = MacroResolutionInfo {
1734 base: path_defining_module,
1735 data: macro_call_data,
1736 modifier: macro_context_modifier,
1737 };
1738 Ok(Resolution {
1739 resolver,
1740 diagnostics,
1741 segments,
1742 expected_item_type: item_type,
1743 resolution_context,
1744 macro_info,
1745 })
1746 }
1747
1748 fn full<ResolvedItem: Clone>(
1751 mut self,
1752 mut callbacks: ResolutionCallbacks<
1753 'db,
1754 'a,
1755 ResolvedItem,
1756 impl FnOnce(&mut Resolution<'db, 'a>) -> Maybe<ResolvedItem>,
1757 impl FnMut(
1758 &mut Resolution<'db, 'a>,
1759 &ResolvedItem,
1760 &ast::PathSegment<'db>,
1761 ) -> Maybe<ResolvedItem>,
1762 impl FnMut(&mut SemanticDiagnostics<'db>, &ast::PathSegment<'db>) -> Maybe<()>,
1763 impl FnMut(
1764 &mut ResolvedItems<'db>,
1765 &'db dyn Database,
1766 &syntax::node::ast::PathSegment<'db>,
1767 ResolvedItem,
1768 ),
1769 >,
1770 ) -> Maybe<ResolvedItem>
1771 where
1772 'db: 'a,
1773 {
1774 let mut item: ResolvedItem = (callbacks.first)(&mut self)?;
1776
1777 while let Some(segment) = self.segments.next() {
1779 (callbacks.validate)(self.diagnostics, &segment)?;
1780 item = (callbacks.next)(&mut self, &item, &segment)?;
1783 let db = self.resolver.db;
1784 (callbacks.mark)(&mut self.resolver.resolved_items, db, &segment, item.clone());
1785 }
1786 Ok(item)
1787 }
1788
1789 fn specialize_generic_inner_item(
1791 &mut self,
1792 module_id: ModuleId<'db>,
1793 segment: &ast::PathSegment<'db>,
1794 identifier: &TerminalIdentifier<'db>,
1795 inner_item_info: ModuleItemInfo<'db>,
1796 ) -> Maybe<ResolvedConcreteItem<'db>> {
1797 let db = self.resolver.db;
1798 let generic_args_syntax = segment.generic_args(db);
1799 let segment_stable_ptr = segment.stable_ptr(db).untyped();
1800 self.validate_module_item_usability(module_id, identifier, &inner_item_info);
1801 self.resolver.insert_used_use(inner_item_info.item_id);
1802 let inner_generic_item =
1803 ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)?;
1804 let mut specialized_item = self.resolver.specialize_generic_module_item(
1805 self.diagnostics,
1806 identifier,
1807 inner_generic_item.clone(),
1808 generic_args_syntax.clone(),
1809 )?;
1810 self.resolver
1811 .data
1812 .resolved_items
1813 .generic
1814 .insert(identifier.stable_ptr(db), inner_generic_item);
1815 self.resolver.handle_same_impl_trait(
1816 self.diagnostics,
1817 &mut specialized_item,
1818 &generic_args_syntax.unwrap_or_default(),
1819 segment_stable_ptr,
1820 );
1821 Ok(specialized_item)
1822 }
1823
1824 fn first_concrete(&mut self) -> Maybe<ResolvedConcreteItem<'db>> {
1826 if let Some(base_module) =
1827 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
1828 resolved_items.mark_concrete(db, segment, ResolvedConcreteItem::Module(module_id));
1829 })
1830 {
1831 return Ok(ResolvedConcreteItem::Module(base_module?));
1832 }
1833
1834 let db = self.resolver.db;
1835 Ok(match self.segments.peek().unwrap() {
1836 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
1837 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
1838 let identifier = generic_segment.ident(db);
1839 match self.determine_base(&identifier)? {
1841 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1842 ResolvedBase::Crate(_) => {
1843 return Err(self
1845 .diagnostics
1846 .report(generics_stable_ptr, UnexpectedGenericArgs));
1847 }
1848 ResolvedBase::StatementEnvironment(generic_item) => {
1849 let segment = self.segments.next().unwrap();
1850 let concrete_item = self.resolver.specialize_generic_statement_arg(
1851 self.diagnostics,
1852 &segment,
1853 &identifier,
1854 generic_item,
1855 segment.generic_args(db),
1856 );
1857 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1858 }
1859 ResolvedBase::FoundThroughGlobalUse {
1860 item_info: inner_module_item,
1861 containing_module: module_id,
1862 } => {
1863 let segment = self.segments.next().unwrap();
1864
1865 let concrete_item = self.specialize_generic_inner_item(
1866 module_id,
1867 &segment,
1868 &identifier,
1869 inner_module_item,
1870 )?;
1871 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1872 }
1873 ResolvedBase::Ambiguous(module_items) => {
1874 return Err(self
1875 .diagnostics
1876 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1877 }
1878 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1879 return Err(self.diagnostics.report(
1880 identifier.stable_ptr(db),
1881 ItemNotVisible(module_item_id, containing_modules),
1882 ));
1883 }
1884 }
1885 }
1886 syntax::node::ast::PathSegment::Simple(simple_segment) => {
1887 let identifier = simple_segment.ident(db);
1888
1889 if let Some(resolved_item) = resolve_self_segment(
1890 db,
1891 self.diagnostics,
1892 &identifier,
1893 &self.resolver.data.trait_or_impl_ctx,
1894 ) {
1895 return Ok(self.resolver.resolved_items.mark_concrete(
1897 db,
1898 &self.segments.next().unwrap(),
1899 resolved_item?,
1900 ));
1901 }
1902
1903 if let Some(local_item) =
1904 self.resolver.determine_base_item_in_local_scope(&identifier)
1905 {
1906 self.resolver.resolved_items.mark_concrete(
1907 db,
1908 &self.segments.next().unwrap(),
1909 local_item,
1910 )
1911 } else {
1912 match self.determine_base(&identifier)? {
1913 ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1915 ResolvedBase::Crate(crate_id) => {
1916 self.resolver.resolved_items.mark_concrete(
1917 db,
1918 &self.segments.next().unwrap(),
1919 ResolvedConcreteItem::Module(ModuleId::CrateRoot(crate_id)),
1920 )
1921 }
1922 ResolvedBase::StatementEnvironment(generic_item) => {
1923 let segment = self.segments.next().unwrap();
1924
1925 let concrete_item = self.resolver.specialize_generic_statement_arg(
1926 self.diagnostics,
1927 &segment,
1928 &identifier,
1929 generic_item,
1930 segment.generic_args(db),
1931 );
1932 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1933 }
1934 ResolvedBase::FoundThroughGlobalUse {
1935 item_info: inner_module_item,
1936 containing_module: module_id,
1937 } => {
1938 let segment = self.segments.next().unwrap();
1939 let concrete_item = self.specialize_generic_inner_item(
1940 module_id,
1941 &segment,
1942 &identifier,
1943 inner_module_item,
1944 )?;
1945 self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1946 }
1947 ResolvedBase::Ambiguous(module_items) => {
1948 return Err(self
1949 .diagnostics
1950 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1951 }
1952 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1953 return Err(self.diagnostics.report(
1954 identifier.stable_ptr(db),
1955 ItemNotVisible(module_item_id, containing_modules),
1956 ));
1957 }
1958 }
1959 }
1960 }
1961 syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
1963 })
1964 }
1965 fn first_generic(&mut self, allow_generic_args: bool) -> Maybe<ResolvedGenericItem<'db>> {
1968 if let Some(base_module) =
1969 self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
1970 resolved_items.mark_generic(db, segment, ResolvedGenericItem::Module(module_id));
1971 })
1972 {
1973 return Ok(ResolvedGenericItem::Module(base_module?));
1974 }
1975 let db = self.resolver.db;
1976 Ok(match self.segments.peek().unwrap() {
1977 syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
1978 let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
1979 if !allow_generic_args {
1980 return Err(self
1981 .diagnostics
1982 .report(generics_stable_ptr, UnexpectedGenericArgs));
1983 }
1984 let identifier = generic_segment.ident(db);
1985 match self.determine_base(&identifier)? {
1986 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
1987 ResolvedBase::Crate(_) => {
1988 return Err(self
1990 .diagnostics
1991 .report(generics_stable_ptr, UnexpectedGenericArgs));
1992 }
1993 ResolvedBase::StatementEnvironment(generic_item) => generic_item,
1994 ResolvedBase::FoundThroughGlobalUse {
1995 item_info: inner_module_item, ..
1996 } => {
1997 self.resolver.insert_used_use(inner_module_item.item_id);
1998 let generic_item =
1999 ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2000 self.resolver.resolved_items.mark_generic(
2001 db,
2002 &self.segments.next().unwrap(),
2003 generic_item,
2004 )
2005 }
2006 ResolvedBase::Ambiguous(module_items) => {
2007 return Err(self
2008 .diagnostics
2009 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2010 }
2011 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2012 return Err(self.diagnostics.report(
2013 identifier.stable_ptr(db),
2014 ItemNotVisible(module_item_id, containing_modules),
2015 ));
2016 }
2017 }
2018 }
2019 syntax::node::ast::PathSegment::Simple(simple_segment) => {
2020 let identifier = simple_segment.ident(db);
2021 match self.determine_base(&identifier)? {
2022 ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2024 ResolvedBase::Crate(crate_id) => self.resolver.resolved_items.mark_generic(
2025 db,
2026 &self.segments.next().unwrap(),
2027 ResolvedGenericItem::Module(ModuleId::CrateRoot(crate_id)),
2028 ),
2029 ResolvedBase::StatementEnvironment(generic_item) => self
2030 .resolver
2031 .resolved_items
2032 .mark_generic(db, &self.segments.next().unwrap(), generic_item),
2033 ResolvedBase::FoundThroughGlobalUse {
2034 item_info: inner_module_item, ..
2035 } => {
2036 self.resolver.insert_used_use(inner_module_item.item_id);
2037 let generic_item =
2038 ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2039 self.resolver.resolved_items.mark_generic(
2040 db,
2041 &self.segments.next().unwrap(),
2042 generic_item,
2043 )
2044 }
2045 ResolvedBase::Ambiguous(module_items) => {
2046 return Err(self
2047 .diagnostics
2048 .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2049 }
2050 ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2051 return Err(self.diagnostics.report(
2052 identifier.stable_ptr(db),
2053 ItemNotVisible(module_item_id, containing_modules),
2054 ));
2055 }
2056 }
2057 }
2058 syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
2060 })
2061 }
2062
2063 fn try_handle_super_segments(
2067 &mut self,
2068 mut mark: impl FnMut(
2069 &mut ResolvedItems<'db>,
2070 &'db dyn Database,
2071 &syntax::node::ast::PathSegment<'db>,
2072 ModuleId<'db>,
2073 ),
2074 ) -> Option<Maybe<ModuleId<'db>>> {
2075 let db = self.resolver.db;
2076 let mut curr = None;
2077 for segment in self.segments.peeking_take_while(|segment| match segment {
2078 ast::PathSegment::WithGenericArgs(_) | ast::PathSegment::Missing(_) => false,
2079 ast::PathSegment::Simple(simple) => simple.identifier(db).long(db) == SUPER_KW,
2080 }) {
2081 let module_id = match curr {
2082 Some(module_id) => module_id,
2083 None => {
2084 if let Some(module_id) =
2085 self.resolver.try_get_active_module_id(&self.macro_info)
2086 {
2087 module_id
2088 } else {
2089 return Some(Err(self
2090 .diagnostics
2091 .report(segment.stable_ptr(db), SuperUsedInMacroCallTopLevel)));
2092 }
2093 }
2094 };
2095 match module_id {
2096 ModuleId::CrateRoot(_) => {
2097 return Some(Err(self
2098 .diagnostics
2099 .report(segment.stable_ptr(db), SuperUsedInRootModule)));
2100 }
2101 ModuleId::Submodule(submodule_id) => {
2102 let parent = submodule_id.parent_module(db);
2103 mark(&mut self.resolver.resolved_items, db, &segment, parent);
2104 curr = Some(parent);
2105 }
2106 ModuleId::MacroCall { .. } => {
2107 return Some(Err(self
2108 .diagnostics
2109 .report(segment.stable_ptr(db), SuperUsedInMacroCallTopLevel)));
2110 }
2111 }
2112 }
2113 curr.map(Ok)
2114 }
2115
2116 fn module_inner_item(
2118 &mut self,
2119 module_id: &ModuleId<'db>,
2120 ident: SmolStrId<'db>,
2121 identifier: &TerminalIdentifier<'db>,
2122 ) -> Maybe<ModuleItemInfo<'db>> {
2123 let db = self.resolver.db;
2124 if let Some(info) =
2125 self.resolver.resolve_item_in_module_or_expanded_macro(*module_id, ident)
2126 {
2127 return Ok(info);
2128 }
2129 match self.resolver.resolve_path_using_use_star(*module_id, ident) {
2130 UseStarResult::UniquePathFound(item_info) => Ok(item_info),
2131 UseStarResult::AmbiguousPath(module_items) => {
2132 Err(self.diagnostics.report(identifier.stable_ptr(db), AmbiguousPath(module_items)))
2133 }
2134 UseStarResult::PathNotFound => {
2135 let item_type = if self.segments.len() == 0 {
2136 self.expected_item_type
2137 } else {
2138 NotFoundItemType::Identifier
2139 };
2140 Err(self.diagnostics.report(identifier.stable_ptr(db), PathNotFound(item_type)))
2141 }
2142 UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
2143 Err(self.diagnostics.report(
2144 identifier.stable_ptr(db),
2145 ItemNotVisible(module_item_id, containing_modules),
2146 ))
2147 }
2148 }
2149 }
2150
2151 fn next_concrete(
2153 &mut self,
2154 containing_item: &ResolvedConcreteItem<'db>,
2155 segment: &ast::PathSegment<'db>,
2156 ) -> Maybe<ResolvedConcreteItem<'db>> {
2157 let db = self.resolver.db;
2158 let identifier = &segment.identifier_ast(db);
2159 let generic_args_syntax = segment.generic_args(db);
2160
2161 let ident = identifier.text(db);
2162
2163 if identifier.text(db).long(db) == SELF_TYPE_KW {
2164 return Err(self.diagnostics.report(identifier.stable_ptr(db), SelfMustBeFirst));
2165 }
2166
2167 match containing_item {
2168 ResolvedConcreteItem::Module(module_id) => {
2169 if ident.long(db) == SUPER_KW {
2172 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2173 }
2174 let inner_item_info = self.module_inner_item(module_id, ident, identifier)?;
2175
2176 self.specialize_generic_inner_item(*module_id, segment, identifier, inner_item_info)
2177 }
2178 ResolvedConcreteItem::Type(ty) => {
2179 if let TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_enum_id)) = ty.long(db) {
2180 let enum_id = concrete_enum_id.enum_id(db);
2181 let variants = db.enum_variants(enum_id).map_err(|_| {
2182 self.diagnostics.report(identifier.stable_ptr(db), UnknownEnum)
2183 })?;
2184 let variant_id = variants.get(&ident).ok_or_else(|| {
2185 self.diagnostics.report(
2186 identifier.stable_ptr(db),
2187 NoSuchVariant { enum_id, variant_name: ident },
2188 )
2189 })?;
2190 let variant = db.variant_semantic(enum_id, *variant_id)?;
2191 let concrete_variant = db.concrete_enum_variant(*concrete_enum_id, &variant)?;
2192 Ok(ResolvedConcreteItem::Variant(concrete_variant))
2193 } else {
2194 Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath))
2195 }
2196 }
2197 ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
2198 let impl_id = ImplLongId::SelfImpl(*concrete_trait_id).intern(db);
2199 let Some(trait_item_id) =
2200 db.trait_item_by_name(concrete_trait_id.trait_id(db), ident)?
2201 else {
2202 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2203 };
2204 if let Ok(Some(trait_item_info)) =
2205 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2206 {
2207 self.resolver.validate_feature_constraints(
2208 self.diagnostics,
2209 identifier,
2210 &trait_item_info,
2211 );
2212 }
2213 Ok(match trait_item_id {
2214 TraitItemId::Function(trait_function_id) => {
2215 ResolvedConcreteItem::Function(self.resolver.specialize_function(
2216 self.diagnostics,
2217 identifier.stable_ptr(db).untyped(),
2218 GenericFunctionId::Impl(ImplGenericFunctionId {
2219 impl_id,
2220 function: trait_function_id,
2221 }),
2222 &generic_args_syntax.unwrap_or_default(),
2223 )?)
2224 }
2225 TraitItemId::Type(trait_type_id) => ResolvedConcreteItem::Type(
2226 TypeLongId::ImplType(ImplTypeId::new(impl_id, trait_type_id, db))
2227 .intern(db),
2228 ),
2229 TraitItemId::Constant(trait_constant_id) => ResolvedConcreteItem::Constant(
2230 ConstValue::ImplConstant(ImplConstantId::new(
2231 impl_id,
2232 trait_constant_id,
2233 db,
2234 ))
2235 .intern(db),
2236 ),
2237 TraitItemId::Impl(trait_impl_id) => ResolvedConcreteItem::Impl(
2238 ImplLongId::ImplImpl(ImplImplId::new(impl_id, trait_impl_id, db))
2239 .intern(db),
2240 ),
2241 })
2242 }
2243 ResolvedConcreteItem::Trait(concrete_trait_id) => {
2244 let Some(trait_item_id) =
2245 db.trait_item_by_name(concrete_trait_id.trait_id(db), ident)?
2246 else {
2247 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2248 };
2249
2250 if let Ok(Some(trait_item_info)) =
2251 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2252 {
2253 self.resolver.validate_feature_constraints(
2254 self.diagnostics,
2255 identifier,
2256 &trait_item_info,
2257 );
2258 }
2259
2260 match trait_item_id {
2261 TraitItemId::Function(trait_function_id) => {
2262 let concrete_trait_function = ConcreteTraitGenericFunctionLongId::new(
2263 db,
2264 *concrete_trait_id,
2265 trait_function_id,
2266 )
2267 .intern(db);
2268 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2269 let impl_lookup_context =
2270 self.resolver.impl_lookup_context_ex(&self.macro_info);
2271 let generic_function = GenericFunctionId::Impl(
2272 self.resolver.inference().infer_trait_generic_function(
2273 concrete_trait_function,
2274 impl_lookup_context,
2275 Some(identifier_stable_ptr),
2276 ),
2277 );
2278
2279 Ok(ResolvedConcreteItem::Function(self.resolver.specialize_function(
2280 self.diagnostics,
2281 identifier_stable_ptr,
2282 generic_function,
2283 &generic_args_syntax.unwrap_or_default(),
2284 )?))
2285 }
2286 TraitItemId::Type(trait_type_id) => {
2287 let concrete_trait_type = ConcreteTraitTypeId::new_from_data(
2288 db,
2289 *concrete_trait_id,
2290 trait_type_id,
2291 );
2292
2293 let impl_lookup_context =
2294 self.resolver.impl_lookup_context_ex(&self.macro_info);
2295 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2296 let ty = self.resolver.inference().infer_trait_type(
2297 concrete_trait_type,
2298 impl_lookup_context,
2299 Some(identifier_stable_ptr),
2300 );
2301 Ok(ResolvedConcreteItem::Type(
2302 self.resolver.inference().rewrite(ty).no_err(),
2303 ))
2304 }
2305 TraitItemId::Constant(trait_constant_id) => {
2306 let concrete_trait_constant = ConcreteTraitConstantLongId::new(
2307 db,
2308 *concrete_trait_id,
2309 trait_constant_id,
2310 )
2311 .intern(db);
2312
2313 let impl_lookup_context =
2314 self.resolver.impl_lookup_context_ex(&self.macro_info);
2315 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2316 let imp_constant_id = self.resolver.inference().infer_trait_constant(
2317 concrete_trait_constant,
2318 impl_lookup_context,
2319 Some(identifier_stable_ptr),
2320 );
2321 self.resolver.inference().solve().ok();
2325
2326 Ok(ResolvedConcreteItem::Constant(
2327 ConstValue::ImplConstant(imp_constant_id).intern(db),
2328 ))
2329 }
2330 TraitItemId::Impl(trait_impl_id) => {
2331 let concrete_trait_impl = ConcreteTraitImplLongId::new_from_data(
2332 db,
2333 *concrete_trait_id,
2334 trait_impl_id,
2335 )
2336 .intern(db);
2337
2338 let impl_lookup_context =
2339 self.resolver.impl_lookup_context_ex(&self.macro_info);
2340 let identifier_stable_ptr = identifier.stable_ptr(db).untyped();
2341 let impl_impl_id = self.resolver.inference().infer_trait_impl(
2342 concrete_trait_impl,
2343 impl_lookup_context,
2344 Some(identifier_stable_ptr),
2345 );
2346 self.resolver.inference().solve().ok();
2350
2351 Ok(ResolvedConcreteItem::Impl(
2352 ImplLongId::ImplImpl(impl_impl_id).intern(db),
2353 ))
2354 }
2355 }
2356 }
2357 ResolvedConcreteItem::Impl(impl_id) => {
2358 let concrete_trait_id = db.impl_concrete_trait(*impl_id)?;
2359 let trait_id = concrete_trait_id.trait_id(db);
2360 let Some(trait_item_id) = db.trait_item_by_name(trait_id, ident)? else {
2361 return Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath));
2362 };
2363 if let Ok(Some(trait_item_info)) =
2364 db.trait_item_info_by_name(concrete_trait_id.trait_id(db), ident)
2365 {
2366 self.resolver.validate_feature_constraints(
2367 self.diagnostics,
2368 identifier,
2369 &trait_item_info,
2370 );
2371 }
2372 if let ImplLongId::Concrete(concrete_impl) = impl_id.long(db) {
2373 let impl_def_id: ImplDefId<'_> = concrete_impl.impl_def_id(db);
2374
2375 if let Ok(Some(impl_item_info)) = db.impl_item_info_by_name(impl_def_id, ident)
2376 {
2377 self.resolver.validate_feature_constraints(
2378 self.diagnostics,
2379 identifier,
2380 &impl_item_info,
2381 );
2382 }
2383 }
2384
2385 match trait_item_id {
2386 TraitItemId::Function(trait_function_id) => {
2387 let generic_function_id = GenericFunctionId::Impl(ImplGenericFunctionId {
2388 impl_id: *impl_id,
2389 function: trait_function_id,
2390 });
2391
2392 Ok(ResolvedConcreteItem::Function(self.resolver.specialize_function(
2393 self.diagnostics,
2394 identifier.stable_ptr(db).untyped(),
2395 generic_function_id,
2396 &generic_args_syntax.unwrap_or_default(),
2397 )?))
2398 }
2399 TraitItemId::Type(trait_type_id) => {
2400 let impl_type_id = ImplTypeId::new(*impl_id, trait_type_id, db);
2401 let ty = self
2402 .resolver
2403 .inference()
2404 .reduce_impl_ty(impl_type_id)
2405 .unwrap_or_else(|_| TypeLongId::ImplType(impl_type_id).intern(db));
2406 Ok(ResolvedConcreteItem::Type(ty))
2407 }
2408 TraitItemId::Constant(trait_constant_id) => {
2409 let impl_constant_id = ImplConstantId::new(*impl_id, trait_constant_id, db);
2410
2411 let constant = self
2412 .resolver
2413 .inference()
2414 .reduce_impl_constant(impl_constant_id)
2415 .unwrap_or_else(|_| {
2416 ConstValue::ImplConstant(impl_constant_id).intern(db)
2417 });
2418
2419 Ok(ResolvedConcreteItem::Constant(constant))
2420 }
2421 TraitItemId::Impl(trait_impl_id) => {
2422 let impl_impl_id = ImplImplId::new(*impl_id, trait_impl_id, db);
2423 let imp = self
2424 .resolver
2425 .inference()
2426 .reduce_impl_impl(impl_impl_id)
2427 .unwrap_or_else(|_| ImplLongId::ImplImpl(impl_impl_id).intern(db));
2428
2429 Ok(ResolvedConcreteItem::Impl(imp))
2430 }
2431 }
2432 }
2433 ResolvedConcreteItem::Function(function_id) if ident.long(db) == "Coupon" => {
2434 if !are_coupons_enabled(db, self.resolver.active_module_id(&self.macro_info)) {
2435 self.diagnostics.report(identifier.stable_ptr(db), CouponsDisabled);
2436 }
2437 if matches!(
2438 function_id.get_concrete(db).generic_function,
2439 GenericFunctionId::Extern(_)
2440 ) {
2441 return Err(self
2442 .diagnostics
2443 .report(identifier.stable_ptr(db), CouponForExternFunctionNotAllowed));
2444 }
2445 Ok(ResolvedConcreteItem::Type(TypeLongId::Coupon(*function_id).intern(db)))
2446 }
2447 _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2448 }
2449 }
2450
2451 fn next_generic(
2453 &mut self,
2454 containing_item: &ResolvedGenericItem<'db>,
2455 segment: &ast::PathSegment<'db>,
2456 ) -> Maybe<ResolvedGenericItem<'db>> {
2457 let db = self.resolver.db;
2458 let identifier = segment.identifier_ast(db);
2459 let ident = identifier.text(db);
2460 match containing_item {
2461 ResolvedGenericItem::Module(module_id) => {
2462 let inner_item_info = self.module_inner_item(module_id, ident, &identifier)?;
2463
2464 self.validate_module_item_usability(*module_id, &identifier, &inner_item_info);
2465 self.resolver.insert_used_use(inner_item_info.item_id);
2466 ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)
2467 }
2468 ResolvedGenericItem::GenericType(GenericTypeId::Enum(enum_id)) => {
2469 let variants = db.enum_variants(*enum_id)?;
2470 let variant_id = variants.get(&ident).ok_or_else(|| {
2471 self.diagnostics.report(
2472 identifier.stable_ptr(db),
2473 NoSuchVariant { enum_id: *enum_id, variant_name: ident },
2474 )
2475 })?;
2476 let variant = db.variant_semantic(*enum_id, *variant_id)?;
2477 Ok(ResolvedGenericItem::Variant(variant))
2478 }
2479 _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2480 }
2481 }
2482
2483 fn determine_base(
2486 &mut self,
2487 identifier: &ast::TerminalIdentifier<'db>,
2488 ) -> Maybe<ResolvedBase<'db>> {
2489 let db = self.resolver.db;
2490 let ident = identifier.text(db);
2491 if let ResolutionContext::Statement(ref mut env) = self.resolution_context
2492 && let Some(item) = get_statement_item_by_name(env, ident)
2493 {
2494 return Ok(ResolvedBase::StatementEnvironment(item));
2495 }
2496
2497 let Some(module_id) = self.resolver.try_get_active_module_id(&self.macro_info) else {
2498 let item_type = if self.segments.len() == 1 {
2499 self.expected_item_type
2500 } else {
2501 NotFoundItemType::Identifier
2502 };
2503 return Err(self
2504 .diagnostics
2505 .report(identifier.stable_ptr(db), PathNotFound(item_type)));
2506 };
2507 if let Some(info) = self.resolver.resolve_item_in_module_or_expanded_macro(module_id, ident)
2509 && !matches!(self.resolution_context, ResolutionContext::ModuleItem(id) if id == info.item_id)
2510 {
2511 return Ok(ResolvedBase::Module(module_id));
2512 }
2513
2514 if ident.long(db) == CRATE_KW {
2516 return Ok(ResolvedBase::Crate(self.resolver.active_owning_crate_id(&self.macro_info)));
2517 }
2518 if let Some(dep) = self
2521 .resolver
2522 .active_settings(&self.macro_info)
2523 .dependencies
2524 .get(ident.long(db).as_str())
2525 {
2526 let dep_crate_id =
2527 CrateLongId::Real { name: ident, discriminator: dep.discriminator.clone() }
2528 .intern(db);
2529 let configs = db.crate_configs();
2530 if !configs.contains_key(&dep_crate_id) {
2531 let get_long_id = |crate_id: CrateId<'db>| crate_id.long(db);
2532 panic!(
2533 "Invalid crate dependency: {:?}\nconfigured crates: {:#?}",
2534 get_long_id(dep_crate_id),
2535 configs.keys().cloned().map(get_long_id).collect_vec()
2536 );
2537 }
2538
2539 return Ok(ResolvedBase::Crate(dep_crate_id));
2540 }
2541 if ident.long(db) == CORELIB_CRATE_NAME {
2543 return Ok(ResolvedBase::Crate(CrateId::core(db)));
2544 }
2545 if ident.long(db) == STARKNET_CRATE_NAME {
2547 return Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)));
2549 }
2550 match self.resolver.resolve_path_using_use_star(module_id, ident) {
2552 UseStarResult::UniquePathFound(inner_module_item) => {
2553 return Ok(ResolvedBase::FoundThroughGlobalUse {
2554 item_info: inner_module_item,
2555 containing_module: module_id,
2556 });
2557 }
2558 UseStarResult::AmbiguousPath(module_items) => {
2559 return Ok(ResolvedBase::Ambiguous(module_items));
2560 }
2561 UseStarResult::PathNotFound => {}
2562 UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
2563 let prelude = self.resolver.prelude_submodule_ex(&self.macro_info);
2564 if let Ok(Some(_)) = db.module_item_by_name(prelude, ident) {
2565 return Ok(ResolvedBase::Module(prelude));
2566 }
2567 return Ok(ResolvedBase::ItemNotVisible(module_item_id, containing_modules));
2568 }
2569 }
2570 Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)))
2571 }
2572 fn validate_module_item_usability(
2575 &mut self,
2576 containing_module_id: ModuleId<'db>,
2577 identifier: &ast::TerminalIdentifier<'db>,
2578 item_info: &ModuleItemInfo<'db>,
2579 ) {
2580 if !self.resolver.is_item_visible_ex(
2581 containing_module_id,
2582 item_info,
2583 self.resolver.active_module_id(&self.macro_info),
2584 &self.macro_info,
2585 ) {
2586 self.diagnostics.report(
2587 identifier.stable_ptr(self.resolver.db),
2588 ItemNotVisible(item_info.item_id, vec![]),
2589 );
2590 }
2591
2592 self.resolver.validate_feature_constraints(self.diagnostics, identifier, item_info);
2593 }
2594}