cairo_lang_semantic/resolve/
mod.rs

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