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