Skip to main content

cairo_lang_semantic/resolve/
mod.rs

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