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