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