cairo_lang_semantic/resolve/
mod.rs

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