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