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, Member, Mutability, TypeId, TypeLongId,
81};
82
83#[cfg(test)]
84mod test;
85
86mod item;
87
88// Remove when this becomes an actual crate.
89const STARKNET_CRATE_NAME: &str = "starknet";
90
91/// Lookback maps for item resolving. Can be used to quickly check what is the semantic resolution
92/// of any path segment.
93#[derive(Clone, Default, Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
94#[debug_db(dyn Database)]
95pub struct ResolvedItems<'db> {
96    pub concrete: UnorderedHashMap<ast::TerminalIdentifierPtr<'db>, ResolvedConcreteItem<'db>>,
97    pub generic: UnorderedHashMap<ast::TerminalIdentifierPtr<'db>, ResolvedGenericItem<'db>>,
98}
99impl<'db> ResolvedItems<'db> {
100    // Relates a path segment to a ResolvedConcreteItem, and adds to a resolved_items map. This will
101    // be used in "Go to definition".
102    pub fn mark_concrete(
103        &mut self,
104        db: &'db dyn Database,
105        segment: &syntax::node::ast::PathSegment<'db>,
106        resolved_item: ResolvedConcreteItem<'db>,
107    ) -> ResolvedConcreteItem<'db> {
108        let identifier = segment.identifier_ast(db);
109        if let Some(generic_item) = resolved_item.generic(db) {
110            // Mark the generic item as well, for language server resolved_items.
111            self.generic.insert(identifier.stable_ptr(db), generic_item);
112        }
113        self.concrete.insert(identifier.stable_ptr(db), resolved_item.clone());
114        resolved_item
115    }
116    // Relates a path segment to a ResolvedGenericItem, and adds to a resolved_items map. This will
117    // be used in "Go to definition".
118    pub fn mark_generic(
119        &mut self,
120        db: &'db dyn Database,
121        segment: &syntax::node::ast::PathSegment<'db>,
122        resolved_item: ResolvedGenericItem<'db>,
123    ) -> ResolvedGenericItem<'db> {
124        let identifier = segment.identifier_ast(db);
125        self.generic.insert(identifier.stable_ptr(db), resolved_item.clone());
126        resolved_item
127    }
128}
129
130/// The enriched members of a type, including direct members of structs, as well as members of
131/// targets of `Deref` and `DerefMut` of the type.
132#[derive(Debug, PartialEq, Eq, DebugWithDb, Clone, salsa::Update)]
133#[debug_db(dyn Database)]
134pub struct EnrichedMembers<'db> {
135    /// A map from member names to their semantic representation and the number of deref operations
136    /// needed to access them.
137    pub members: OrderedHashMap<SmolStrId<'db>, (Member<'db>, usize)>,
138    /// The sequence of deref needed to access the members.
139    pub deref_chain: Arc<Vec<DerefInfo<'db>>>,
140    // The number of derefs that were explored.
141    pub explored_derefs: usize,
142}
143impl<'db> EnrichedMembers<'db> {
144    /// Returns `EnrichedTypeMemberAccess` for a single member if exists.
145    pub fn get_member(&self, name: SmolStrId<'db>) -> Option<EnrichedTypeMemberAccess<'db>> {
146        let (member, n_derefs) = self.members.get(&name)?;
147        Some(EnrichedTypeMemberAccess {
148            member: member.clone(),
149            deref_functions: self
150                .deref_chain
151                .iter()
152                .map(|deref_info| (deref_info.function_id, deref_info.self_mutability))
153                .take(*n_derefs)
154                .collect(),
155        })
156    }
157}
158
159/// The enriched member of a type, including the member itself and the deref functions needed to
160/// access it.
161pub struct EnrichedTypeMemberAccess<'db> {
162    /// The member itself.
163    pub member: Member<'db>,
164    /// The sequence of deref functions needed to access the member.
165    pub deref_functions: Vec<(FunctionId<'db>, Mutability)>,
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, DebugWithDb)]
169#[debug_db(dyn Database)]
170enum MacroContextModifier {
171    /// The path is resolved in the macro definition site.
172    DefSite,
173    /// The path is resolved in the macro call site.
174    CallSite,
175    /// No modifier, the path is resolved in the current resolver context.
176    None,
177}
178
179#[derive(Debug, PartialEq, Eq, DebugWithDb, salsa::Update)]
180#[debug_db(dyn Database)]
181pub struct ResolverData<'db> {
182    /// Current module in which to resolve the path.
183    pub module_id: ModuleId<'db>,
184    /// Named generic parameters accessible to the resolver.
185    generic_param_by_name: OrderedHashMap<SmolStrId<'db>, GenericParamId<'db>>,
186    /// All generic parameters accessible to the resolver.
187    pub generic_params: Vec<GenericParamId<'db>>,
188    /// The enriched members per type and its mutability in the resolver context.
189    pub type_enriched_members: OrderedHashMap<(TypeId<'db>, bool), EnrichedMembers<'db>>,
190    /// Lookback map for resolved identifiers in path. Used in "Go to definition".
191    pub resolved_items: ResolvedItems<'db>,
192    /// Inference data for the resolver.
193    pub inference_data: InferenceData<'db>,
194    /// The trait/impl context the resolver is currently in. Used to resolve "Self::" paths.
195    pub trait_or_impl_ctx: TraitOrImplContext<'db>,
196    /// The configuration of allowed features.
197    pub feature_config: FeatureConfig<'db>,
198    /// The set of used `use` items in the current context.
199    pub used_uses: OrderedHashSet<UseId<'db>>,
200    /// Virtual files generated during inline macro expansion.
201    pub files: Vec<FileId<'db>>,
202}
203impl<'db> ResolverData<'db> {
204    pub fn new(module_id: ModuleId<'db>, inference_id: InferenceId<'db>) -> Self {
205        Self {
206            module_id,
207            generic_param_by_name: Default::default(),
208            generic_params: Default::default(),
209            type_enriched_members: Default::default(),
210            resolved_items: Default::default(),
211            inference_data: InferenceData::new(inference_id),
212            trait_or_impl_ctx: TraitOrImplContext::None,
213            feature_config: Default::default(),
214            used_uses: Default::default(),
215            files: vec![],
216        }
217    }
218    pub fn clone_with_inference_id(
219        &self,
220        db: &'db dyn Database,
221        inference_id: InferenceId<'db>,
222    ) -> Self {
223        Self {
224            module_id: self.module_id,
225            generic_param_by_name: self.generic_param_by_name.clone(),
226            generic_params: self.generic_params.clone(),
227            type_enriched_members: self.type_enriched_members.clone(),
228            resolved_items: self.resolved_items.clone(),
229            inference_data: self.inference_data.clone_with_inference_id(db, inference_id),
230            trait_or_impl_ctx: self.trait_or_impl_ctx,
231            feature_config: self.feature_config.clone(),
232            used_uses: self.used_uses.clone(),
233            files: self.files.clone(),
234        }
235    }
236}
237
238/// Resolving data needed for resolving macro expanded code in the correct context.
239#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
240pub struct ResolverMacroData<'db> {
241    /// The module file id of the macro definition site. It is used if the path begins with
242    /// `$defsite`.
243    pub defsite_module_id: ModuleId<'db>,
244    /// The module file id of the macro call site. Items are resolved in this context in two cases:
245    /// 1. The path begins with `$callsite`.
246    /// 2. The path was supplied as a macro argument. In other words, the path is an expansion of a
247    ///    placeholder and is not a part of the macro expansion template.
248    pub callsite_module_id: ModuleId<'db>,
249    /// This is the mappings of the macro expansion. It is used to determine if a part of the
250    /// code came from a macro argument or from the macro expansion template.
251    pub expansion_mappings: Arc<[CodeMapping]>,
252    /// The parent macro data. Exists in case of a macro calling another macro, and is used if we
253    /// climb to the callsite environment.
254    pub parent_macro_call_data: Option<Arc<ResolverMacroData<'db>>>,
255}
256
257/// Information for resolving a path in a macro context.
258struct MacroResolutionInfo<'db> {
259    /// The module where the resolved path is defined.
260    base: ModuleId<'db>,
261    /// The macro call data of the current resolution.
262    data: Option<Arc<ResolverMacroData<'db>>>,
263    /// The macro context modifier.
264    modifier: MacroContextModifier,
265}
266impl<'db> MacroResolutionInfo<'db> {
267    fn from_resolver(resolver: &Resolver<'db>) -> Self {
268        Self {
269            base: resolver.data.module_id,
270            data: resolver.macro_call_data.clone(),
271            modifier: MacroContextModifier::None,
272        }
273    }
274}
275
276/// Resolves paths semantically.
277pub struct Resolver<'db> {
278    db: &'db dyn Database,
279    pub data: ResolverData<'db>,
280    /// The resolving context for macro related resolving. Should be `Some` only if the current
281    /// code is an expansion of a macro.
282    pub macro_call_data: Option<Arc<ResolverMacroData<'db>>>,
283    /// If true, allow resolution of path through the module definition, without a modifier.
284    /// Should be true only within plugin macros generated code, or item macro call generated code.
285    pub default_module_allowed: bool,
286    pub owning_crate_id: CrateId<'db>,
287    pub settings: CrateSettings,
288}
289impl<'db> Deref for Resolver<'db> {
290    type Target = ResolverData<'db>;
291
292    fn deref(&self) -> &Self::Target {
293        &self.data
294    }
295}
296impl DerefMut for Resolver<'_> {
297    fn deref_mut(&mut self) -> &mut Self::Target {
298        &mut self.data
299    }
300}
301impl<'db> Resolver<'db> {
302    /// Extracts the allowed node from the syntax, and sets it as the allowed features of the
303    /// resolver.
304    pub fn set_feature_config(
305        &mut self,
306        element_id: &impl LanguageElementId<'db>,
307        syntax: &impl QueryAttrs<'db>,
308        diagnostics: &mut SemanticDiagnostics<'db>,
309    ) {
310        self.feature_config =
311            feature_config_from_item_and_parent_modules(self.db, element_id, syntax, diagnostics);
312    }
313
314    /// Extends the current feature config with the contents of those extracted from the given item,
315    /// returns the original feature config for restoring it later.
316    /// IMPORTANT: don't forget to call `restore_feature_config`!
317    pub fn extend_feature_config_from_item(
318        &mut self,
319        db: &'db dyn Database,
320        crate_id: CrateId<'db>,
321        diagnostics: &mut SemanticDiagnostics<'db>,
322        item: &impl QueryAttrs<'db>,
323    ) -> FeatureConfigRestore<'db> {
324        self.data.feature_config.override_with(feature_config_from_ast_item(
325            db,
326            crate_id,
327            item,
328            diagnostics,
329        ))
330    }
331
332    /// Restores the feature config to its state before [Self::extend_feature_config_from_item],
333    /// using the restoration state returned by that method.
334    pub fn restore_feature_config(&mut self, restore: FeatureConfigRestore<'db>) {
335        self.data.feature_config.restore(restore);
336    }
337}
338
339pub enum ResolutionContext<'a, 'mt> {
340    /// Default resolution.
341    Default,
342    /// The resolution is of a module item.
343    ModuleItem(ModuleItemId<'a>),
344    /// The resolution is in a statement environment.
345    Statement(&'mt mut Environment<'a>),
346}
347
348/// The result of resolving an item using `use *` imports.
349enum UseStarResult<'db> {
350    /// A unique path was found, considering only the `use *` imports.
351    UniquePathFound(ModuleItemInfo<'db>),
352    /// The path is ambiguous, considering only the `use *` imports.
353    AmbiguousPath(Vec<ModuleItemId<'db>>),
354    /// The path was not found, considering only the `use *` imports.
355    PathNotFound,
356    /// Item is not visible in the current module, considering only the `use *` imports.
357    ItemNotVisible(ModuleItemId<'db>, Vec<ModuleId<'db>>),
358}
359
360/// A trait for things that can be interpreted as a path of segments.
361pub trait AsSegments<'db> {
362    fn to_segments(self, db: &'db dyn Database) -> Vec<ast::PathSegment<'db>>;
363    /// Returns placeholder marker `$` if the path prefixed with one, indicating a resolver site
364    /// modifier.
365    fn placeholder_marker(&self, db: &'db dyn Database) -> Option<ast::TerminalDollar<'db>>;
366    /// The offset of the path in the file.
367    fn offset(&self, db: &'db dyn Database) -> Option<TextOffset>;
368}
369impl<'db> AsSegments<'db> for &ast::ExprPath<'db> {
370    fn to_segments(self, db: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
371        self.segments(db).elements_vec(db)
372    }
373    fn placeholder_marker(&self, db: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
374        match self.dollar(db) {
375            ast::OptionTerminalDollar::Empty(_) => None,
376            ast::OptionTerminalDollar::TerminalDollar(dollar) => Some(dollar),
377        }
378    }
379
380    fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
381        Some(self.as_syntax_node().offset(db))
382    }
383}
384impl<'db> AsSegments<'db> for Vec<ast::PathSegment<'db>> {
385    fn to_segments(self, _: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
386        self
387    }
388    fn placeholder_marker(&self, _: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
389        // A dollar can prefix only the first segment of a path, thus irrelevant to a list of
390        // segments.
391        None
392    }
393    fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
394        self.first().map(|segment| segment.as_syntax_node().offset(db))
395    }
396}
397impl<'db> AsSegments<'db> for UseAsPathSegments<'db> {
398    fn to_segments(self, _: &'db dyn Database) -> Vec<ast::PathSegment<'db>> {
399        self.segments
400    }
401
402    fn placeholder_marker(&self, _: &'db dyn Database) -> Option<ast::TerminalDollar<'db>> {
403        self.is_placeholder.clone()
404    }
405
406    fn offset(&self, db: &'db dyn Database) -> Option<TextOffset> {
407        if let Some(ref dollar) = self.is_placeholder {
408            Some(dollar.as_syntax_node().offset(db))
409        } else {
410            self.segments.first().map(|segment| segment.as_syntax_node().offset(db))
411        }
412    }
413}
414
415impl<'db> Resolver<'db> {
416    pub fn new(
417        db: &'db dyn Database,
418        module_id: ModuleId<'db>,
419        inference_id: InferenceId<'db>,
420    ) -> Self {
421        Self::with_data(db, ResolverData::new(module_id, inference_id))
422    }
423
424    pub fn with_data(db: &'db dyn Database, data: ResolverData<'db>) -> Self {
425        let owning_crate_id = data.module_id.owning_crate(db);
426        let macro_call_data = match data.module_id {
427            ModuleId::CrateRoot(_) | ModuleId::Submodule(_) => None,
428            ModuleId::MacroCall { id, .. } => match db.priv_macro_call_data(id) {
429                Ok(data) => Some(
430                    ResolverMacroData {
431                        defsite_module_id: data.defsite_module_id,
432                        callsite_module_id: data.callsite_module_id,
433                        expansion_mappings: data.expansion_mappings.clone(),
434                        parent_macro_call_data: data.parent_macro_call_data,
435                    }
436                    .into(),
437                ),
438                Err(_) => None,
439            },
440        };
441        Self {
442            owning_crate_id,
443            settings: db
444                .crate_config(owning_crate_id)
445                .map(|c| c.settings.clone())
446                .unwrap_or_default(),
447            db,
448            data,
449            default_module_allowed: macro_call_data.is_some(),
450            macro_call_data,
451        }
452    }
453
454    pub fn inference(&mut self) -> Inference<'db, '_> {
455        self.data.inference_data.inference(self.db)
456    }
457
458    /// Adds a generic param to an existing resolver.
459    /// This is required since a resolver needs to exist before resolving the generic params,
460    /// and thus, they are added to the Resolver only after they are resolved.
461    pub fn add_generic_param(&mut self, generic_param_id: GenericParamId<'db>) {
462        self.generic_params.push(generic_param_id);
463        if let Some(name) = generic_param_id.name(self.db) {
464            self.generic_param_by_name.insert(name, generic_param_id);
465        }
466    }
467
468    pub fn set_default_module_allowed(&mut self, default_module_allowed: bool) {
469        self.default_module_allowed = default_module_allowed;
470    }
471
472    /// Return the module_id, with respect to the macro context modifier, see
473    /// [`MacroContextModifier`].
474    fn active_module_id(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
475        if let Some(data) = &info.data {
476            match info.modifier {
477                MacroContextModifier::DefSite => data.defsite_module_id,
478                MacroContextModifier::CallSite => data.callsite_module_id,
479                MacroContextModifier::None => info.base,
480            }
481        } else {
482            assert_eq!(info.modifier, MacroContextModifier::None);
483            info.base
484        }
485    }
486
487    /// Return the module_id, with respect to the macro context modifier, see
488    /// [`MacroContextModifier`].
489    fn try_get_active_module_id(&self, info: &MacroResolutionInfo<'db>) -> Option<ModuleId<'db>> {
490        if let Some(data) = &info.data {
491            match info.modifier {
492                MacroContextModifier::DefSite => Some(data.defsite_module_id),
493                MacroContextModifier::CallSite => Some(data.callsite_module_id),
494                MacroContextModifier::None => (data.callsite_module_id != info.base
495                    || self.default_module_allowed)
496                    .then_some(info.base),
497            }
498        } else {
499            Some(info.base)
500        }
501    }
502
503    /// Returns the owning crate id of the active module file id, with respect to the macro context
504    /// modifier, see [`MacroContextModifier`].
505    fn active_owning_crate_id(&self, info: &MacroResolutionInfo<'db>) -> CrateId<'db> {
506        self.active_module_id(info).owning_crate(self.db)
507    }
508
509    /// Returns the active settings of the owning crate, with respect to the macro context
510    /// modifier, see [`MacroContextModifier`].
511    fn active_settings(&self, info: &MacroResolutionInfo<'db>) -> &CrateSettings {
512        self.db
513            .crate_config(self.active_owning_crate_id(info))
514            .map(|c| &c.settings)
515            .unwrap_or_else(|| default_crate_settings(self.db))
516    }
517
518    /// Resolves a concrete item, given a path.
519    /// Guaranteed to result in at most one diagnostic.
520    /// Item not inside a statement.
521    pub fn resolve_concrete_path(
522        &mut self,
523        diagnostics: &mut SemanticDiagnostics<'db>,
524        path: impl AsSegments<'db>,
525        item_type: NotFoundItemType,
526    ) -> Maybe<ResolvedConcreteItem<'db>> {
527        self.resolve_concrete_path_ex(diagnostics, path, item_type, ResolutionContext::Default)
528    }
529
530    /// Resolves a concrete item, given a path.
531    /// Guaranteed to result in at most one diagnostic.
532    pub fn resolve_concrete_path_ex(
533        &mut self,
534        diagnostics: &mut SemanticDiagnostics<'db>,
535        path: impl AsSegments<'db>,
536        item_type: NotFoundItemType,
537        ctx: ResolutionContext<'db, '_>,
538    ) -> Maybe<ResolvedConcreteItem<'db>> {
539        Resolution::new(self, diagnostics, path, item_type, ctx)?.full::<ResolvedConcreteItem<'db>>(
540            ResolutionCallbacks {
541                _phantom: PhantomData,
542                first: |resolution| resolution.first_concrete(),
543                next: |resolution, item, segment| resolution.next_concrete(item, segment),
544                validate: |_, _| Ok(()),
545                mark: |resolved_items: &mut ResolvedItems<'db>, db, segment, item| {
546                    resolved_items.mark_concrete(db, segment, item);
547                },
548            },
549        )
550    }
551
552    /// Resolves a generic item, given a path.
553    /// Guaranteed to result in at most one diagnostic.
554    pub fn resolve_generic_path(
555        &mut self,
556        diagnostics: &mut SemanticDiagnostics<'db>,
557        path: impl AsSegments<'db>,
558        item_type: NotFoundItemType,
559        ctx: ResolutionContext<'db, '_>,
560    ) -> Maybe<ResolvedGenericItem<'db>> {
561        self.resolve_generic_path_inner(diagnostics, path, item_type, false, ctx)
562    }
563
564    /// Resolves a plugin macro, given a path.
565    /// Guaranteed to result in at most one diagnostic.
566    pub fn resolve_plugin_macro(
567        &mut self,
568        path: &ast::ExprPath<'db>,
569        ctx: ResolutionContext<'db, '_>,
570    ) -> Option<InlineMacroExprPluginId<'db>> {
571        let mut diagnostics = SemanticDiagnostics::new(self.module_id);
572        let resolution =
573            Resolution::new(self, &mut diagnostics, path, NotFoundItemType::Macro, ctx).ok()?;
574        let macro_name = resolution.segments.exactly_one().ok()?;
575        let macro_info = resolution.macro_info;
576        let crate_id = self.active_owning_crate_id(&macro_info);
577        let db = self.db;
578        db.crate_inline_macro_plugins(crate_id)
579            .get(macro_name.identifier(db).long(db).as_str())
580            .cloned()
581    }
582
583    /// Resolves a generic item from a `use` statement path.
584    ///
585    /// Useful for resolving paths from `use` items and statements.
586    pub fn resolve_use_path(
587        &mut self,
588        diagnostics: &mut SemanticDiagnostics<'db>,
589        use_path: ast::UsePath<'db>,
590        ctx: ResolutionContext<'db, '_>,
591    ) -> Maybe<ResolvedGenericItem<'db>> {
592        let mut segments = get_use_path_segments(self.db, use_path.clone())?;
593        // Remove the last segment if it's `self`.
594        if let Some(last) = segments.segments.last()
595            && last.identifier(self.db).long(self.db) == SELF_PARAM_KW
596        {
597            // If the `self` keyword is used in a non-multi-use path, report an error.
598            if use_path.as_syntax_node().parent_kind(self.db).unwrap() != SyntaxKind::UsePathList {
599                diagnostics.report(use_path.stable_ptr(self.db), UseSelfNonMulti);
600            }
601            segments.segments.pop();
602        }
603        if segments.segments.is_empty() {
604            return Err(diagnostics.report(use_path.stable_ptr(self.db), UseSelfEmptyPath));
605        }
606        self.resolve_generic_path(diagnostics, segments, NotFoundItemType::Identifier, ctx)
607    }
608
609    /// Resolves a generic item, given a concrete item path, while ignoring the generic args.
610    /// Guaranteed to result in at most one diagnostic.
611    pub fn resolve_generic_path_with_args(
612        &mut self,
613        diagnostics: &mut SemanticDiagnostics<'db>,
614        path: impl AsSegments<'db>,
615        item_type: NotFoundItemType,
616        ctx: ResolutionContext<'db, '_>,
617    ) -> Maybe<ResolvedGenericItem<'db>> {
618        self.resolve_generic_path_inner(diagnostics, path, item_type, true, ctx)
619    }
620
621    /// Resolves a generic item, given a path.
622    /// Guaranteed to result in at most one diagnostic.
623    /// If `allow_generic_args` is true a path with generic args will be processed, but the generic
624    /// params will be ignored.
625    fn resolve_generic_path_inner(
626        &mut self,
627        diagnostics: &mut SemanticDiagnostics<'db>,
628        path: impl AsSegments<'db>,
629        item_type: NotFoundItemType,
630        allow_generic_args: bool,
631        ctx: ResolutionContext<'db, '_>,
632    ) -> Maybe<ResolvedGenericItem<'db>> {
633        let validate = |diagnostics: &mut SemanticDiagnostics<'db>,
634                        segment: &ast::PathSegment<'db>| {
635            match segment {
636                ast::PathSegment::WithGenericArgs(generic_args) if !allow_generic_args => {
637                    Err(diagnostics.report(generic_args.stable_ptr(self.db), UnexpectedGenericArgs))
638                }
639                _ => Ok(()),
640            }
641        };
642        Resolution::new(self, diagnostics, path, item_type, ctx)?.full::<ResolvedGenericItem<'_>>(
643            ResolutionCallbacks {
644                _phantom: PhantomData,
645                first: |resolution| resolution.first_generic(allow_generic_args),
646                next: |resolution, item, segment| resolution.next_generic(item, segment),
647                validate,
648                mark: |resolved_items, db, segment, item| {
649                    resolved_items.mark_generic(db, segment, item);
650                },
651            },
652        )
653    }
654
655    /// Specializes a ResolvedGenericItem that came from a ModuleItem.
656    fn specialize_generic_module_item(
657        &mut self,
658        diagnostics: &mut SemanticDiagnostics<'db>,
659        identifier: &syntax::node::ast::TerminalIdentifier<'db>,
660        generic_item: ResolvedGenericItem<'db>,
661        generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
662    ) -> Maybe<ResolvedConcreteItem<'db>> {
663        let db: &'db dyn Database = self.db;
664        Ok(match generic_item {
665            ResolvedGenericItem::GenericConstant(id) => {
666                ResolvedConcreteItem::Constant(db.constant_const_value(id)?)
667            }
668            ResolvedGenericItem::Module(module_id) => {
669                if generic_args_syntax.is_some() {
670                    return Err(
671                        diagnostics.report(identifier.stable_ptr(db), UnexpectedGenericArgs)
672                    );
673                }
674                ResolvedConcreteItem::Module(module_id)
675            }
676            ResolvedGenericItem::GenericFunction(generic_function) => {
677                ResolvedConcreteItem::Function(self.specialize_function(
678                    diagnostics,
679                    identifier.stable_ptr(db).untyped(),
680                    generic_function,
681                    &generic_args_syntax.unwrap_or_default(),
682                )?)
683            }
684            ResolvedGenericItem::GenericType(generic_type) => {
685                ResolvedConcreteItem::Type(self.specialize_type(
686                    diagnostics,
687                    identifier.stable_ptr(db).untyped(),
688                    generic_type,
689                    &generic_args_syntax.unwrap_or_default(),
690                )?)
691            }
692            ResolvedGenericItem::GenericTypeAlias(module_type_alias_id) => {
693                let ty = self.db.module_type_alias_resolved_type(module_type_alias_id)?;
694                let generic_params =
695                    self.db.module_type_alias_generic_params(module_type_alias_id)?;
696                let generic_args = self.resolve_generic_args(
697                    diagnostics,
698                    GenericSubstitution::default(),
699                    &generic_params,
700                    &generic_args_syntax.unwrap_or_default(),
701                    identifier.stable_ptr(db).untyped(),
702                )?;
703                ResolvedConcreteItem::Type(
704                    GenericSubstitution::new(&generic_params, &generic_args).substitute(db, ty)?,
705                )
706            }
707            ResolvedGenericItem::GenericImplAlias(impl_alias_id) => {
708                let impl_id = db.impl_alias_resolved_impl(impl_alias_id)?;
709                let generic_params = db.impl_alias_generic_params(impl_alias_id)?;
710                let generic_args = self.resolve_generic_args(
711                    diagnostics,
712                    GenericSubstitution::default(),
713                    &generic_params,
714                    &generic_args_syntax.unwrap_or_default(),
715                    identifier.stable_ptr(db).untyped(),
716                )?;
717                ResolvedConcreteItem::Impl(
718                    GenericSubstitution::new(&generic_params, &generic_args)
719                        .substitute(db, impl_id)?,
720                )
721            }
722            ResolvedGenericItem::Trait(trait_id) => {
723                ResolvedConcreteItem::Trait(self.specialize_trait(
724                    diagnostics,
725                    identifier.stable_ptr(db).untyped(),
726                    trait_id,
727                    &generic_args_syntax.unwrap_or_default(),
728                )?)
729            }
730            ResolvedGenericItem::Impl(impl_def_id) => ResolvedConcreteItem::Impl(
731                ImplLongId::Concrete(self.specialize_impl(
732                    diagnostics,
733                    identifier.stable_ptr(db).untyped(),
734                    impl_def_id,
735                    &generic_args_syntax.unwrap_or_default(),
736                )?)
737                .intern(self.db),
738            ),
739            ResolvedGenericItem::Macro(macro_declaration_id) => {
740                ResolvedConcreteItem::Macro(macro_declaration_id)
741            }
742            ResolvedGenericItem::Variant(var) => {
743                ResolvedConcreteItem::Variant(self.specialize_variant(
744                    diagnostics,
745                    identifier.stable_ptr(db).untyped(),
746                    var.id,
747                    &generic_args_syntax.unwrap_or_default(),
748                )?)
749            }
750            ResolvedGenericItem::Variable(_) => panic!("Variable is not a module item."),
751            ResolvedGenericItem::TraitItem(id) => {
752                panic!("`{}` is not a module item.", id.full_path(db))
753            }
754        })
755    }
756
757    /// Resolves an item using the `use *` imports.
758    fn resolve_path_using_use_star(
759        &mut self,
760        module_id: ModuleId<'db>,
761        ident: SmolStrId<'db>,
762    ) -> UseStarResult<'db> {
763        let mut item_info = None;
764        let mut module_items_found: OrderedHashSet<ModuleItemId<'_>> = OrderedHashSet::default();
765        let mut other_containing_modules = vec![];
766        for (item_module_id, info) in self.db.module_imported_modules((), module_id).iter() {
767            // Not checking the main module to prevent cycles.
768            if *item_module_id == module_id {
769                continue;
770            }
771            if let Some(inner_item_info) =
772                self.resolve_item_in_module_or_expanded_macro(*item_module_id, ident)
773            {
774                if info.user_modules.iter().any(|user_module_id| {
775                    self.is_item_visible(*item_module_id, &inner_item_info, *user_module_id)
776                }) {
777                    item_info = Some(inner_item_info.clone());
778                    module_items_found.insert(inner_item_info.item_id);
779                } else {
780                    other_containing_modules.push(*item_module_id);
781                }
782            }
783        }
784        if module_items_found.len() > 1 {
785            return UseStarResult::AmbiguousPath(module_items_found.iter().cloned().collect());
786        }
787        match item_info {
788            Some(item_info) => UseStarResult::UniquePathFound(item_info),
789            None => {
790                for item_module_id in &other_containing_modules {
791                    if let Some(inner_item_info) =
792                        self.resolve_item_in_module_or_expanded_macro(*item_module_id, ident)
793                    {
794                        item_info = Some(inner_item_info.clone());
795                        module_items_found.insert(inner_item_info.item_id);
796                    }
797                }
798                if let Some(item_info) = item_info {
799                    if module_items_found.len() > 1 {
800                        UseStarResult::AmbiguousPath(module_items_found.iter().cloned().collect())
801                    } else {
802                        UseStarResult::ItemNotVisible(item_info.item_id, other_containing_modules)
803                    }
804                } else {
805                    UseStarResult::PathNotFound
806                }
807            }
808        }
809    }
810
811    /// Resolves an item in a module, checking direct items, macro expansions, and star uses.
812    ///
813    /// Returns `Some(info)` if the item is found uniquely, `None` otherwise (not found, ambiguous,
814    /// or not visible).
815    pub fn resolve_item_in_module(
816        &mut self,
817        module_id: ModuleId<'db>,
818        ident: SmolStrId<'db>,
819    ) -> Option<ModuleItemInfo<'db>> {
820        self.resolve_item_in_module_ex(module_id, ident).ok()
821    }
822
823    /// Resolves an item in a module, checking direct items, macro expansions, and star uses.
824    ///
825    /// Returns `SemanticDiagnosticKind` on failure. Note: `PathNotFound` uses
826    /// `NotFoundItemType::Identifier` as default; callers may need to adjust based on context.
827    fn resolve_item_in_module_ex(
828        &mut self,
829        module_id: ModuleId<'db>,
830        ident: SmolStrId<'db>,
831    ) -> Result<ModuleItemInfo<'db>, SemanticDiagnosticKind<'db>> {
832        if let Some(info) = self.resolve_item_in_module_or_expanded_macro(module_id, ident) {
833            return Ok(info);
834        }
835        match self.resolve_path_using_use_star(module_id, ident) {
836            UseStarResult::UniquePathFound(info) => Ok(info),
837            UseStarResult::AmbiguousPath(items) => Err(AmbiguousPath(items)),
838            UseStarResult::PathNotFound => Err(PathNotFound(NotFoundItemType::Identifier)),
839            UseStarResult::ItemNotVisible(item, modules) => Err(ItemNotVisible(item, modules)),
840        }
841    }
842
843    /// Resolves an item in a module and falls back to the expanded macro code of the module.
844    fn resolve_item_in_module_or_expanded_macro(
845        &mut self,
846        module_id: ModuleId<'db>,
847        ident: SmolStrId<'db>,
848    ) -> Option<ModuleItemInfo<'db>> {
849        if let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
850            self.insert_used_use(info.item_id);
851            return Some(info);
852        }
853        let mut stack = vec![(module_id, false)];
854        loop {
855            let (module_id, expose) = stack.pop()?;
856            if expose && let Ok(Some(info)) = self.db.module_item_info_by_name(module_id, ident) {
857                self.insert_used_use(info.item_id);
858                return Some(info);
859            }
860            if let Ok(macro_calls) = self.db.module_macro_calls_ids(module_id) {
861                for macro_call in macro_calls {
862                    if let Ok(macro_module_id) = self.db.macro_call_module_id(*macro_call) {
863                        let expose = expose
864                            || matches!(
865                                macro_module_id,
866                                ModuleId::MacroCall { is_expose: true, .. }
867                            );
868                        stack.push((macro_module_id, expose));
869                    }
870                }
871            }
872        }
873    }
874
875    /// Determines whether the first identifier of a path is a local item.
876    pub fn determine_base_item_in_local_scope(
877        &mut self,
878        identifier: &ast::TerminalIdentifier<'db>,
879    ) -> Option<ResolvedConcreteItem<'db>> {
880        let db = self.db;
881        let ident = identifier.text(db);
882
883        // If a generic param with this name is found, use it.
884        if let Some(generic_param_id) = self.data.generic_param_by_name.get(&ident) {
885            let item = match generic_param_id.kind(self.db) {
886                GenericKind::Type => ResolvedConcreteItem::Type(
887                    TypeLongId::GenericParameter(*generic_param_id).intern(self.db),
888                ),
889                GenericKind::Const => ResolvedConcreteItem::Constant(
890                    ConstValue::Generic(*generic_param_id).intern(self.db),
891                ),
892                GenericKind::Impl => ResolvedConcreteItem::Impl(
893                    ImplLongId::GenericParameter(*generic_param_id).intern(self.db),
894                ),
895                GenericKind::NegImpl => return None,
896            };
897            return Some(item);
898        }
899        // TODO(spapini): Resolve local variables.
900
901        None
902    }
903
904    pub fn prelude_submodule(&self) -> ModuleId<'db> {
905        self.prelude_submodule_ex(&MacroResolutionInfo::from_resolver(self))
906    }
907
908    /// Returns the crate's `prelude` submodule.
909    fn prelude_submodule_ex(&self, info: &MacroResolutionInfo<'db>) -> ModuleId<'db> {
910        let active_settings = self.active_settings(info);
911        self.db.get_prelude_submodule(active_settings).unwrap_or_else(|| {
912            panic!(
913                "expected prelude submodule `{}` not found in `core::prelude`.",
914                active_settings.edition.prelude_submodule_name(self.db).long(self.db)
915            )
916        })
917    }
918
919    /// Specializes a trait.
920    fn specialize_trait(
921        &mut self,
922        diagnostics: &mut SemanticDiagnostics<'db>,
923        stable_ptr: SyntaxStablePtrId<'db>,
924        trait_id: TraitId<'db>,
925        generic_args: &[ast::GenericArg<'db>],
926    ) -> Maybe<ConcreteTraitId<'db>> {
927        // TODO(lior): Should we report diagnostic if `trait_generic_params` failed?
928        let generic_params = self
929            .db
930            .trait_generic_params(trait_id)
931            .map_err(|_| diagnostics.report(stable_ptr, UnknownTrait))?;
932        let generic_args = self.resolve_generic_args(
933            diagnostics,
934            GenericSubstitution::default(),
935            generic_params,
936            generic_args,
937            stable_ptr,
938        )?;
939
940        Ok(ConcreteTraitLongId { trait_id, generic_args }.intern(self.db))
941    }
942
943    /// Specializes an impl.
944    fn specialize_impl(
945        &mut self,
946        diagnostics: &mut SemanticDiagnostics<'db>,
947        stable_ptr: SyntaxStablePtrId<'db>,
948        impl_def_id: ImplDefId<'db>,
949        generic_args: &[ast::GenericArg<'db>],
950    ) -> Maybe<ConcreteImplId<'db>> {
951        // TODO(lior): Should we report diagnostic if `impl_def_generic_params` failed?
952        let generic_params = self
953            .db
954            .impl_def_generic_params(impl_def_id)
955            .map_err(|_| diagnostics.report(stable_ptr, UnknownImpl))?;
956        let generic_args = self.resolve_generic_args(
957            diagnostics,
958            GenericSubstitution::default(),
959            generic_params,
960            generic_args,
961            stable_ptr,
962        )?;
963
964        Ok(ConcreteImplLongId { impl_def_id, generic_args }.intern(self.db))
965    }
966
967    /// Specializes a variant.
968    fn specialize_variant(
969        &mut self,
970        diagnostics: &mut SemanticDiagnostics<'db>,
971        stable_ptr: SyntaxStablePtrId<'db>,
972        variant_id: VariantId<'db>,
973        generic_args: &[ast::GenericArg<'db>],
974    ) -> Maybe<ConcreteVariant<'db>> {
975        let concrete_enum_id = ConcreteEnumLongId {
976            enum_id: variant_id.enum_id(self.db),
977            generic_args: self.resolve_generic_args(
978                diagnostics,
979                GenericSubstitution::default(),
980                self.db.enum_generic_params(variant_id.enum_id(self.db))?,
981                generic_args,
982                stable_ptr,
983            )?,
984        }
985        .intern(self.db);
986        self.db.concrete_enum_variant(
987            concrete_enum_id,
988            &self.db.variant_semantic(variant_id.enum_id(self.db), variant_id)?,
989        )
990    }
991
992    /// Specializes a generic function.
993    pub fn specialize_function(
994        &mut self,
995        diagnostics: &mut SemanticDiagnostics<'db>,
996        stable_ptr: SyntaxStablePtrId<'db>,
997        generic_function: GenericFunctionId<'db>,
998        generic_args: &[ast::GenericArg<'db>],
999    ) -> Maybe<FunctionId<'db>> {
1000        // TODO(lior): Should we report diagnostic if `impl_def_generic_params` failed?
1001        let generic_params = generic_function.generic_params(self.db)?;
1002        let generic_args = self.resolve_generic_args(
1003            diagnostics,
1004            GenericSubstitution::default(),
1005            generic_params,
1006            generic_args,
1007            stable_ptr,
1008        )?;
1009
1010        Ok(FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }
1011            .intern(self.db))
1012    }
1013
1014    /// Specializes a generic type.
1015    pub fn specialize_type(
1016        &mut self,
1017        diagnostics: &mut SemanticDiagnostics<'db>,
1018        stable_ptr: SyntaxStablePtrId<'db>,
1019        generic_type: GenericTypeId<'db>,
1020        generic_args: &[ast::GenericArg<'db>],
1021    ) -> Maybe<TypeId<'db>> {
1022        let generic_params = self
1023            .db
1024            .generic_type_generic_params(generic_type)
1025            .map_err(|_| diagnostics.report(stable_ptr, UnknownType))?;
1026        let generic_args = self.resolve_generic_args(
1027            diagnostics,
1028            GenericSubstitution::default(),
1029            generic_params,
1030            generic_args,
1031            stable_ptr,
1032        )?;
1033
1034        Ok(TypeLongId::Concrete(ConcreteTypeId::new(self.db, generic_type, generic_args))
1035            .intern(self.db))
1036    }
1037
1038    /// Returns the current impl lookup context.
1039    pub fn impl_lookup_context(&self) -> ImplLookupContextId<'db> {
1040        self.impl_lookup_context_ex(&MacroResolutionInfo::from_resolver(self))
1041    }
1042
1043    /// Returns the current impl lookup context, with respect to the macro context modifier,
1044    /// see [`MacroContextModifier`].
1045    fn impl_lookup_context_ex(&self, info: &MacroResolutionInfo<'db>) -> ImplLookupContextId<'db> {
1046        let mut lookup_context = ImplLookupContext::new(
1047            self.active_module_id(info),
1048            self.generic_params.clone(),
1049            self.db,
1050        );
1051
1052        if let TraitOrImplContext::Impl(impl_def_id) = &self.trait_or_impl_ctx {
1053            let Ok(generic_params) = self.db.impl_def_generic_params(*impl_def_id) else {
1054                return lookup_context.intern(self.db);
1055            };
1056            let generic_args = generic_params_to_args(generic_params, self.db);
1057            let impl_id: ConcreteImplId<'_> =
1058                ConcreteImplLongId { impl_def_id: *impl_def_id, generic_args }.intern(self.db);
1059            lookup_context.insert_impl(ImplLongId::Concrete(impl_id).intern(self.db), self.db);
1060        }
1061        lookup_context.intern(self.db)
1062    }
1063
1064    /// Resolves generic arguments.
1065    /// For each generic argument, if the syntax is provided, it will be resolved by the inference.
1066    /// Otherwise, resolved by type.
1067    pub fn resolve_generic_args(
1068        &mut self,
1069        diagnostics: &mut SemanticDiagnostics<'db>,
1070        mut substitution: GenericSubstitution<'db>,
1071        generic_params: &[GenericParam<'db>],
1072        generic_args_syntax: &[ast::GenericArg<'db>],
1073        stable_ptr: SyntaxStablePtrId<'db>,
1074    ) -> Maybe<Vec<GenericArgumentId<'db>>> {
1075        let mut resolved_args = vec![];
1076        let arg_syntax_per_param = self.get_arg_syntax_per_param(
1077            diagnostics,
1078            &generic_params.iter().map(|generic_param| generic_param.id()).collect_vec(),
1079            generic_args_syntax,
1080        )?;
1081
1082        for generic_param in generic_params {
1083            let generic_param = substitution.substitute(self.db, generic_param.clone())?;
1084            let generic_arg = self.resolve_generic_arg(
1085                &generic_param,
1086                arg_syntax_per_param
1087                    .get(&generic_param.id())
1088                    .filter(|expr| !matches!(expr, ast::Expr::Underscore(_))),
1089                stable_ptr,
1090                diagnostics,
1091            )?;
1092            resolved_args.push(generic_arg);
1093            substitution.insert(generic_param.id(), generic_arg);
1094        }
1095
1096        Ok(resolved_args)
1097    }
1098
1099    /// Returns a map of generic param id -> its assigned arg syntax.
1100    pub fn get_arg_syntax_per_param(
1101        &self,
1102        diagnostics: &mut SemanticDiagnostics<'db>,
1103        generic_params: &[GenericParamId<'db>],
1104        generic_args_syntax: &[ast::GenericArg<'db>],
1105    ) -> Maybe<UnorderedHashMap<GenericParamId<'db>, ast::Expr<'db>>> {
1106        let db = self.db;
1107        let mut arg_syntax_per_param =
1108            UnorderedHashMap::<GenericParamId<'_>, ast::Expr<'_>>::default();
1109        let mut last_named_arg_index = None;
1110        let generic_param_by_name = generic_params
1111            .iter()
1112            .enumerate()
1113            .filter_map(|(i, param)| Some((param.name(self.db)?, (i, param))))
1114            .collect::<UnorderedHashMap<_, _>>();
1115        for (idx, generic_arg_syntax) in generic_args_syntax.iter().enumerate() {
1116            match generic_arg_syntax {
1117                ast::GenericArg::Named(arg_syntax) => {
1118                    let name = arg_syntax.name(db).text(db);
1119                    let Some((index, generic_param_id)) = generic_param_by_name.get(&name) else {
1120                        return Err(diagnostics
1121                            .report(arg_syntax.stable_ptr(db), UnknownGenericParam(name)));
1122                    };
1123                    if let Some(prev_index) = last_named_arg_index
1124                        && prev_index > index
1125                    {
1126                        return Err(diagnostics
1127                            .report(arg_syntax.stable_ptr(db), GenericArgOutOfOrder(name)));
1128                    }
1129                    last_named_arg_index = Some(index);
1130                    if arg_syntax_per_param
1131                        .insert(**generic_param_id, arg_syntax.value(db))
1132                        .is_some()
1133                    {
1134                        return Err(diagnostics
1135                            .report(arg_syntax.stable_ptr(db), GenericArgDuplicate(name)));
1136                    }
1137                }
1138                ast::GenericArg::Unnamed(arg_syntax) => {
1139                    if last_named_arg_index.is_some() {
1140                        return Err(diagnostics
1141                            .report(arg_syntax.stable_ptr(db), PositionalGenericAfterNamed));
1142                    }
1143                    let generic_param = generic_params.get(idx).ok_or_else(|| {
1144                        diagnostics.report(
1145                            arg_syntax.stable_ptr(db),
1146                            TooManyGenericArguments {
1147                                expected: generic_params.len(),
1148                                actual: generic_args_syntax.len(),
1149                            },
1150                        )
1151                    })?;
1152                    assert_eq!(
1153                        arg_syntax_per_param.insert(*generic_param, arg_syntax.value(db)),
1154                        None,
1155                        "Unexpected duplication in ordered params."
1156                    );
1157                }
1158            }
1159        }
1160        Ok(arg_syntax_per_param)
1161    }
1162
1163    /// Resolves a generic argument.
1164    /// If no syntax Expr is provided, inference will be used.
1165    /// If a syntax Expr is provided, it will be resolved by type.
1166    fn resolve_generic_arg(
1167        &mut self,
1168        generic_param: &GenericParam<'db>,
1169        generic_arg_syntax_opt: Option<&ast::Expr<'db>>,
1170        stable_ptr: SyntaxStablePtrId<'db>,
1171        diagnostics: &mut SemanticDiagnostics<'db>,
1172    ) -> Result<GenericArgumentId<'db>, cairo_lang_diagnostics::DiagnosticAdded> {
1173        let Some(generic_arg_syntax) = generic_arg_syntax_opt else {
1174            let lookup_context = self.impl_lookup_context();
1175            let inference = &mut self.data.inference_data.inference(self.db);
1176            return inference
1177                .infer_generic_arg(generic_param, lookup_context, Some(stable_ptr))
1178                .map_err(|err_set| {
1179                    inference.report_on_pending_error(err_set, diagnostics, stable_ptr)
1180                });
1181        };
1182        let db = self.db;
1183        Ok(match generic_param {
1184            GenericParam::Type(_) => {
1185                GenericArgumentId::Type(resolve_type(db, diagnostics, self, generic_arg_syntax))
1186            }
1187            GenericParam::Const(const_param) => {
1188                // TODO(spapini): Currently no bound checks are performed. Move literal validation
1189                // to inference finalization and use inference here. This will become more relevant
1190                // when we support constant expressions, which need inference.
1191                let mut ctx = ComputationContext::new_global(db, diagnostics, self);
1192                let value = compute_expr_semantic(&mut ctx, generic_arg_syntax);
1193                GenericArgumentId::Constant(resolve_const_expr_and_evaluate(
1194                    db,
1195                    &mut ctx,
1196                    &value,
1197                    generic_arg_syntax.stable_ptr(db).untyped(),
1198                    const_param.ty,
1199                    false,
1200                ))
1201            }
1202
1203            GenericParam::Impl(param) => {
1204                let expr_path = try_extract_matches!(generic_arg_syntax, ast::Expr::Path)
1205                    .ok_or_else(|| {
1206                        diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1207                    })?;
1208                let resolved_impl = match self.resolve_concrete_path(
1209                    diagnostics,
1210                    expr_path,
1211                    NotFoundItemType::Impl,
1212                )? {
1213                    ResolvedConcreteItem::Impl(resolved_impl) => resolved_impl,
1214                    ResolvedConcreteItem::SelfTrait(concrete_trait_id) => {
1215                        ImplLongId::SelfImpl(concrete_trait_id).intern(self.db)
1216                    }
1217                    _ => {
1218                        return Err(
1219                            diagnostics.report(generic_arg_syntax.stable_ptr(db), UnknownImpl)
1220                        );
1221                    }
1222                };
1223                let impl_def_concrete_trait = self.db.impl_concrete_trait(resolved_impl)?;
1224                let expected_concrete_trait = param.concrete_trait?;
1225                if let Err(err_set) = self
1226                    .inference()
1227                    .conform_traits(impl_def_concrete_trait, expected_concrete_trait)
1228                {
1229                    let diag_added = diagnostics.report(
1230                        generic_arg_syntax.stable_ptr(db),
1231                        TraitMismatch {
1232                            expected_trt: expected_concrete_trait,
1233                            actual_trt: impl_def_concrete_trait,
1234                        },
1235                    );
1236                    self.inference().consume_reported_error(err_set, diag_added);
1237                } else {
1238                    for (trait_ty, ty1) in param.type_constraints.iter() {
1239                        let ty0 = TypeLongId::ImplType(ImplTypeId::new(
1240                            resolved_impl,
1241                            *trait_ty,
1242                            self.db,
1243                        ))
1244                        .intern(self.db);
1245                        let _ = self.inference().conform_ty(ty0, *ty1).map_err(|err_set| {
1246                            self.inference().report_on_pending_error(
1247                                err_set,
1248                                diagnostics,
1249                                stable_ptr,
1250                            )
1251                        });
1252                    }
1253                }
1254                GenericArgumentId::Impl(resolved_impl)
1255            }
1256            GenericParam::NegImpl(_) => {
1257                return Err(
1258                    diagnostics.report(generic_arg_syntax.stable_ptr(db), ArgPassedToNegativeImpl)
1259                );
1260            }
1261        })
1262    }
1263
1264    /// Should visibility checks not actually happen for lookups in this module.
1265    // TODO(orizi): Remove this check when performing a major Cairo update.
1266    pub fn ignore_visibility_checks(&self, module_id: ModuleId<'db>) -> bool {
1267        self.ignore_visibility_checks_ex(module_id, &MacroResolutionInfo::from_resolver(self))
1268    }
1269
1270    /// Same as [Self::ignore_visibility_checks], but takes into account the current macro context
1271    /// modifier.
1272    fn ignore_visibility_checks_ex(
1273        &self,
1274        module_id: ModuleId<'db>,
1275        info: &MacroResolutionInfo<'db>,
1276    ) -> bool {
1277        let module_crate = module_id.owning_crate(self.db);
1278        let module_edition =
1279            self.db.crate_config(module_crate).map(|c| c.settings.edition).unwrap_or_default();
1280        module_edition.ignore_visibility()
1281            || self.active_settings(info).edition.ignore_visibility()
1282                && module_crate == self.db.core_crate()
1283    }
1284
1285    /// Validates whether a given item is allowed based on its feature kind.
1286    /// This function checks if the item's feature kind is allowed in the current
1287    /// configuration. If the item uses an unstable, deprecated, or internal feature
1288    /// that is not permitted, a corresponding diagnostic error is reported.
1289    pub fn validate_feature_constraints<T: HasFeatureKind<'db>>(
1290        &self,
1291        diagnostics: &mut SemanticDiagnostics<'db>,
1292        identifier: &ast::TerminalIdentifier<'db>,
1293        item_info: &T,
1294    ) {
1295        let db = self.db;
1296        match item_info.feature_kind() {
1297            FeatureKind::Unstable { feature, note }
1298                if !self.data.feature_config.allowed_features.contains(feature) =>
1299            {
1300                diagnostics.report(
1301                    identifier.stable_ptr(db),
1302                    UnstableFeature { feature_name: *feature, note: *note },
1303                );
1304            }
1305            FeatureKind::Deprecated { feature, note }
1306                if !self
1307                    .data
1308                    .feature_config
1309                    .allowed_lints
1310                    .contains(&SmolStrId::from(self.db, DEPRECATED_ATTR))
1311                    && !self.data.feature_config.allowed_features.contains(feature) =>
1312            {
1313                diagnostics.report(
1314                    identifier.stable_ptr(db),
1315                    DeprecatedFeature { feature_name: *feature, note: *note },
1316                );
1317            }
1318            FeatureKind::Internal { feature, note }
1319                if !self.data.feature_config.allowed_features.contains(feature) =>
1320            {
1321                diagnostics.report(
1322                    identifier.stable_ptr(db),
1323                    InternalFeature { feature_name: *feature, note: *note },
1324                );
1325            }
1326            _ => {}
1327        }
1328    }
1329
1330    /// Checks if an item is visible from the current module.
1331    pub fn is_item_visible(
1332        &self,
1333        containing_module_id: ModuleId<'db>,
1334        item_info: &ModuleItemInfo<'db>,
1335        user_module: ModuleId<'db>,
1336    ) -> bool {
1337        self.is_item_visible_ex(
1338            containing_module_id,
1339            item_info,
1340            user_module,
1341            &MacroResolutionInfo::from_resolver(self),
1342        )
1343    }
1344
1345    /// Same as [Self::is_item_visible], but takes into account the current macro context modifier.
1346    fn is_item_visible_ex(
1347        &self,
1348        mut containing_module_id: ModuleId<'db>, // must never be a macro.
1349        item_info: &ModuleItemInfo<'db>,
1350        user_module: ModuleId<'db>,
1351        info: &MacroResolutionInfo<'db>,
1352    ) -> bool {
1353        let db = self.db;
1354        if containing_module_id == user_module {
1355            return true;
1356        }
1357        while let ModuleId::MacroCall { id, .. } = containing_module_id {
1358            containing_module_id = id.parent_module(self.db);
1359        }
1360        self.ignore_visibility_checks_ex(containing_module_id, info)
1361            || visibility::peek_visible_in(
1362                db,
1363                item_info.visibility,
1364                containing_module_id,
1365                user_module,
1366            )
1367    }
1368
1369    /// Inserts an item into the used uses set, if it is indeed a use.
1370    pub fn insert_used_use(&mut self, item_id: ModuleItemId<'db>) {
1371        if let ModuleItemId::Use(use_id) = item_id {
1372            self.data.used_uses.insert(use_id);
1373        }
1374    }
1375
1376    // TODO(yuval): on a breaking version change, consider changing warnings to errors.
1377    /// Warns about the use of a trait in a path inside the same trait or an impl of it, and the use
1378    /// of an impl in a path inside the same impl, additionally, converts a `Self` equivalent
1379    /// trait to be resolved as `Self`.
1380    /// That is, warns about using the actual path equivalent to `Self`, where `Self` can be used.
1381    fn handle_same_impl_trait(
1382        &mut self,
1383        diagnostics: &mut SemanticDiagnostics<'db>,
1384        specialized_item: &mut ResolvedConcreteItem<'db>,
1385        generic_args_syntax_slice: &[ast::GenericArg<'db>],
1386        segment_stable_ptr: SyntaxStablePtrId<'db>,
1387    ) {
1388        match *specialized_item {
1389            ResolvedConcreteItem::Trait(current_segment_concrete_trait) => {
1390                match self.trait_or_impl_ctx {
1391                    TraitOrImplContext::None => {}
1392                    TraitOrImplContext::Trait(ctx_trait) => {
1393                        if self
1394                            .warn_trait_in_same_trait(
1395                                diagnostics,
1396                                current_segment_concrete_trait.trait_id(self.db),
1397                                generic_args_syntax_slice,
1398                                ctx_trait,
1399                                segment_stable_ptr,
1400                            )
1401                            .is_err()
1402                        {
1403                            *specialized_item =
1404                                ResolvedConcreteItem::SelfTrait(current_segment_concrete_trait);
1405                        }
1406                    }
1407                    TraitOrImplContext::Impl(ctx_impl_def_id) => {
1408                        self.warn_trait_in_its_impl(
1409                            diagnostics,
1410                            current_segment_concrete_trait,
1411                            ctx_impl_def_id,
1412                            segment_stable_ptr,
1413                        )
1414                        .ok();
1415                    }
1416                };
1417            }
1418            ResolvedConcreteItem::Impl(current_segment_impl_id) => {
1419                if let TraitOrImplContext::Impl(ctx_impl) = self.trait_or_impl_ctx {
1420                    // A ResolvedConcreteItem::Impl returned by
1421                    // `specialize_generic_module_item` must be ImplLongId::Concrete.
1422                    let current_segment_concrete_impl_id = extract_matches!(
1423                        current_segment_impl_id.long(self.db),
1424                        ImplLongId::Concrete
1425                    );
1426                    self.warn_impl_in_same_impl(
1427                        diagnostics,
1428                        current_segment_concrete_impl_id.impl_def_id(self.db),
1429                        generic_args_syntax_slice,
1430                        ctx_impl,
1431                        segment_stable_ptr,
1432                    )
1433                    .ok();
1434                }
1435            }
1436            _ => {}
1437        };
1438    }
1439
1440    /// Raises a warning diagnostic (and returns an error) if the segment describes an impl in the
1441    /// context of that impl (that is, could be expressed as `Self`).
1442    fn warn_impl_in_same_impl(
1443        &mut self,
1444        diagnostics: &mut SemanticDiagnostics<'db>,
1445        current_segment_impl_def_id: ImplDefId<'db>,
1446        current_segment_generic_args: &[ast::GenericArg<'db>],
1447        ctx_impl: ImplDefId<'db>,
1448        segment_stable_ptr: SyntaxStablePtrId<'db>,
1449    ) -> Maybe<()> {
1450        if current_segment_impl_def_id != ctx_impl {
1451            return Ok(());
1452        }
1453
1454        let generic_params = self.db.impl_def_generic_params(ctx_impl)?;
1455        self.compare_segment_args_to_params(
1456            diagnostics,
1457            current_segment_generic_args,
1458            generic_params,
1459            segment_stable_ptr,
1460            ImplInImplMustBeExplicit,
1461            ImplItemForbiddenInTheImpl,
1462        )
1463    }
1464
1465    /// Raises a warning diagnostic (and returns an error) if the segment is of a concrete trait in
1466    /// the context of an impl of that concrete trait (that is, could be expressed as `Self`).
1467    fn warn_trait_in_its_impl(
1468        &mut self,
1469        diagnostics: &mut SemanticDiagnostics<'db>,
1470        current_segment_concrete_trait_id: ConcreteTraitId<'db>,
1471        impl_ctx: ImplDefId<'db>,
1472        segment_stable_ptr: SyntaxStablePtrId<'db>,
1473    ) -> Maybe<()> {
1474        let ctx_impl_trait = self.db.impl_def_trait(impl_ctx)?;
1475        if current_segment_concrete_trait_id.trait_id(self.db) != ctx_impl_trait {
1476            return Ok(());
1477        }
1478
1479        let ctx_impl_concrete_trait = self.db.impl_def_concrete_trait(impl_ctx)?;
1480        if ctx_impl_concrete_trait.generic_args(self.db)
1481            == current_segment_concrete_trait_id.generic_args(self.db)
1482        {
1483            return Err(diagnostics.report(segment_stable_ptr, TraitItemForbiddenInItsImpl));
1484        }
1485        Ok(())
1486    }
1487
1488    /// Raises a warning diagnostic (and returns an error) if the segment describes a trait in the
1489    /// context of that trait (that is, could be expressed as `Self`).
1490    fn warn_trait_in_same_trait(
1491        &mut self,
1492        diagnostics: &mut SemanticDiagnostics<'db>,
1493        current_segment_trait_id: TraitId<'db>,
1494        current_segment_generic_args: &[ast::GenericArg<'db>],
1495        ctx_trait: TraitId<'db>,
1496        segment_stable_ptr: SyntaxStablePtrId<'db>,
1497    ) -> Maybe<()> {
1498        if current_segment_trait_id != ctx_trait {
1499            return Ok(());
1500        }
1501
1502        let generic_params = self.db.trait_generic_params(ctx_trait)?;
1503        self.compare_segment_args_to_params(
1504            diagnostics,
1505            current_segment_generic_args,
1506            generic_params,
1507            segment_stable_ptr,
1508            TraitInTraitMustBeExplicit,
1509            TraitItemForbiddenInTheTrait,
1510        )
1511    }
1512
1513    /// Check if the given generic arguments exactly match the given generic parameters.
1514    /// This is used to check if a path segment is forbidden in the context of the item referred to
1515    /// by the segment.
1516    ///
1517    /// Fails if not all arguments are explicitly specified or if they are all specified and exactly
1518    /// the same as the parameters.
1519    fn compare_segment_args_to_params(
1520        &mut self,
1521        diagnostics: &mut SemanticDiagnostics<'db>,
1522        current_segment_generic_args: &[ast::GenericArg<'db>],
1523        generic_params: &[GenericParam<'db>],
1524        segment_stable_ptr: SyntaxStablePtrId<'db>,
1525        must_be_explicit_error: SemanticDiagnosticKind<'db>,
1526        item_forbidden_in_itself_explicit_error: SemanticDiagnosticKind<'db>,
1527    ) -> Maybe<()> {
1528        // This assumes the current segment item and the context items are equal. In this specific
1529        // case we disallow implicit arguments.
1530        if current_segment_generic_args.len() < generic_params.len() {
1531            return Err(diagnostics.report(segment_stable_ptr, must_be_explicit_error));
1532        }
1533        let resolved_args = self.resolve_generic_args(
1534            diagnostics,
1535            GenericSubstitution::default(),
1536            generic_params,
1537            current_segment_generic_args,
1538            segment_stable_ptr,
1539        )?;
1540
1541        if generic_params
1542            .iter()
1543            .zip_eq(resolved_args.iter())
1544            .all(|(gparam, garg)| gparam.as_arg(self.db) == *garg)
1545        {
1546            return Err(
1547                diagnostics.report(segment_stable_ptr, item_forbidden_in_itself_explicit_error)
1548            );
1549        }
1550        Ok(())
1551    }
1552
1553    /// Specializes a ResolvedGenericItem that came from a Statement Environment.
1554    fn specialize_generic_statement_arg(
1555        &mut self,
1556        diagnostics: &mut SemanticDiagnostics<'db>,
1557        segment: &ast::PathSegment<'db>,
1558        identifier: &ast::TerminalIdentifier<'db>,
1559        inner_generic_item: ResolvedGenericItem<'db>,
1560        generic_args_syntax: Option<Vec<ast::GenericArg<'db>>>,
1561    ) -> ResolvedConcreteItem<'db> {
1562        let segment_stable_ptr = segment.stable_ptr(self.db).untyped();
1563        let mut specialized_item = self
1564            .specialize_generic_module_item(
1565                diagnostics,
1566                identifier,
1567                inner_generic_item,
1568                generic_args_syntax.clone(),
1569            )
1570            .unwrap();
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        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(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        self.validate_module_item_usability(module_id, identifier, &inner_item_info);
1845        self.resolver.insert_used_use(inner_item_info.item_id);
1846        let inner_generic_item =
1847            ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)?;
1848        let mut specialized_item = self.resolver.specialize_generic_module_item(
1849            self.diagnostics,
1850            identifier,
1851            inner_generic_item.clone(),
1852            generic_args_syntax.clone(),
1853        )?;
1854        self.resolver
1855            .data
1856            .resolved_items
1857            .generic
1858            .insert(identifier.stable_ptr(db), inner_generic_item);
1859        self.resolver.handle_same_impl_trait(
1860            self.diagnostics,
1861            &mut specialized_item,
1862            &generic_args_syntax.unwrap_or_default(),
1863            segment_stable_ptr,
1864        );
1865        Ok(specialized_item)
1866    }
1867
1868    /// Resolves the first segment of a concrete path.
1869    fn first_concrete(&mut self) -> Maybe<ResolvedConcreteItem<'db>> {
1870        if let Some(base_module) =
1871            self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
1872                resolved_items.mark_concrete(db, segment, ResolvedConcreteItem::Module(module_id));
1873            })
1874        {
1875            return Ok(ResolvedConcreteItem::Module(base_module?));
1876        }
1877
1878        let db = self.resolver.db;
1879        Ok(match self.segments.peek().unwrap() {
1880            syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
1881                let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
1882                let identifier = generic_segment.ident(db);
1883                // Identifier with generic args cannot be a local item.
1884                match self.determine_base(&identifier)? {
1885                    ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1886                    ResolvedBase::Crate(_) => {
1887                        // Crates do not have generics.
1888                        return Err(self
1889                            .diagnostics
1890                            .report(generics_stable_ptr, UnexpectedGenericArgs));
1891                    }
1892                    ResolvedBase::StatementEnvironment(generic_item) => {
1893                        let segment = self.segments.next().unwrap();
1894                        let concrete_item = self.resolver.specialize_generic_statement_arg(
1895                            self.diagnostics,
1896                            &segment,
1897                            &identifier,
1898                            generic_item,
1899                            segment.generic_args(db),
1900                        );
1901                        self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1902                    }
1903                    ResolvedBase::FoundThroughGlobalUse {
1904                        item_info: inner_module_item,
1905                        containing_module: module_id,
1906                    } => {
1907                        let segment = self.segments.next().unwrap();
1908
1909                        let concrete_item = self.specialize_generic_inner_item(
1910                            module_id,
1911                            &segment,
1912                            &identifier,
1913                            inner_module_item,
1914                        )?;
1915                        self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1916                    }
1917                    ResolvedBase::Ambiguous(module_items) => {
1918                        return Err(self
1919                            .diagnostics
1920                            .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1921                    }
1922                    ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1923                        return Err(self.diagnostics.report(
1924                            identifier.stable_ptr(db),
1925                            ItemNotVisible(module_item_id, containing_modules),
1926                        ));
1927                    }
1928                }
1929            }
1930            syntax::node::ast::PathSegment::Simple(simple_segment) => {
1931                let identifier = simple_segment.ident(db);
1932
1933                if let Some(resolved_item) = resolve_self_segment(
1934                    db,
1935                    self.diagnostics,
1936                    &identifier,
1937                    &self.resolver.data.trait_or_impl_ctx,
1938                ) {
1939                    // The first segment is `Self`. Consume it and return.
1940                    return Ok(self.resolver.resolved_items.mark_concrete(
1941                        db,
1942                        &self.segments.next().unwrap(),
1943                        resolved_item?,
1944                    ));
1945                }
1946
1947                if let Some(local_item) =
1948                    self.resolver.determine_base_item_in_local_scope(&identifier)
1949                {
1950                    self.resolver.resolved_items.mark_concrete(
1951                        db,
1952                        &self.segments.next().unwrap(),
1953                        local_item,
1954                    )
1955                } else {
1956                    match self.determine_base(&identifier)? {
1957                        // This item lies inside a module.
1958                        ResolvedBase::Module(module_id) => ResolvedConcreteItem::Module(module_id),
1959                        ResolvedBase::Crate(crate_id) => {
1960                            self.resolver.resolved_items.mark_concrete(
1961                                db,
1962                                &self.segments.next().unwrap(),
1963                                ResolvedConcreteItem::Module(ModuleId::CrateRoot(crate_id)),
1964                            )
1965                        }
1966                        ResolvedBase::StatementEnvironment(generic_item) => {
1967                            let segment = self.segments.next().unwrap();
1968
1969                            let concrete_item = self.resolver.specialize_generic_statement_arg(
1970                                self.diagnostics,
1971                                &segment,
1972                                &identifier,
1973                                generic_item,
1974                                segment.generic_args(db),
1975                            );
1976                            self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1977                        }
1978                        ResolvedBase::FoundThroughGlobalUse {
1979                            item_info: inner_module_item,
1980                            containing_module: module_id,
1981                        } => {
1982                            let segment = self.segments.next().unwrap();
1983                            let concrete_item = self.specialize_generic_inner_item(
1984                                module_id,
1985                                &segment,
1986                                &identifier,
1987                                inner_module_item,
1988                            )?;
1989                            self.resolver.resolved_items.mark_concrete(db, &segment, concrete_item)
1990                        }
1991                        ResolvedBase::Ambiguous(module_items) => {
1992                            return Err(self
1993                                .diagnostics
1994                                .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
1995                        }
1996                        ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
1997                            return Err(self.diagnostics.report(
1998                                identifier.stable_ptr(db),
1999                                ItemNotVisible(module_item_id, containing_modules),
2000                            ));
2001                        }
2002                    }
2003                }
2004            }
2005            // A diagnostic for the missing segment should have been reported from the syntax phase.
2006            syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
2007        })
2008    }
2009    /// Resolves the first segment of a generic path.
2010    /// If `allow_generic_args` is true the generic args will be ignored.
2011    fn first_generic(&mut self, allow_generic_args: bool) -> Maybe<ResolvedGenericItem<'db>> {
2012        if let Some(base_module) =
2013            self.try_handle_super_segments(|resolved_items, db, segment, module_id| {
2014                resolved_items.mark_generic(db, segment, ResolvedGenericItem::Module(module_id));
2015            })
2016        {
2017            return Ok(ResolvedGenericItem::Module(base_module?));
2018        }
2019        let db = self.resolver.db;
2020        Ok(match self.segments.peek().unwrap() {
2021            syntax::node::ast::PathSegment::WithGenericArgs(generic_segment) => {
2022                let generics_stable_ptr = generic_segment.generic_args(db).stable_ptr(db);
2023                if !allow_generic_args {
2024                    return Err(self
2025                        .diagnostics
2026                        .report(generics_stable_ptr, UnexpectedGenericArgs));
2027                }
2028                let identifier = generic_segment.ident(db);
2029                match self.determine_base(&identifier)? {
2030                    ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2031                    ResolvedBase::Crate(_) => {
2032                        // Crates do not have generics.
2033                        return Err(self
2034                            .diagnostics
2035                            .report(generics_stable_ptr, UnexpectedGenericArgs));
2036                    }
2037                    ResolvedBase::StatementEnvironment(generic_item) => generic_item,
2038                    ResolvedBase::FoundThroughGlobalUse {
2039                        item_info: inner_module_item, ..
2040                    } => {
2041                        self.resolver.insert_used_use(inner_module_item.item_id);
2042                        let generic_item =
2043                            ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2044                        self.resolver.resolved_items.mark_generic(
2045                            db,
2046                            &self.segments.next().unwrap(),
2047                            generic_item,
2048                        )
2049                    }
2050                    ResolvedBase::Ambiguous(module_items) => {
2051                        return Err(self
2052                            .diagnostics
2053                            .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2054                    }
2055                    ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2056                        return Err(self.diagnostics.report(
2057                            identifier.stable_ptr(db),
2058                            ItemNotVisible(module_item_id, containing_modules),
2059                        ));
2060                    }
2061                }
2062            }
2063            syntax::node::ast::PathSegment::Simple(simple_segment) => {
2064                let identifier = simple_segment.ident(db);
2065                match self.determine_base(&identifier)? {
2066                    // This item lies inside a module.
2067                    ResolvedBase::Module(module_id) => ResolvedGenericItem::Module(module_id),
2068                    ResolvedBase::Crate(crate_id) => self.resolver.resolved_items.mark_generic(
2069                        db,
2070                        &self.segments.next().unwrap(),
2071                        ResolvedGenericItem::Module(ModuleId::CrateRoot(crate_id)),
2072                    ),
2073                    ResolvedBase::StatementEnvironment(generic_item) => self
2074                        .resolver
2075                        .resolved_items
2076                        .mark_generic(db, &self.segments.next().unwrap(), generic_item),
2077                    ResolvedBase::FoundThroughGlobalUse {
2078                        item_info: inner_module_item, ..
2079                    } => {
2080                        self.resolver.insert_used_use(inner_module_item.item_id);
2081                        let generic_item =
2082                            ResolvedGenericItem::from_module_item(db, inner_module_item.item_id)?;
2083                        self.resolver.resolved_items.mark_generic(
2084                            db,
2085                            &self.segments.next().unwrap(),
2086                            generic_item,
2087                        )
2088                    }
2089                    ResolvedBase::Ambiguous(module_items) => {
2090                        return Err(self
2091                            .diagnostics
2092                            .report(identifier.stable_ptr(db), AmbiguousPath(module_items)));
2093                    }
2094                    ResolvedBase::ItemNotVisible(module_item_id, containing_modules) => {
2095                        return Err(self.diagnostics.report(
2096                            identifier.stable_ptr(db),
2097                            ItemNotVisible(module_item_id, containing_modules),
2098                        ));
2099                    }
2100                }
2101            }
2102            // A diagnostic for the missing segment should have been reported from the syntax phase.
2103            syntax::node::ast::PathSegment::Missing(_) => return Err(skip_diagnostic()),
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(_) | ast::PathSegment::Missing(_) => 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 identifier.text(db).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.validate_module_item_usability(*module_id, &identifier, &inner_item_info);
2494                self.resolver.insert_used_use(inner_item_info.item_id);
2495                ResolvedGenericItem::from_module_item(db, inner_item_info.item_id)
2496            }
2497            ResolvedGenericItem::GenericType(GenericTypeId::Enum(enum_id)) => {
2498                let variants = db.enum_variants(*enum_id)?;
2499                let variant_id = variants.get(&ident).ok_or_else(|| {
2500                    self.diagnostics.report(
2501                        identifier.stable_ptr(db),
2502                        NoSuchVariant { enum_id: *enum_id, variant_name: ident },
2503                    )
2504                })?;
2505                let variant = db.variant_semantic(*enum_id, *variant_id)?;
2506                Ok(ResolvedGenericItem::Variant(variant))
2507            }
2508            _ => Err(self.diagnostics.report(identifier.stable_ptr(db), InvalidPath)),
2509        }
2510    }
2511
2512    /// Determines the base module or crate for the path resolving. Looks only in non-local scope
2513    /// (i.e. current module, or crates).
2514    fn determine_base(
2515        &mut self,
2516        identifier: &ast::TerminalIdentifier<'db>,
2517    ) -> Maybe<ResolvedBase<'db>> {
2518        let db = self.resolver.db;
2519        let ident = identifier.text(db);
2520        if let ResolutionContext::Statement(ref mut env) = self.resolution_context
2521            && let Some(item) = get_statement_item_by_name(env, ident)
2522        {
2523            return Ok(ResolvedBase::StatementEnvironment(item));
2524        }
2525
2526        let Some(module_id) = self.resolver.try_get_active_module_id(&self.macro_info) else {
2527            let item_type = if self.segments.len() == 1 {
2528                self.expected_item_type
2529            } else {
2530                NotFoundItemType::Identifier
2531            };
2532            return Err(self
2533                .diagnostics
2534                .report(identifier.stable_ptr(db), PathNotFound(item_type)));
2535        };
2536        // If an item with this name is found inside the current module, use the current module.
2537        if let Some(info) = self.resolver.resolve_item_in_module_or_expanded_macro(module_id, ident)
2538            && !matches!(self.resolution_context, ResolutionContext::ModuleItem(id) if id == info.item_id)
2539        {
2540            return Ok(ResolvedBase::Module(module_id));
2541        }
2542
2543        // If the first element is `crate`, use the crate's root module as the base module.
2544        if ident.long(db) == CRATE_KW {
2545            return Ok(ResolvedBase::Crate(self.resolver.active_owning_crate_id(&self.macro_info)));
2546        }
2547        // If the first segment is a name of a crate, use the crate's root module as the base
2548        // module.
2549        if let Some(dep) = self
2550            .resolver
2551            .active_settings(&self.macro_info)
2552            .dependencies
2553            .get(ident.long(db).as_str())
2554        {
2555            let dep_crate_id =
2556                CrateLongId::Real { name: ident, discriminator: dep.discriminator.clone() }
2557                    .intern(db);
2558            let configs = db.crate_configs();
2559            if !configs.contains_key(&dep_crate_id) {
2560                let get_long_id = |crate_id: CrateId<'db>| crate_id.long(db);
2561                panic!(
2562                    "Invalid crate dependency: {:?}\nconfigured crates: {:#?}",
2563                    get_long_id(dep_crate_id),
2564                    configs.keys().cloned().map(get_long_id).collect_vec()
2565                );
2566            }
2567
2568            return Ok(ResolvedBase::Crate(dep_crate_id));
2569        }
2570        // If the first segment is `core` - and it was not overridden by a dependency - using it.
2571        if ident.long(db) == CORELIB_CRATE_NAME {
2572            return Ok(ResolvedBase::Crate(CrateId::core(db)));
2573        }
2574        // TODO(orizi): Remove when `starknet` becomes a proper crate.
2575        if ident.long(db) == STARKNET_CRATE_NAME {
2576            // Making sure we don't look for it in `*` modules, to prevent cycles.
2577            return Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)));
2578        }
2579        // Finding whether the item is an imported module.
2580        match self.resolver.resolve_path_using_use_star(module_id, ident) {
2581            UseStarResult::UniquePathFound(inner_module_item) => {
2582                return Ok(ResolvedBase::FoundThroughGlobalUse {
2583                    item_info: inner_module_item,
2584                    containing_module: module_id,
2585                });
2586            }
2587            UseStarResult::AmbiguousPath(module_items) => {
2588                return Ok(ResolvedBase::Ambiguous(module_items));
2589            }
2590            UseStarResult::PathNotFound => {}
2591            UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
2592                let prelude = self.resolver.prelude_submodule_ex(&self.macro_info);
2593                if let Ok(Some(_)) = db.module_item_by_name(prelude, ident) {
2594                    return Ok(ResolvedBase::Module(prelude));
2595                }
2596                return Ok(ResolvedBase::ItemNotVisible(module_item_id, containing_modules));
2597            }
2598        }
2599        Ok(ResolvedBase::Module(self.resolver.prelude_submodule_ex(&self.macro_info)))
2600    }
2601    /// Validates that an item is usable from the current module or adds a diagnostic.
2602    /// This includes visibility checks and feature checks.
2603    fn validate_module_item_usability(
2604        &mut self,
2605        containing_module_id: ModuleId<'db>,
2606        identifier: &ast::TerminalIdentifier<'db>,
2607        item_info: &ModuleItemInfo<'db>,
2608    ) {
2609        if !self.resolver.is_item_visible_ex(
2610            containing_module_id,
2611            item_info,
2612            self.resolver.active_module_id(&self.macro_info),
2613            &self.macro_info,
2614        ) {
2615            self.diagnostics.report(
2616                identifier.stable_ptr(self.resolver.db),
2617                ItemNotVisible(item_info.item_id, vec![]),
2618            );
2619        }
2620
2621        self.resolver.validate_feature_constraints(self.diagnostics, identifier, item_info);
2622    }
2623}