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 return ResolvedBase::Crate(
1281 CrateLongId::Real { name: ident, discriminator: dep.discriminator.clone() }
1282 .intern(self.db),
1283 );
1284 }
1285 match self.resolve_path_using_use_star(module_id, identifier) {
1287 UseStarResult::UniquePathFound(inner_module_item) => {
1288 return ResolvedBase::FoundThroughGlobalUse {
1289 item_info: inner_module_item,
1290 containing_module: module_id,
1291 };
1292 }
1293 UseStarResult::AmbiguousPath(module_items) => {
1294 return ResolvedBase::Ambiguous(module_items);
1295 }
1296 UseStarResult::PathNotFound => {}
1297 UseStarResult::ItemNotVisible(module_item_id, containing_modules) => {
1298 return ResolvedBase::ItemNotVisible(module_item_id, containing_modules);
1299 }
1300 }
1301 if ident == CORELIB_CRATE_NAME {
1303 return ResolvedBase::Crate(CrateId::core(self.db));
1304 }
1305 ResolvedBase::Module(self.prelude_submodule())
1306 }
1307
1308 pub fn prelude_submodule(&self) -> ModuleId {
1310 let prelude_submodule_name = self.settings.edition.prelude_submodule_name();
1311 let core_prelude_submodule = core_submodule(self.db, "prelude");
1312 get_submodule(self.db, core_prelude_submodule, prelude_submodule_name).unwrap_or_else(
1313 || {
1314 panic!(
1315 "expected prelude submodule `{prelude_submodule_name}` not found in \
1316 `core::prelude`."
1317 )
1318 },
1319 )
1320 }
1321
1322 fn specialize_trait(
1324 &mut self,
1325 diagnostics: &mut SemanticDiagnostics,
1326 stable_ptr: SyntaxStablePtrId,
1327 trait_id: TraitId,
1328 generic_args: &[ast::GenericArg],
1329 ) -> Maybe<ConcreteTraitId> {
1330 let generic_params = self
1332 .db
1333 .trait_generic_params(trait_id)
1334 .map_err(|_| diagnostics.report(stable_ptr, UnknownTrait))?;
1335 let generic_args =
1336 self.resolve_generic_args(diagnostics, &generic_params, generic_args, stable_ptr)?;
1337
1338 Ok(ConcreteTraitLongId { trait_id, generic_args }.intern(self.db))
1339 }
1340
1341 fn specialize_impl(
1343 &mut self,
1344 diagnostics: &mut SemanticDiagnostics,
1345 stable_ptr: SyntaxStablePtrId,
1346 impl_def_id: ImplDefId,
1347 generic_args: &[ast::GenericArg],
1348 ) -> Maybe<ConcreteImplId> {
1349 let generic_params = self
1351 .db
1352 .impl_def_generic_params(impl_def_id)
1353 .map_err(|_| diagnostics.report(stable_ptr, UnknownImpl))?;
1354 let generic_args =
1355 self.resolve_generic_args(diagnostics, &generic_params, generic_args, stable_ptr)?;
1356
1357 Ok(ConcreteImplLongId { impl_def_id, generic_args }.intern(self.db))
1358 }
1359
1360 pub fn specialize_function(
1362 &mut self,
1363 diagnostics: &mut SemanticDiagnostics,
1364 stable_ptr: SyntaxStablePtrId,
1365 generic_function: GenericFunctionId,
1366 generic_args: &[ast::GenericArg],
1367 ) -> Maybe<FunctionId> {
1368 let generic_params: Vec<_> = generic_function.generic_params(self.db)?;
1370 let generic_args =
1371 self.resolve_generic_args(diagnostics, &generic_params, generic_args, stable_ptr)?;
1372
1373 Ok(FunctionLongId { function: ConcreteFunction { generic_function, generic_args } }
1374 .intern(self.db))
1375 }
1376
1377 pub fn specialize_type(
1379 &mut self,
1380 diagnostics: &mut SemanticDiagnostics,
1381 stable_ptr: SyntaxStablePtrId,
1382 generic_type: GenericTypeId,
1383 generic_args: &[ast::GenericArg],
1384 ) -> Maybe<TypeId> {
1385 let generic_params = self
1386 .db
1387 .generic_type_generic_params(generic_type)
1388 .map_err(|_| diagnostics.report(stable_ptr, UnknownType))?;
1389 let generic_args =
1390 self.resolve_generic_args(diagnostics, &generic_params, generic_args, stable_ptr)?;
1391
1392 Ok(TypeLongId::Concrete(ConcreteTypeId::new(self.db, generic_type, generic_args))
1393 .intern(self.db))
1394 }
1395
1396 pub fn impl_lookup_context(&self) -> ImplLookupContext {
1397 let mut lookup_context =
1398 ImplLookupContext::new(self.module_file_id.0, self.generic_params.clone());
1399
1400 if let TraitOrImplContext::Impl(impl_def_id) = &self.trait_or_impl_ctx {
1401 let Ok(generic_params) = self.db.impl_def_generic_params(*impl_def_id) else {
1402 return lookup_context;
1403 };
1404 let generic_args = generic_params_to_args(generic_params.as_slice(), self.db);
1405 let impl_id: ConcreteImplId =
1406 ConcreteImplLongId { impl_def_id: *impl_def_id, generic_args }.intern(self.db);
1407 lookup_context.insert_impl(ImplLongId::Concrete(impl_id).intern(self.db));
1408 }
1409 lookup_context
1410 }
1411
1412 pub fn resolve_generic_args(
1416 &mut self,
1417 diagnostics: &mut SemanticDiagnostics,
1418 generic_params: &[GenericParam],
1419 generic_args_syntax: &[ast::GenericArg],
1420 stable_ptr: SyntaxStablePtrId,
1421 ) -> Maybe<Vec<GenericArgumentId>> {
1422 let mut substitution = GenericSubstitution::default();
1423 let mut resolved_args = vec![];
1424 let arg_syntax_per_param =
1425 self.get_arg_syntax_per_param(diagnostics, generic_params, generic_args_syntax)?;
1426
1427 for generic_param in generic_params.iter() {
1428 let generic_param = SubstitutionRewriter { db: self.db, substitution: &substitution }
1429 .rewrite(generic_param.clone())?;
1430 let generic_arg = self.resolve_generic_arg(
1431 &generic_param,
1432 arg_syntax_per_param
1433 .get(&generic_param.id())
1434 .and_then(|arg_syntax| {
1435 if let ast::GenericArgValue::Expr(expr) = arg_syntax {
1436 Some(expr.expr(self.db.upcast()))
1437 } else {
1438 None
1439 }
1440 })
1441 .as_ref(),
1442 stable_ptr,
1443 diagnostics,
1444 )?;
1445 resolved_args.push(generic_arg);
1446 substitution.insert(generic_param.id(), generic_arg);
1447 }
1448
1449 Ok(resolved_args)
1450 }
1451
1452 fn get_arg_syntax_per_param(
1454 &self,
1455 diagnostics: &mut SemanticDiagnostics,
1456 generic_params: &[GenericParam],
1457 generic_args_syntax: &[ast::GenericArg],
1458 ) -> Maybe<UnorderedHashMap<GenericParamId, ast::GenericArgValue>> {
1459 let syntax_db = self.db.upcast();
1460 let mut arg_syntax_per_param =
1461 UnorderedHashMap::<GenericParamId, ast::GenericArgValue>::default();
1462 let mut last_named_arg_index = None;
1463 let generic_param_by_name = generic_params
1464 .iter()
1465 .enumerate()
1466 .filter_map(|(i, param)| Some((param.id().name(self.db.upcast())?, (i, param.id()))))
1467 .collect::<UnorderedHashMap<_, _>>();
1468 for (idx, generic_arg_syntax) in generic_args_syntax.iter().enumerate() {
1469 match generic_arg_syntax {
1470 ast::GenericArg::Named(arg_syntax) => {
1471 let name = arg_syntax.name(syntax_db).text(syntax_db);
1472 let Some((index, generic_param_id)) = generic_param_by_name.get(&name) else {
1473 return Err(diagnostics.report(arg_syntax, UnknownGenericParam(name)));
1474 };
1475 if let Some(prev_index) = last_named_arg_index {
1476 if prev_index > index {
1477 return Err(diagnostics.report(arg_syntax, GenericArgOutOfOrder(name)));
1478 }
1479 }
1480 last_named_arg_index = Some(index);
1481 if arg_syntax_per_param
1482 .insert(*generic_param_id, arg_syntax.value(syntax_db))
1483 .is_some()
1484 {
1485 return Err(diagnostics.report(arg_syntax, GenericArgDuplicate(name)));
1486 }
1487 }
1488 ast::GenericArg::Unnamed(arg_syntax) => {
1489 if last_named_arg_index.is_some() {
1490 return Err(diagnostics.report(arg_syntax, PositionalGenericAfterNamed));
1491 }
1492 let generic_param = generic_params.get(idx).ok_or_else(|| {
1493 diagnostics.report(arg_syntax, TooManyGenericArguments {
1494 expected: generic_params.len(),
1495 actual: generic_args_syntax.len(),
1496 })
1497 })?;
1498 assert_eq!(
1499 arg_syntax_per_param
1500 .insert(generic_param.id(), arg_syntax.value(syntax_db)),
1501 None,
1502 "Unexpected duplication in ordered params."
1503 );
1504 }
1505 }
1506 }
1507 Ok(arg_syntax_per_param)
1508 }
1509
1510 fn resolve_generic_arg(
1514 &mut self,
1515 generic_param: &GenericParam,
1516 generic_arg_syntax_opt: Option<&ast::Expr>,
1517 stable_ptr: SyntaxStablePtrId,
1518 diagnostics: &mut SemanticDiagnostics,
1519 ) -> Result<GenericArgumentId, cairo_lang_diagnostics::DiagnosticAdded> {
1520 let Some(generic_arg_syntax) = generic_arg_syntax_opt else {
1521 let lookup_context = self.impl_lookup_context();
1522 let inference = &mut self.data.inference_data.inference(self.db);
1523 return inference
1524 .infer_generic_arg(generic_param, lookup_context, Some(stable_ptr))
1525 .map_err(|err_set| {
1526 inference.report_on_pending_error(err_set, diagnostics, stable_ptr)
1527 });
1528 };
1529 Ok(match generic_param {
1530 GenericParam::Type(_) => {
1531 let ty = resolve_type(self.db, diagnostics, self, generic_arg_syntax);
1532 GenericArgumentId::Type(ty)
1533 }
1534 GenericParam::Const(const_param) => {
1535 let environment = Environment::empty();
1539
1540 let mut resolver_data =
1543 ResolverData::new(self.module_file_id, self.inference_data.inference_id);
1544 std::mem::swap(&mut self.data, &mut resolver_data);
1545
1546 let mut ctx = ComputationContext::new(
1547 self.db,
1548 diagnostics,
1549 Resolver::with_data(self.db, resolver_data),
1550 None,
1551 environment,
1552 ContextFunction::Global,
1553 );
1554 let value = compute_expr_semantic(&mut ctx, generic_arg_syntax);
1555
1556 let const_value = resolve_const_expr_and_evaluate(
1557 self.db,
1558 &mut ctx,
1559 &value,
1560 generic_arg_syntax.stable_ptr().untyped(),
1561 const_param.ty,
1562 );
1563
1564 std::mem::swap(&mut ctx.resolver.data, &mut self.data);
1566
1567 GenericArgumentId::Constant(const_value.intern(self.db))
1568 }
1569
1570 GenericParam::Impl(param) => {
1571 let expr_path = try_extract_matches!(generic_arg_syntax, ast::Expr::Path)
1572 .ok_or_else(|| diagnostics.report(generic_arg_syntax, UnknownImpl))?;
1573 let resolved_impl = try_extract_matches!(
1574 self.resolve_concrete_path(diagnostics, expr_path, NotFoundItemType::Impl)?,
1575 ResolvedConcreteItem::Impl
1576 )
1577 .ok_or_else(|| diagnostics.report(generic_arg_syntax, UnknownImpl))?;
1578 let impl_def_concrete_trait = self.db.impl_concrete_trait(resolved_impl)?;
1579 let expected_concrete_trait = param.concrete_trait?;
1580 if let Err(err_set) = self
1581 .inference()
1582 .conform_traits(impl_def_concrete_trait, expected_concrete_trait)
1583 {
1584 let diag_added = diagnostics.report(generic_arg_syntax, TraitMismatch {
1585 expected_trt: expected_concrete_trait,
1586 actual_trt: impl_def_concrete_trait,
1587 });
1588 self.inference().consume_reported_error(err_set, diag_added);
1589 } else {
1590 for (trait_ty, ty1) in param.type_constraints.iter() {
1591 let ty0 = TypeLongId::ImplType(ImplTypeId::new(
1592 resolved_impl,
1593 trait_ty.trait_type(self.db),
1594 self.db,
1595 ))
1596 .intern(self.db);
1597 let _ = self.inference().conform_ty(ty0, *ty1).map_err(|err_set| {
1598 self.inference().report_on_pending_error(
1599 err_set,
1600 diagnostics,
1601 stable_ptr,
1602 )
1603 });
1604 }
1605 }
1606 GenericArgumentId::Impl(resolved_impl)
1607 }
1608 GenericParam::NegImpl(_) => {
1609 return Err(diagnostics.report(generic_arg_syntax, ArgPassedToNegativeImpl));
1610 }
1611 })
1612 }
1613 pub fn ignore_visibility_checks(&self, module_id: ModuleId) -> bool {
1616 let module_crate = module_id.owning_crate(self.db.upcast());
1617 let module_edition =
1618 self.db.crate_config(module_crate).map(|c| c.settings.edition).unwrap_or_default();
1619 module_edition.ignore_visibility()
1620 || self.settings.edition.ignore_visibility() && module_crate == self.db.core_crate()
1621 }
1622
1623 fn validate_item_usability(
1626 &self,
1627 diagnostics: &mut SemanticDiagnostics,
1628 containing_module_id: ModuleId,
1629 identifier: &ast::TerminalIdentifier,
1630 item_info: &ModuleItemInfo,
1631 ) {
1632 if !self.is_item_visible(containing_module_id, item_info, self.module_file_id.0) {
1633 diagnostics.report(identifier, ItemNotVisible(item_info.item_id, vec![]));
1634 }
1635 match &item_info.feature_kind {
1636 FeatureKind::Unstable { feature, note }
1637 if !self.data.feature_config.allowed_features.contains(feature) =>
1638 {
1639 diagnostics.report(identifier, UnstableFeature {
1640 feature_name: feature.clone(),
1641 note: note.clone(),
1642 });
1643 }
1644 FeatureKind::Deprecated { feature, note }
1645 if !self.data.feature_config.allow_deprecated
1646 && !self.data.feature_config.allowed_features.contains(feature) =>
1647 {
1648 diagnostics.report(identifier, DeprecatedFeature {
1649 feature_name: feature.clone(),
1650 note: note.clone(),
1651 });
1652 }
1653 FeatureKind::Internal { feature, note }
1654 if !self.data.feature_config.allowed_features.contains(feature) =>
1655 {
1656 diagnostics.report(identifier, InternalFeature {
1657 feature_name: feature.clone(),
1658 note: note.clone(),
1659 });
1660 }
1661 _ => {}
1662 }
1663 }
1664
1665 fn is_item_visible(
1667 &self,
1668 containing_module_id: ModuleId,
1669 item_info: &ModuleItemInfo,
1670 user_module: ModuleId,
1671 ) -> bool {
1672 let db = self.db.upcast();
1673 self.ignore_visibility_checks(containing_module_id)
1674 || visibility::peek_visible_in(
1675 db,
1676 item_info.visibility,
1677 containing_module_id,
1678 user_module,
1679 )
1680 }
1681
1682 fn is_item_feature_usable(&self, item_info: &ModuleItemInfo) -> bool {
1684 match &item_info.feature_kind {
1685 FeatureKind::Unstable { feature, .. }
1686 | FeatureKind::Deprecated { feature, .. }
1687 | FeatureKind::Internal { feature, .. } => {
1688 self.data.feature_config.allowed_features.contains(feature)
1689 }
1690 _ => true,
1691 }
1692 }
1693
1694 fn warn_same_impl_trait(
1699 &mut self,
1700 diagnostics: &mut SemanticDiagnostics,
1701 specialized_item: &ResolvedConcreteItem,
1702 generic_args_syntax_slice: &[ast::GenericArg],
1703 segment_stable_ptr: SyntaxStablePtrId,
1704 ) {
1705 match *specialized_item {
1706 ResolvedConcreteItem::Trait(current_segment_concrete_trait) => {
1707 match self.trait_or_impl_ctx {
1708 TraitOrImplContext::None => {}
1709 TraitOrImplContext::Trait(ctx_trait) => {
1710 self.warn_trait_in_same_trait(
1711 diagnostics,
1712 current_segment_concrete_trait.trait_id(self.db),
1713 generic_args_syntax_slice,
1714 ctx_trait,
1715 segment_stable_ptr,
1716 )
1717 .ok();
1718 }
1719 TraitOrImplContext::Impl(ctx_impl_def_id) => {
1720 self.warn_trait_in_its_impl(
1721 diagnostics,
1722 current_segment_concrete_trait,
1723 ctx_impl_def_id,
1724 segment_stable_ptr,
1725 )
1726 .ok();
1727 }
1728 };
1729 }
1730 ResolvedConcreteItem::Impl(current_segment_impl_id) => {
1731 if let TraitOrImplContext::Impl(ctx_impl) = self.trait_or_impl_ctx {
1732 let current_segment_concrete_impl_id = extract_matches!(
1735 current_segment_impl_id.lookup_intern(self.db),
1736 ImplLongId::Concrete
1737 );
1738 self.warn_impl_in_same_impl(
1739 diagnostics,
1740 current_segment_concrete_impl_id.impl_def_id(self.db),
1741 generic_args_syntax_slice,
1742 ctx_impl,
1743 segment_stable_ptr,
1744 )
1745 .ok();
1746 }
1747 }
1748 _ => {}
1749 };
1750 }
1751
1752 fn warn_impl_in_same_impl(
1755 &mut self,
1756 diagnostics: &mut SemanticDiagnostics,
1757 current_segment_impl_def_id: ImplDefId,
1758 current_segment_generic_args: &[ast::GenericArg],
1759 ctx_impl: ImplDefId,
1760 segment_stable_ptr: SyntaxStablePtrId,
1761 ) -> Maybe<()> {
1762 if current_segment_impl_def_id != ctx_impl {
1763 return Ok(());
1764 }
1765
1766 let generic_params = self.db.impl_def_generic_params(ctx_impl)?;
1767 self.compare_segment_args_to_params(
1768 diagnostics,
1769 current_segment_generic_args,
1770 generic_params,
1771 segment_stable_ptr,
1772 ImplInImplMustBeExplicit,
1773 ImplItemForbiddenInTheImpl,
1774 )
1775 }
1776
1777 fn warn_trait_in_its_impl(
1780 &mut self,
1781 diagnostics: &mut SemanticDiagnostics,
1782 current_segment_concrete_trait_id: ConcreteTraitId,
1783 impl_ctx: ImplDefId,
1784 segment_stable_ptr: SyntaxStablePtrId,
1785 ) -> Maybe<()> {
1786 let ctx_impl_trait = self.db.impl_def_trait(impl_ctx)?;
1787 if current_segment_concrete_trait_id.trait_id(self.db) != ctx_impl_trait {
1788 return Ok(());
1789 }
1790
1791 let ctx_impl_concrete_trait = self.db.impl_def_concrete_trait(impl_ctx)?;
1792 if ctx_impl_concrete_trait.generic_args(self.db)
1793 == current_segment_concrete_trait_id.generic_args(self.db)
1794 {
1795 return Err(diagnostics.report(segment_stable_ptr, TraitItemForbiddenInItsImpl));
1796 }
1797 Ok(())
1798 }
1799
1800 fn warn_trait_in_same_trait(
1803 &mut self,
1804 diagnostics: &mut SemanticDiagnostics,
1805 current_segment_trait_id: TraitId,
1806 current_segment_generic_args: &[ast::GenericArg],
1807 ctx_trait: TraitId,
1808 segment_stable_ptr: SyntaxStablePtrId,
1809 ) -> Maybe<()> {
1810 if current_segment_trait_id != ctx_trait {
1811 return Ok(());
1812 }
1813
1814 let generic_params = self.db.trait_generic_params(ctx_trait)?;
1815 self.compare_segment_args_to_params(
1816 diagnostics,
1817 current_segment_generic_args,
1818 generic_params,
1819 segment_stable_ptr,
1820 TraitInTraitMustBeExplicit,
1821 TraitItemForbiddenInTheTrait,
1822 )
1823 }
1824
1825 fn compare_segment_args_to_params(
1832 &mut self,
1833 diagnostics: &mut SemanticDiagnostics,
1834 current_segment_generic_args: &[ast::GenericArg],
1835 generic_params: Vec<GenericParam>,
1836 segment_stable_ptr: SyntaxStablePtrId,
1837 must_be_explicit_error: SemanticDiagnosticKind,
1838 item_forbidden_in_itself_explicit_error: SemanticDiagnosticKind,
1839 ) -> Maybe<()> {
1840 if current_segment_generic_args.len() < generic_params.len() {
1843 return Err(diagnostics.report(segment_stable_ptr, must_be_explicit_error));
1844 }
1845 let resolved_args = self.resolve_generic_args(
1846 diagnostics,
1847 &generic_params,
1848 current_segment_generic_args,
1849 segment_stable_ptr,
1850 )?;
1851
1852 if generic_params
1853 .iter()
1854 .zip_eq(resolved_args.iter())
1855 .all(|(gparam, garg)| gparam.as_arg(self.db) == *garg)
1856 {
1857 return Err(
1858 diagnostics.report(segment_stable_ptr, item_forbidden_in_itself_explicit_error)
1859 );
1860 }
1861 Ok(())
1862 }
1863
1864 fn specialize_generic_statement_arg(
1866 &mut self,
1867 segment: &ast::PathSegment,
1868 diagnostics: &mut SemanticDiagnostics,
1869 identifier: &ast::TerminalIdentifier,
1870 inner_generic_item: ResolvedGenericItem,
1871 generic_args_syntax: Option<Vec<ast::GenericArg>>,
1872 ) -> ResolvedConcreteItem {
1873 let segment_stable_ptr = segment.stable_ptr().untyped();
1874 let specialized_item = self
1875 .specialize_generic_module_item(
1876 diagnostics,
1877 identifier,
1878 inner_generic_item.clone(),
1879 generic_args_syntax.clone(),
1880 )
1881 .unwrap();
1882 self.warn_same_impl_trait(
1883 diagnostics,
1884 &specialized_item,
1885 &generic_args_syntax.unwrap_or_default(),
1886 segment_stable_ptr,
1887 );
1888 specialized_item
1889 }
1890}
1891
1892fn resolve_self_segment(
1895 db: &dyn SemanticGroup,
1896 diagnostics: &mut SemanticDiagnostics,
1897 identifier: &ast::TerminalIdentifier,
1898 trait_or_impl_ctx: &TraitOrImplContext,
1899) -> Option<Maybe<ResolvedConcreteItem>> {
1900 require(identifier.text(db.upcast()) == SELF_TYPE_KW)?;
1901 Some(resolve_actual_self_segment(db, diagnostics, identifier, trait_or_impl_ctx))
1902}
1903
1904fn resolve_actual_self_segment(
1906 db: &dyn SemanticGroup,
1907 diagnostics: &mut SemanticDiagnostics,
1908 identifier: &ast::TerminalIdentifier,
1909 trait_or_impl_ctx: &TraitOrImplContext,
1910) -> Maybe<ResolvedConcreteItem> {
1911 match trait_or_impl_ctx {
1912 TraitOrImplContext::None => Err(diagnostics.report(identifier, SelfNotSupportedInContext)),
1913 TraitOrImplContext::Trait(trait_id) => {
1914 let generic_parameters = db.trait_generic_params(*trait_id)?;
1915 let concrete_trait_id = ConcreteTraitLongId {
1916 trait_id: *trait_id,
1917 generic_args: generic_params_to_args(&generic_parameters, db),
1918 }
1919 .intern(db);
1920 Ok(ResolvedConcreteItem::Trait(concrete_trait_id))
1921 }
1922 TraitOrImplContext::Impl(impl_def_id) => {
1923 let generic_parameters = db.impl_def_generic_params(*impl_def_id)?;
1924 let impl_id = ImplLongId::Concrete(
1925 ConcreteImplLongId {
1926 impl_def_id: *impl_def_id,
1927 generic_args: generic_params_to_args(&generic_parameters, db),
1928 }
1929 .intern(db),
1930 );
1931 Ok(ResolvedConcreteItem::Impl(impl_id.intern(db)))
1932 }
1933 }
1934}
1935
1936enum ResolvedBase {
1938 Module(ModuleId),
1940 Crate(CrateId),
1942 StatementEnvironment(ResolvedGenericItem),
1944 FoundThroughGlobalUse { item_info: ModuleItemInfo, containing_module: ModuleId },
1946 Ambiguous(Vec<ModuleItemId>),
1948 ItemNotVisible(ModuleItemId, Vec<ModuleId>),
1950}
1951
1952struct ResolvePathInnerCallbacks<ResolvedItem, ResolveFirst, ResolveNext, Validate, Mark>
1954where
1955 ResolveFirst: FnMut(
1956 &mut Resolver<'_>,
1957 &mut SemanticDiagnostics,
1958 &mut Peekable<std::slice::Iter<'_, ast::PathSegment>>,
1959 Option<&mut Environment>,
1960 ) -> Maybe<ResolvedItem>,
1961 ResolveNext: FnMut(
1962 &mut Resolver<'_>,
1963 &mut SemanticDiagnostics,
1964 &ResolvedItem,
1965 &ast::PathSegment,
1966 NotFoundItemType,
1967 ) -> Maybe<ResolvedItem>,
1968 Validate: FnMut(&mut SemanticDiagnostics, &ast::PathSegment) -> Maybe<()>,
1969 Mark: FnMut(
1970 &mut ResolvedItems,
1971 &dyn SemanticGroup,
1972 &syntax::node::ast::PathSegment,
1973 ResolvedItem,
1974 ),
1975{
1976 resolved_item_type: PhantomData<ResolvedItem>,
1978 resolve_path_first_segment: ResolveFirst,
1980 resolve_path_next_segment: ResolveNext,
1982 validate_segment: Validate,
1985 mark: Mark,
1986}