cairo_lang_semantic/resolve/
mod.rs

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