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