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