1#![expect(clippy::disallowed_types)]
4
5use std::collections::HashMap;
6use std::hash::Hash;
7use std::ops::{Deref, DerefMut};
8use std::sync::Arc;
9
10use cairo_lang_debug::DebugWithDb;
11use cairo_lang_defs::ids::{
12 ConstantId, EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, GenericKind,
13 GenericParamId, GlobalUseId, ImplAliasId, ImplDefId, ImplFunctionId, ImplImplDefId, LocalVarId,
14 LookupItemId, MacroCallId, MemberId, ModuleId, NamedLanguageElementId, ParamId, StructId,
15 TraitConstantId, TraitFunctionId, TraitId, TraitImplId, TraitTypeId, VarId, VariantId,
16};
17use cairo_lang_diagnostics::{DiagnosticAdded, skip_diagnostic};
18use cairo_lang_proc_macros::{DebugWithDb, HeapSize, SemanticObject};
19use cairo_lang_syntax::node::TypedStablePtr;
20use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
21use cairo_lang_utils::deque::Deque;
22use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
23use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
24use cairo_lang_utils::{Intern, define_short_id, extract_matches};
25use salsa::Database;
26
27use self::canonic::{CanonicalImpl, CanonicalMapping, CanonicalTrait, NoError};
28use self::solver::{Ambiguity, SolutionSet};
29use crate::corelib::{CorelibSemantic, is_valid_literal_type};
30use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder};
31use crate::expr::inference::canonic::ResultNoErrEx;
32use crate::expr::inference::conform::InferenceConform;
33use crate::expr::inference::solver::SemanticSolver;
34use crate::expr::objects::*;
35use crate::expr::pattern::*;
36use crate::items::constant::{ConstValue, ConstValueId, ImplConstantId};
37use crate::items::functions::{
38 ConcreteFunctionWithBody, ConcreteFunctionWithBodyId, GenericFunctionId,
39 GenericFunctionWithBodyId, ImplFunctionBodyId, ImplGenericFunctionId,
40 ImplGenericFunctionWithBodyId,
41};
42use crate::items::generics::{
43 GenericParamConst, GenericParamImpl, GenericParamSemantic, GenericParamType,
44};
45use crate::items::imp::{
46 GeneratedImplId, GeneratedImplItems, GeneratedImplLongId, ImplId, ImplImplId, ImplLongId,
47 ImplLookupContext, ImplLookupContextId, ImplSemantic, NegativeImplId, NegativeImplLongId,
48 UninferredGeneratedImplId, UninferredGeneratedImplLongId, UninferredImpl,
49};
50use crate::items::trt::{
51 ConcreteTraitGenericFunctionId, ConcreteTraitGenericFunctionLongId, ConcreteTraitTypeId,
52 ConcreteTraitTypeLongId,
53};
54use crate::path::ContextualizePath;
55use crate::substitution::{GenericSubstitution, HasDb, RewriteResult, SemanticRewriter};
56use crate::types::{
57 ClosureTypeLongId, ConcreteEnumLongId, ConcreteExternTypeLongId, ConcreteStructLongId,
58 ImplTypeId, get_impl_at_context,
59};
60use crate::{
61 ConcreteEnumId, ConcreteExternTypeId, ConcreteFunction, ConcreteImplId, ConcreteImplLongId,
62 ConcreteStructId, ConcreteTraitId, ConcreteTraitLongId, ConcreteTypeId, ConcreteVariant,
63 FunctionId, FunctionLongId, GenericArgumentId, GenericParam, LocalVariable, MatchArmSelector,
64 Member, Parameter, SemanticObject, Signature, TypeId, TypeLongId, ValueSelectorArm,
65 add_basic_rewrites, add_expr_rewrites, add_rewrite, semantic_object_for_id,
66};
67
68pub mod canonic;
69pub mod conform;
70pub mod infers;
71pub mod solver;
72
73#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HeapSize, salsa::SalsaValue)]
76pub struct TypeVar<'db> {
77 pub inference_id: InferenceId<'db>,
78 pub id: LocalTypeVarId,
79}
80
81#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HeapSize, salsa::SalsaValue)]
84pub struct ConstVar<'db> {
85 pub inference_id: InferenceId<'db>,
86 pub id: LocalConstVarId,
87}
88
89#[derive(
91 Copy,
92 Clone,
93 Debug,
94 PartialEq,
95 Eq,
96 Hash,
97 DebugWithDb,
98 SemanticObject,
99 HeapSize,
100 salsa::SalsaValue,
101)]
102#[debug_db(dyn Database)]
103pub enum InferenceId<'db> {
104 LookupItemDeclaration(LookupItemId<'db>),
105 LookupItemGenerics(LookupItemId<'db>),
106 LookupItemDefinition(LookupItemId<'db>),
107 ImplDefTrait(ImplDefId<'db>),
108 ImplAliasImplDef(ImplAliasId<'db>),
109 GenericParam(GenericParamId<'db>),
110 GenericImplParamTrait(GenericParamId<'db>),
111 GlobalUseStar(GlobalUseId<'db>),
112 MacroCall(MacroCallId<'db>),
113 Canonical,
114 NoContext,
116}
117
118#[derive(
121 Clone, Debug, PartialEq, Eq, Hash, DebugWithDb, SemanticObject, HeapSize, salsa::SalsaValue,
122)]
123#[debug_db(dyn Database)]
124pub struct ImplVar<'db> {
125 pub inference_id: InferenceId<'db>,
126 #[dont_rewrite]
127 pub id: LocalImplVarId,
128 pub concrete_trait_id: ConcreteTraitId<'db>,
129 #[dont_rewrite]
130 pub lookup_context: ImplLookupContextId<'db>,
131}
132impl<'db> ImplVar<'db> {
133 pub fn intern(&self, db: &'db dyn Database) -> ImplVarId<'db> {
134 self.clone().intern(db)
135 }
136}
137
138#[derive(
140 Clone, Debug, PartialEq, Eq, Hash, DebugWithDb, SemanticObject, HeapSize, salsa::SalsaValue,
141)]
142#[debug_db(dyn Database)]
143pub struct NegativeImplVar<'db> {
144 pub inference_id: InferenceId<'db>,
145 #[dont_rewrite]
146 pub id: LocalNegativeImplVarId,
147 pub concrete_trait_id: ConcreteTraitId<'db>,
148 #[dont_rewrite]
149 pub lookup_context: ImplLookupContextId<'db>,
150}
151
152#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, SemanticObject, HeapSize, salsa::SalsaValue)]
153pub struct LocalTypeVarId(pub usize);
154#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, SemanticObject, HeapSize, salsa::SalsaValue)]
155pub struct LocalImplVarId(pub usize);
156
157#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, SemanticObject, HeapSize, salsa::SalsaValue)]
158pub struct LocalNegativeImplVarId(pub usize);
159
160#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, SemanticObject, HeapSize, salsa::SalsaValue)]
161pub struct LocalConstVarId(pub usize);
162
163define_short_id!(ImplVarId, ImplVar<'db>);
164impl<'db> ImplVarId<'db> {
165 pub fn id(&self, db: &dyn Database) -> LocalImplVarId {
166 self.long(db).id
167 }
168 pub fn concrete_trait_id(&self, db: &'db dyn Database) -> ConcreteTraitId<'db> {
169 self.long(db).concrete_trait_id
170 }
171 pub fn lookup_context(&self, db: &'db dyn Database) -> ImplLookupContextId<'db> {
172 self.long(db).lookup_context
173 }
174}
175semantic_object_for_id!(ImplVarId, ImplVar<'a>);
176
177define_short_id!(NegativeImplVarId, NegativeImplVar<'db>);
178impl<'db> NegativeImplVarId<'db> {
179 pub fn id(&self, db: &dyn Database) -> LocalNegativeImplVarId {
180 self.long(db).id
181 }
182 pub fn concrete_trait_id(&self, db: &'db dyn Database) -> ConcreteTraitId<'db> {
183 self.long(db).concrete_trait_id
184 }
185 pub fn lookup_context(&self, db: &'db dyn Database) -> ImplLookupContextId<'db> {
186 self.long(db).lookup_context
187 }
188}
189semantic_object_for_id!(NegativeImplVarId, NegativeImplVar<'a>);
190
191#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, SemanticObject, salsa::SalsaValue)]
192pub enum InferenceVar {
193 Type(LocalTypeVarId),
194 Const(LocalConstVarId),
195 Impl(LocalImplVarId),
196 NegativeImpl(LocalNegativeImplVarId),
197}
198
199#[derive(Clone, Debug, Eq, Hash, PartialEq, DebugWithDb, salsa::SalsaValue)]
201#[debug_db(dyn Database)]
202pub enum InferenceError<'db> {
203 Reported(DiagnosticAdded),
205 Cycle(InferenceVar),
206 TypeKindMismatch {
207 ty0: TypeId<'db>,
208 ty1: TypeId<'db>,
209 },
210 ConstKindMismatch {
211 const0: ConstValueId<'db>,
212 const1: ConstValueId<'db>,
213 },
214 ImplKindMismatch {
215 impl0: ImplId<'db>,
216 impl1: ImplId<'db>,
217 },
218 NegativeImplKindMismatch {
219 impl0: NegativeImplId<'db>,
220 impl1: NegativeImplId<'db>,
221 },
222 GenericArgMismatch {
223 garg0: GenericArgumentId<'db>,
224 garg1: GenericArgumentId<'db>,
225 },
226 TraitMismatch {
227 trt0: TraitId<'db>,
228 trt1: TraitId<'db>,
229 },
230 ImplTypeMismatch {
231 impl_id: ImplId<'db>,
232 trait_type_id: TraitTypeId<'db>,
233 ty0: TypeId<'db>,
234 ty1: TypeId<'db>,
235 },
236 GenericFunctionMismatch {
237 func0: GenericFunctionId<'db>,
238 func1: GenericFunctionId<'db>,
239 },
240 ConstNotInferred,
241 NoImplsFound(ConcreteTraitId<'db>),
244 NoNegativeImplsFound(ConcreteTraitId<'db>),
245 Ambiguity(Ambiguity<'db>),
246 TypeNotInferred(TypeId<'db>),
247 InvalidLiteralType(TypeId<'db>),
249}
250impl<'db> InferenceError<'db> {
251 pub fn format(&self, db: &dyn Database, context_module: ModuleId<'db>) -> String {
252 match self {
253 InferenceError::Reported(_) => "Inference error occurred.".into(),
254 InferenceError::Cycle(_var) => "Inference cycle detected".into(),
255 InferenceError::TypeKindMismatch { ty0, ty1 } => {
256 format!(
257 "Type mismatch: `{}` and `{}`.",
258 ty0.contextualized_path(db, context_module),
259 ty1.contextualized_path(db, context_module)
260 )
261 }
262 InferenceError::ConstKindMismatch { const0, const1 } => {
263 format!(
264 "Const mismatch: `{}` and `{}`.",
265 const0.contextualized_path(db, context_module),
266 const1.contextualized_path(db, context_module)
267 )
268 }
269 InferenceError::ImplKindMismatch { impl0, impl1 } => {
270 format!(
271 "Impl mismatch: `{}` and `{}`.",
272 impl0.contextualized_path(db, context_module),
273 impl1.contextualized_path(db, context_module)
274 )
275 }
276 InferenceError::NegativeImplKindMismatch { impl0, impl1 } => {
277 format!(
278 "Negative impl mismatch: `{:?}` and `{:?}`.",
279 impl0.debug(db),
280 impl1.debug(db)
281 )
282 }
283 InferenceError::GenericArgMismatch { garg0, garg1 } => {
284 format!(
285 "Generic arg mismatch: `{}` and `{}`.",
286 garg0.contextualized_path(db, context_module),
287 garg1.contextualized_path(db, context_module)
288 )
289 }
290 InferenceError::TraitMismatch { trt0, trt1 } => {
291 format!(
292 "Trait mismatch: `{}` and `{}`.",
293 trt0.contextualized_path(db, context_module),
294 trt1.contextualized_path(db, context_module)
295 )
296 }
297 InferenceError::ConstNotInferred => "Failed to infer constant.".into(),
298 InferenceError::NoImplsFound(concrete_trait_id) => {
299 if concrete_trait_id.trait_id(db) == db.core_info().string_literal_trt {
300 let generic_type = extract_matches!(
301 concrete_trait_id.generic_args(db)[0],
302 GenericArgumentId::Type
303 );
304 return format!(
305 "Mismatched types. The type `{}` cannot be created from a string literal.",
306 generic_type.contextualized_path(db, context_module)
307 );
308 }
309 format!(
310 "Trait has no implementation in context: {}.",
311 concrete_trait_id.contextualized_path(db, context_module)
312 )
313 }
314 InferenceError::NoNegativeImplsFound(concrete_trait_id) => {
315 format!(
316 "Trait has implementation in context: {}.",
317 concrete_trait_id.contextualized_path(db, context_module)
318 )
319 }
320 InferenceError::Ambiguity(ambiguity) => ambiguity.format(db, context_module),
321 InferenceError::TypeNotInferred(ty) => {
322 format!(
323 "Type annotations needed. Failed to infer {}.",
324 ty.contextualized_path(db, context_module)
325 )
326 }
327 InferenceError::GenericFunctionMismatch { func0, func1 } => {
328 format!(
329 "Function mismatch: `{}` and `{}`.",
330 func0.contextualized_path(db, context_module),
331 func1.contextualized_path(db, context_module)
332 )
333 }
334 InferenceError::ImplTypeMismatch { impl_id, trait_type_id, ty0, ty1 } => {
335 format!(
336 "`{}::{}` type mismatch: `{}` and `{}`.",
337 impl_id.contextualized_path(db, context_module),
338 trait_type_id.name(db).long(db),
339 ty0.contextualized_path(db, context_module),
340 ty1.contextualized_path(db, context_module)
341 )
342 }
343 InferenceError::InvalidLiteralType(ty) => format!(
344 "Mismatched types. The type `{}` cannot be created from a numeric literal.",
345 ty.contextualized_path(db, context_module),
346 ),
347 }
348 }
349}
350
351impl<'db> InferenceError<'db> {
352 pub fn report(
353 &self,
354 diagnostics: &mut SemanticDiagnostics<'db>,
355 stable_ptr: SyntaxStablePtrId<'db>,
356 ) -> DiagnosticAdded {
357 match self {
358 InferenceError::Reported(diagnostic_added) => *diagnostic_added,
359 _ => diagnostics
360 .report(stable_ptr, SemanticDiagnosticKind::InternalInferenceError(self.clone())),
361 }
362 }
363}
364
365#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
370pub struct ErrorSet;
371
372pub type InferenceResult<T> = Result<T, ErrorSet>;
373
374#[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::SalsaValue)]
375enum InferenceErrorStatus<'db> {
376 Pending(PendingInferenceError<'db>),
378 Consumed(DiagnosticAdded),
380}
381
382#[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::SalsaValue)]
384struct PendingInferenceError<'db> {
385 err: InferenceError<'db>,
387 stable_ptr: Option<SyntaxStablePtrId<'db>>,
389}
390
391#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, SemanticObject, salsa::SalsaValue)]
393pub struct ImplVarTraitItemMappings<'db> {
394 types: OrderedHashMap<TraitTypeId<'db>, TypeId<'db>>,
396 constants: OrderedHashMap<TraitConstantId<'db>, ConstValueId<'db>>,
398 impls: OrderedHashMap<TraitImplId<'db>, ImplId<'db>>,
400}
401
402impl ImplVarTraitItemMappings<'_> {
403 pub fn is_empty(&self) -> bool {
405 self.types.is_empty() && self.constants.is_empty() && self.impls.is_empty()
406 }
407}
408
409#[derive(Debug, DebugWithDb, PartialEq, Eq, salsa::SalsaValue)]
411#[debug_db(dyn Database)]
412pub struct InferenceData<'db> {
413 pub inference_id: InferenceId<'db>,
414 pub type_assignment: OrderedHashMap<LocalTypeVarId, TypeId<'db>>,
416 pub const_assignment: OrderedHashMap<LocalConstVarId, ConstValueId<'db>>,
418 pub impl_assignment: OrderedHashMap<LocalImplVarId, ImplId<'db>>,
420 pub negative_impl_assignment: OrderedHashMap<LocalNegativeImplVarId, NegativeImplId<'db>>,
422 pub impl_vars_trait_item_mappings: HashMap<LocalImplVarId, ImplVarTraitItemMappings<'db>>,
425 pub type_vars: Vec<TypeVar<'db>>,
427 pub integer_literal_vars: Vec<LocalTypeVarId>,
431 pub const_vars: Vec<ConstVar<'db>>,
433 pub impl_vars: Vec<ImplVar<'db>>,
435 pub negative_impl_vars: Vec<NegativeImplVar<'db>>,
437 pub stable_ptrs: HashMap<InferenceVar, SyntaxStablePtrId<'db>>,
439 pending: Deque<LocalImplVarId>,
441 negative_pending: Deque<LocalNegativeImplVarId>,
443 refuted: Vec<LocalImplVarId>,
445 negative_refuted: Vec<LocalNegativeImplVarId>,
447 solved: Vec<LocalImplVarId>,
449 ambiguous: Vec<(LocalImplVarId, Ambiguity<'db>)>,
451 negative_ambiguous: Vec<(LocalNegativeImplVarId, Ambiguity<'db>)>,
453 pub impl_type_bounds: Arc<OrderedHashMap<ImplTypeId<'db>, TypeId<'db>>>,
455
456 error_status: Result<(), InferenceErrorStatus<'db>>,
458}
459impl<'db> InferenceData<'db> {
460 pub fn new(inference_id: InferenceId<'db>) -> Self {
461 Self {
462 inference_id,
463 type_assignment: OrderedHashMap::default(),
464 impl_assignment: OrderedHashMap::default(),
465 const_assignment: OrderedHashMap::default(),
466 negative_impl_assignment: OrderedHashMap::default(),
467 impl_vars_trait_item_mappings: HashMap::new(),
468 type_vars: Vec::new(),
469 integer_literal_vars: Vec::new(),
470 impl_vars: Vec::new(),
471 const_vars: Vec::new(),
472 negative_impl_vars: Vec::new(),
473 stable_ptrs: HashMap::new(),
474 pending: Deque::new(),
475 negative_pending: Deque::new(),
476 refuted: Vec::new(),
477 negative_refuted: Vec::new(),
478 solved: Vec::new(),
479 ambiguous: Vec::new(),
480 negative_ambiguous: Vec::new(),
481 impl_type_bounds: Default::default(),
482 error_status: Ok(()),
483 }
484 }
485 pub fn inference<'r>(&'r mut self, db: &'db dyn Database) -> Inference<'db, 'r> {
486 Inference::new(db, self)
487 }
488 pub fn clone_with_inference_id(
489 &self,
490 db: &'db dyn Database,
491 inference_id: InferenceId<'db>,
492 ) -> InferenceData<'db> {
493 let mut inference_id_replacer =
494 InferenceIdReplacer::new(db, self.inference_id, inference_id);
495 Self {
496 inference_id,
497 type_assignment: self
498 .type_assignment
499 .iter()
500 .map(|(k, v)| (*k, inference_id_replacer.rewrite(*v).no_err()))
501 .collect(),
502 const_assignment: self
503 .const_assignment
504 .iter()
505 .map(|(k, v)| (*k, inference_id_replacer.rewrite(*v).no_err()))
506 .collect(),
507 impl_assignment: self
508 .impl_assignment
509 .iter()
510 .map(|(k, v)| (*k, inference_id_replacer.rewrite(*v).no_err()))
511 .collect(),
512 negative_impl_assignment: self
513 .negative_impl_assignment
514 .iter()
515 .map(|(k, v)| (*k, inference_id_replacer.rewrite(*v).no_err()))
516 .collect(),
517 impl_vars_trait_item_mappings: self
518 .impl_vars_trait_item_mappings
519 .iter()
520 .map(|(k, mappings)| {
521 (
522 *k,
523 ImplVarTraitItemMappings {
524 types: mappings
525 .types
526 .iter()
527 .map(|(k, v)| (*k, inference_id_replacer.rewrite(*v).no_err()))
528 .collect(),
529 constants: mappings
530 .constants
531 .iter()
532 .map(|(k, v)| (*k, inference_id_replacer.rewrite(*v).no_err()))
533 .collect(),
534 impls: mappings
535 .impls
536 .iter()
537 .map(|(k, v)| (*k, inference_id_replacer.rewrite(*v).no_err()))
538 .collect(),
539 },
540 )
541 })
542 .collect(),
543 type_vars: inference_id_replacer.rewrite(self.type_vars.clone()).no_err(),
544 integer_literal_vars: self.integer_literal_vars.clone(),
545 const_vars: inference_id_replacer.rewrite(self.const_vars.clone()).no_err(),
546 impl_vars: inference_id_replacer.rewrite(self.impl_vars.clone()).no_err(),
547 negative_impl_vars: inference_id_replacer
548 .rewrite(self.negative_impl_vars.clone())
549 .no_err(),
550 stable_ptrs: self.stable_ptrs.clone(),
551 pending: inference_id_replacer.rewrite(self.pending.clone()).no_err(),
552 negative_pending: inference_id_replacer.rewrite(self.negative_pending.clone()).no_err(),
553 refuted: inference_id_replacer.rewrite(self.refuted.clone()).no_err(),
554 negative_refuted: inference_id_replacer.rewrite(self.negative_refuted.clone()).no_err(),
555 solved: inference_id_replacer.rewrite(self.solved.clone()).no_err(),
556 ambiguous: inference_id_replacer.rewrite(self.ambiguous.clone()).no_err(),
557 negative_ambiguous: inference_id_replacer
558 .rewrite(self.negative_ambiguous.clone())
559 .no_err(),
560 impl_type_bounds: self.impl_type_bounds.clone(),
562
563 error_status: self.error_status.clone(),
564 }
565 }
566 pub fn temporary_clone(&self) -> InferenceData<'db> {
567 Self {
568 inference_id: self.inference_id,
569 type_assignment: self.type_assignment.clone(),
570 const_assignment: self.const_assignment.clone(),
571 impl_assignment: self.impl_assignment.clone(),
572 negative_impl_assignment: self.negative_impl_assignment.clone(),
573 impl_vars_trait_item_mappings: self.impl_vars_trait_item_mappings.clone(),
574 type_vars: self.type_vars.clone(),
575 integer_literal_vars: self.integer_literal_vars.clone(),
576 const_vars: self.const_vars.clone(),
577 impl_vars: self.impl_vars.clone(),
578 negative_impl_vars: self.negative_impl_vars.clone(),
579 stable_ptrs: self.stable_ptrs.clone(),
580 pending: self.pending.clone(),
581 negative_pending: self.negative_pending.clone(),
582 refuted: self.refuted.clone(),
583 negative_refuted: self.negative_refuted.clone(),
584 solved: self.solved.clone(),
585 ambiguous: self.ambiguous.clone(),
586 negative_ambiguous: self.negative_ambiguous.clone(),
587 impl_type_bounds: self.impl_type_bounds.clone(),
588 error_status: self.error_status.clone(),
589 }
590 }
591}
592
593pub struct Inference<'db, 'id> {
595 db: &'db dyn Database,
596 pub data: &'id mut InferenceData<'db>,
597}
598
599impl<'db, 'id> Deref for Inference<'db, 'id> {
600 type Target = InferenceData<'db>;
601
602 fn deref(&self) -> &Self::Target {
603 self.data
604 }
605}
606impl DerefMut for Inference<'_, '_> {
607 fn deref_mut(&mut self) -> &mut Self::Target {
608 self.data
609 }
610}
611
612impl std::fmt::Debug for Inference<'_, '_> {
613 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
614 let x = self.data.debug(self.db);
615 write!(f, "{x:?}")
616 }
617}
618
619impl<'db, 'id> Inference<'db, 'id> {
620 fn new(db: &'db dyn Database, data: &'id mut InferenceData<'db>) -> Self {
621 Self { db, data }
622 }
623
624 fn impl_var(&self, var_id: LocalImplVarId) -> &ImplVar<'db> {
626 &self.impl_vars[var_id.0]
627 }
628
629 pub fn impl_assignment(&self, var_id: LocalImplVarId) -> Option<ImplId<'db>> {
631 self.impl_assignment.get(&var_id).copied()
632 }
633
634 fn negative_impl_var(&self, var_id: LocalNegativeImplVarId) -> &NegativeImplVar<'db> {
636 &self.negative_impl_vars[var_id.0]
637 }
638
639 pub fn negative_impl_assignment(
641 &self,
642 var_id: LocalNegativeImplVarId,
643 ) -> Option<NegativeImplId<'db>> {
644 self.negative_impl_assignment.get(&var_id).copied()
645 }
646
647 fn type_assignment(&self, var_id: LocalTypeVarId) -> Option<TypeId<'db>> {
649 self.type_assignment.get(&var_id).copied()
650 }
651
652 pub fn new_type_var(&mut self, stable_ptr: Option<SyntaxStablePtrId<'db>>) -> TypeId<'db> {
655 let var = self.new_type_var_raw(stable_ptr);
656
657 TypeLongId::Var(var).intern(self.db)
658 }
659
660 pub fn new_integer_literal_type(
665 &mut self,
666 stable_ptr: Option<SyntaxStablePtrId<'db>>,
667 ) -> TypeId<'db> {
668 let var = self.new_type_var_raw(stable_ptr);
669 self.data.integer_literal_vars.push(var.id);
670 TypeLongId::NumericLiteral(var).intern(self.db)
671 }
672
673 pub fn new_type_var_raw(&mut self, stable_ptr: Option<SyntaxStablePtrId<'db>>) -> TypeVar<'db> {
676 let var =
677 TypeVar { inference_id: self.inference_id, id: LocalTypeVarId(self.type_vars.len()) };
678 if let Some(stable_ptr) = stable_ptr {
679 self.stable_ptrs.insert(InferenceVar::Type(var.id), stable_ptr);
680 }
681 self.type_vars.push(var);
682 var
683 }
684
685 pub fn set_impl_type_bounds(
688 &mut self,
689 impl_type_bounds: OrderedHashMap<ImplTypeId<'db>, TypeId<'db>>,
690 ) {
691 let impl_type_bounds_finalized = impl_type_bounds
692 .iter()
693 .filter_map(|(impl_type, ty)| {
694 let rewritten_type = self.rewrite(ty.long(self.db).clone()).no_err();
695 if !matches!(rewritten_type, TypeLongId::Var(_) | TypeLongId::NumericLiteral(_)) {
696 return Some((*impl_type, rewritten_type.intern(self.db)));
697 }
698 self.conform_ty(*ty, TypeLongId::ImplType(*impl_type).intern(self.db)).ok();
701 None
702 })
703 .collect();
704
705 self.data.impl_type_bounds = Arc::new(impl_type_bounds_finalized);
706 }
707
708 pub fn new_const_var(
711 &mut self,
712 stable_ptr: Option<SyntaxStablePtrId<'db>>,
713 ty: TypeId<'db>,
714 ) -> ConstValueId<'db> {
715 let var = self.new_const_var_raw(stable_ptr);
716 ConstValue::Var(var, ty).intern(self.db)
717 }
718
719 pub fn new_const_var_raw(
722 &mut self,
723 stable_ptr: Option<SyntaxStablePtrId<'db>>,
724 ) -> ConstVar<'db> {
725 let var = ConstVar {
726 inference_id: self.inference_id,
727 id: LocalConstVarId(self.const_vars.len()),
728 };
729 if let Some(stable_ptr) = stable_ptr {
730 self.stable_ptrs.insert(InferenceVar::Const(var.id), stable_ptr);
731 }
732 self.const_vars.push(var);
733 var
734 }
735
736 pub fn new_impl_var(
739 &mut self,
740 concrete_trait_id: ConcreteTraitId<'db>,
741 stable_ptr: Option<SyntaxStablePtrId<'db>>,
742 lookup_context: ImplLookupContextId<'db>,
743 ) -> ImplId<'db> {
744 let var = self.new_impl_var_raw(lookup_context, concrete_trait_id, stable_ptr);
745 ImplLongId::ImplVar(self.impl_var(var).intern(self.db)).intern(self.db)
746 }
747
748 fn new_impl_var_raw(
751 &mut self,
752 lookup_context: ImplLookupContextId<'db>,
753 concrete_trait_id: ConcreteTraitId<'db>,
754 stable_ptr: Option<SyntaxStablePtrId<'db>>,
755 ) -> LocalImplVarId {
756 let id = LocalImplVarId(self.impl_vars.len());
757 if let Some(stable_ptr) = stable_ptr {
758 self.stable_ptrs.insert(InferenceVar::Impl(id), stable_ptr);
759 }
760 let var =
761 ImplVar { inference_id: self.inference_id, id, concrete_trait_id, lookup_context };
762 self.impl_vars.push(var);
763 self.pending.push_back(id);
764 id
765 }
766
767 pub fn new_negative_impl_var(
770 &mut self,
771 concrete_trait_id: ConcreteTraitId<'db>,
772 stable_ptr: Option<SyntaxStablePtrId<'db>>,
773 lookup_context: ImplLookupContextId<'db>,
774 ) -> NegativeImplId<'db> {
775 let var = self.new_negative_impl_var_raw(lookup_context, concrete_trait_id, stable_ptr);
776 NegativeImplLongId::NegativeImplVar(self.negative_impl_var(var).clone().intern(self.db))
777 .intern(self.db)
778 }
779
780 fn new_negative_impl_var_raw(
783 &mut self,
784 lookup_context: ImplLookupContextId<'db>,
785 concrete_trait_id: ConcreteTraitId<'db>,
786 stable_ptr: Option<SyntaxStablePtrId<'db>>,
787 ) -> LocalNegativeImplVarId {
788 let id = LocalNegativeImplVarId(self.negative_impl_vars.len());
789 if let Some(stable_ptr) = stable_ptr {
790 self.stable_ptrs.insert(InferenceVar::NegativeImpl(id), stable_ptr);
791 }
792 let var = NegativeImplVar {
793 inference_id: self.inference_id,
794 id,
795 concrete_trait_id,
796 lookup_context,
797 };
798 self.negative_impl_vars.push(var);
799 self.negative_pending.push_back(id);
800 id
801 }
802
803 pub fn solve(&mut self) -> InferenceResult<()> {
808 let ambiguous = std::mem::take(&mut self.ambiguous).into_iter();
809 self.pending.extend(ambiguous.map(|(var, _)| var));
810 while let Some(var) = self.pending.pop_front() {
811 self.solve_single_pending(var).inspect_err(|_err_set| {
813 self.add_error_stable_ptr(InferenceVar::Impl(var));
814 })?;
815 }
816 while let Some(var) = self.negative_pending.pop_front() {
817 self.solve_single_negative_pending(var).inspect_err(|_err_set| {
819 self.add_error_stable_ptr(InferenceVar::NegativeImpl(var));
820 })?;
821 }
822 Ok(())
823 }
824
825 fn solve_single_pending(&mut self, var: LocalImplVarId) -> InferenceResult<()> {
826 if self.impl_assignment.contains_key(&var) {
827 return Ok(());
828 }
829 let solution = match self.impl_var_solution_set(var)? {
830 SolutionSet::None => {
831 self.refuted.push(var);
832 return Ok(());
833 }
834 SolutionSet::Ambiguous(ambiguity) => {
835 self.ambiguous.push((var, ambiguity));
836 return Ok(());
837 }
838 SolutionSet::Unique(solution) => solution,
839 };
840
841 self.assign_local_impl(var, solution)?;
843
844 self.solved.push(var);
846 let ambiguous = std::mem::take(&mut self.ambiguous).into_iter();
847 self.pending.extend(ambiguous.map(|(var, _)| var));
848
849 let negative_ambiguous = std::mem::take(&mut self.negative_ambiguous).into_iter();
850 self.negative_pending.extend(negative_ambiguous.map(|(var, _)| var));
851
852 Ok(())
853 }
854
855 fn solve_single_negative_pending(
857 &mut self,
858 var: LocalNegativeImplVarId,
859 ) -> InferenceResult<()> {
860 if self.negative_impl_assignment.contains_key(&var) {
861 return Ok(());
862 }
863
864 let solution = match self.negative_impl_var_solution_set(var)? {
865 SolutionSet::None => {
866 self.negative_refuted.push(var);
867 return Ok(());
868 }
869 SolutionSet::Ambiguous(ambiguity) => {
870 self.negative_ambiguous.push((var, ambiguity));
871 return Ok(());
872 }
873 SolutionSet::Unique(solution) => solution,
874 };
875
876 self.assign_local_negative_impl(var, solution)?;
878
879 Ok(())
880 }
881
882 pub fn solution_set(&mut self) -> InferenceResult<SolutionSet<'db, ()>> {
885 self.solve()?;
886 if !self.refuted.is_empty() {
887 return Ok(SolutionSet::None);
888 }
889 if !self.negative_refuted.is_empty() {
890 return Ok(SolutionSet::None);
891 }
892 if let Some((_, ambiguity)) = self.ambiguous.first() {
893 return Ok(SolutionSet::Ambiguous(ambiguity.clone()));
894 }
895 if let Some((_, ambiguity)) = self.negative_ambiguous.first() {
896 return Ok(SolutionSet::Ambiguous(ambiguity.clone()));
897 }
898 assert!(self.pending.is_empty(), "solution() called on an unsolved solver");
899 assert!(self.negative_pending.is_empty(), "solution() called on an unsolved solver");
900 Ok(SolutionSet::Unique(()))
901 }
902
903 pub fn finalize_without_reporting(&mut self) -> Result<(), ErrorSet> {
906 if self.error_status.is_err() {
907 return Err(ErrorSet);
908 }
909 let felt_ty = self.db.core_info().felt252;
910
911 loop {
918 self.solve()?;
919 let mut changed = false;
920 for var_id in self.data.integer_literal_vars.clone() {
921 if self.type_assignment.contains_key(&var_id) {
922 continue;
923 }
924 let var = self.type_vars[var_id.0];
925 let placeholder = TypeLongId::NumericLiteral(var).intern(self.db);
926 if self.rewrite(placeholder).no_err() == felt_ty {
927 continue;
928 }
929 self.conform_ty(placeholder, felt_ty).inspect_err(|_err_set| {
930 self.add_error_stable_ptr(InferenceVar::Type(var_id));
931 })?;
932 changed = true;
933 break;
934 }
935 if !changed {
936 break;
937 }
938 }
939 assert!(
940 self.pending.is_empty(),
941 "pending should all be solved by this point. Guaranteed by solve()."
942 );
943
944 for var_id in self.data.integer_literal_vars.clone() {
947 let Some(bound) = self.type_assignment.get(&var_id).copied() else {
948 continue;
949 };
950 let bound = self.rewrite(bound).no_err();
951 if !bound.is_var_free(self.db) || is_valid_literal_type(self.db, bound) {
952 continue;
953 }
954 let err = self.set_error(InferenceError::InvalidLiteralType(bound));
955 self.add_error_stable_ptr(InferenceVar::Type(var_id));
956 return Err(err);
957 }
958
959 let assignments: Vec<_> = self.impl_assignment.iter().map(|(k, v)| (*k, *v)).collect();
962 for (var_id, impl_id) in assignments {
963 let rewritten = self.rewrite(impl_id).no_err();
964 if rewritten != impl_id {
965 self.impl_assignment.insert(var_id, rewritten);
966 }
967 }
968
969 let Some((var, err)) = self.first_undetermined_variable() else {
970 return Ok(());
971 };
972 Err(self.set_error_on_var(err, var))
973 }
974
975 pub fn finalize<'m>(
979 &'m mut self,
980 diagnostics: &mut SemanticDiagnostics<'db>,
981 stable_ptr: SyntaxStablePtrId<'db>,
982 ) {
983 if let Err(err_set) = self.finalize_without_reporting() {
984 let diag = self.report_on_pending_error(err_set, diagnostics, stable_ptr);
985
986 let ty_missing = TypeId::missing(self.db, diag);
987 for var in &self.data.type_vars {
988 self.data.type_assignment.entry(var.id).or_insert(ty_missing);
989 }
990 }
991 }
992
993 fn first_undetermined_variable(&mut self) -> Option<(InferenceVar, InferenceError<'db>)> {
997 if let Some(var) = self.refuted.first().copied() {
998 let impl_var = self.impl_var(var).clone();
999 let concrete_trait_id = impl_var.concrete_trait_id;
1000 let concrete_trait_id = self.rewrite(concrete_trait_id).no_err();
1001 return Some((
1002 InferenceVar::Impl(var),
1003 InferenceError::NoImplsFound(concrete_trait_id),
1004 ));
1005 }
1006 if let Some(var) = self.negative_refuted.first().copied() {
1007 let negative_impl_var = self.negative_impl_var(var).clone();
1008 let concrete_trait_id = negative_impl_var.concrete_trait_id;
1009 let concrete_trait_id = self.rewrite(concrete_trait_id).no_err();
1010 return Some((
1011 InferenceVar::NegativeImpl(var),
1012 InferenceError::NoNegativeImplsFound(concrete_trait_id),
1013 ));
1014 }
1015
1016 let mut fallback_ret = None;
1017 if let Some((var, ambiguity)) = self.ambiguous.first() {
1018 let ret =
1020 Some((InferenceVar::Impl(*var), InferenceError::Ambiguity(ambiguity.clone())));
1021 if !matches!(ambiguity, Ambiguity::WillNotInfer(_)) {
1022 return ret;
1023 } else {
1024 fallback_ret = ret;
1025 }
1026 }
1027 if let Some((var, ambiguity)) = self.negative_ambiguous.first() {
1028 let ret = Some((
1029 InferenceVar::NegativeImpl(*var),
1030 InferenceError::Ambiguity(ambiguity.clone()),
1031 ));
1032 if !matches!(ambiguity, Ambiguity::WillNotInfer(_)) {
1033 return ret;
1034 } else {
1035 fallback_ret = ret;
1036 }
1037 }
1038 for (id, var) in self.type_vars.iter().enumerate() {
1039 if self.type_assignment(LocalTypeVarId(id)).is_none() {
1040 let ty = TypeLongId::Var(*var).intern(self.db);
1041 return Some((InferenceVar::Type(var.id), InferenceError::TypeNotInferred(ty)));
1042 }
1043 }
1044 for (id, var) in self.const_vars.iter().enumerate() {
1045 if !self.const_assignment.contains_key(&LocalConstVarId(id)) {
1046 let infernence_var = InferenceVar::Const(var.id);
1047 return Some((infernence_var, InferenceError::ConstNotInferred));
1048 }
1049 }
1050 fallback_ret
1051 }
1052
1053 fn assign_local_impl(
1055 &mut self,
1056 var: LocalImplVarId,
1057 impl_id: ImplId<'db>,
1058 ) -> InferenceResult<ImplId<'db>> {
1059 let concrete_trait = impl_id
1060 .concrete_trait(self.db)
1061 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
1062 self.conform_traits(self.impl_var(var).concrete_trait_id, concrete_trait)?;
1063 if let Some(other_impl) = self.impl_assignment(var) {
1064 return self.conform_impl(impl_id, other_impl);
1065 }
1066 if !impl_id.is_var_free(self.db) && self.impl_contains_var(impl_id, InferenceVar::Impl(var))
1067 {
1068 let inference_var = InferenceVar::Impl(var);
1069 return Err(self.set_error_on_var(InferenceError::Cycle(inference_var), inference_var));
1070 }
1071 self.impl_assignment.insert(var, impl_id);
1072 if let Some(mappings) = self.impl_vars_trait_item_mappings.remove(&var) {
1073 for (trait_type_id, ty) in mappings.types {
1074 let impl_ty = self
1075 .db
1076 .impl_type_concrete_implized(ImplTypeId::new(impl_id, trait_type_id, self.db))
1077 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
1078 if let Err(err_set) = self.conform_ty(ty, impl_ty) {
1079 let ty0 = self.rewrite(ty).no_err();
1081 let ty1 = self.rewrite(impl_ty).no_err();
1082
1083 let err = InferenceError::ImplTypeMismatch { impl_id, trait_type_id, ty0, ty1 };
1084 self.error_status = Err(InferenceErrorStatus::Pending(PendingInferenceError {
1085 err,
1086 stable_ptr: self.stable_ptrs.get(&InferenceVar::Impl(var)).cloned(),
1087 }));
1088 return Err(err_set);
1089 }
1090 }
1091 for (trait_constant, constant_id) in mappings.constants {
1092 let concrete_impl_constant = self
1093 .db
1094 .impl_constant_concrete_implized_value(ImplConstantId::new(
1095 impl_id,
1096 trait_constant,
1097 self.db,
1098 ))
1099 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
1100 self.conform_const(constant_id, concrete_impl_constant)?;
1101 }
1102 for (trait_impl, inner_impl_id) in mappings.impls {
1103 let concrete_impl_impl = self
1104 .db
1105 .impl_impl_concrete_implized(ImplImplId::new(impl_id, trait_impl, self.db))
1106 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
1107 self.conform_impl(inner_impl_id, concrete_impl_impl)?;
1108 }
1109 }
1110 Ok(impl_id)
1111 }
1112
1113 fn assign_impl(
1115 &mut self,
1116 var_id: ImplVarId<'db>,
1117 impl_id: ImplId<'db>,
1118 ) -> InferenceResult<ImplId<'db>> {
1119 let var = var_id.long(self.db);
1120 if var.inference_id != self.inference_id {
1121 return Err(self.set_error(InferenceError::ImplKindMismatch {
1122 impl0: ImplLongId::ImplVar(var_id).intern(self.db),
1123 impl1: impl_id,
1124 }));
1125 }
1126 self.assign_local_impl(var.id, impl_id)
1127 }
1128
1129 fn assign_local_negative_impl(
1131 &mut self,
1132 var: LocalNegativeImplVarId,
1133 neg_impl_id: NegativeImplId<'db>,
1134 ) -> InferenceResult<NegativeImplId<'db>> {
1135 let concrete_trait = neg_impl_id
1136 .concrete_trait(self.db)
1137 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
1138 self.conform_traits(self.negative_impl_var(var).concrete_trait_id, concrete_trait)?;
1139 if let Some(other_impl) = self.negative_impl_assignment(var) {
1140 return self.conform_neg_impl(neg_impl_id, other_impl);
1141 }
1142 if !neg_impl_id.is_var_free(self.db)
1143 && self.negative_impl_contains_var(neg_impl_id, InferenceVar::NegativeImpl(var))
1144 {
1145 return Err(self.set_error(InferenceError::Cycle(InferenceVar::NegativeImpl(var))));
1146 }
1147 self.negative_impl_assignment.insert(var, neg_impl_id);
1148 Ok(neg_impl_id)
1149 }
1150
1151 fn assign_neg_impl(
1154 &mut self,
1155 var_id: NegativeImplVarId<'db>,
1156 neg_impl_id: NegativeImplId<'db>,
1157 ) -> InferenceResult<NegativeImplId<'db>> {
1158 let var = var_id.long(self.db);
1159 if var.inference_id != self.inference_id {
1160 return Err(self.set_error(InferenceError::NegativeImplKindMismatch {
1161 impl0: NegativeImplLongId::NegativeImplVar(var_id).intern(self.db),
1162 impl1: neg_impl_id,
1163 }));
1164 }
1165 self.assign_local_negative_impl(var.id, neg_impl_id)
1166 }
1167
1168 fn assign_ty(&mut self, var: TypeVar<'db>, ty: TypeId<'db>) -> InferenceResult<TypeId<'db>> {
1171 if var.inference_id != self.inference_id {
1172 return Err(self.set_error(InferenceError::TypeKindMismatch {
1173 ty0: TypeLongId::Var(var).intern(self.db),
1174 ty1: ty,
1175 }));
1176 }
1177 assert!(!self.type_assignment.contains_key(&var.id), "Cannot reassign variable.");
1178 let inference_var = InferenceVar::Type(var.id);
1179 if !ty.is_var_free(self.db) && self.ty_contains_var(ty, inference_var) {
1180 return Err(self.set_error_on_var(InferenceError::Cycle(inference_var), inference_var));
1181 }
1182 if let TypeLongId::Var(other) = ty.long(self.db)
1184 && other.inference_id == self.inference_id
1185 && other.id.0 > var.id.0
1186 {
1187 let var_ty = TypeLongId::Var(var).intern(self.db);
1188 self.type_assignment.insert(other.id, var_ty);
1189 return Ok(var_ty);
1190 }
1191 self.type_assignment.insert(var.id, ty);
1192 Ok(ty)
1193 }
1194
1195 fn assign_const(
1198 &mut self,
1199 var: ConstVar<'db>,
1200 id: ConstValueId<'db>,
1201 ) -> InferenceResult<ConstValueId<'db>> {
1202 if var.inference_id != self.inference_id {
1203 return Err(self.set_error(InferenceError::ConstKindMismatch {
1204 const0: ConstValue::Var(var, TypeId::missing(self.db, skip_diagnostic()))
1205 .intern(self.db),
1206 const1: id,
1207 }));
1208 }
1209
1210 self.const_assignment.insert(var.id, id);
1211 Ok(id)
1212 }
1213
1214 fn impl_var_solution_set(
1216 &mut self,
1217 var: LocalImplVarId,
1218 ) -> InferenceResult<SolutionSet<'db, ImplId<'db>>> {
1219 let impl_var = self.impl_var(var).clone();
1220 let concrete_trait_id = self.rewrite(impl_var.concrete_trait_id).no_err();
1222 self.impl_vars[impl_var.id.0].concrete_trait_id = concrete_trait_id;
1223 let impl_var_trait_item_mappings =
1224 self.impl_vars_trait_item_mappings.get(&var).cloned().unwrap_or_default();
1225 let solution_set = self.trait_solution_set(
1226 concrete_trait_id,
1227 impl_var_trait_item_mappings,
1228 impl_var.lookup_context,
1229 )?;
1230 Ok(match solution_set {
1231 SolutionSet::None => SolutionSet::None,
1232 SolutionSet::Unique((canonical_impl, canonicalizer)) => {
1233 SolutionSet::Unique(canonical_impl.embed(self, &canonicalizer))
1234 }
1235 SolutionSet::Ambiguous(ambiguity) => SolutionSet::Ambiguous(ambiguity),
1236 })
1237 }
1238
1239 fn negative_impl_var_solution_set(
1241 &mut self,
1242 var: LocalNegativeImplVarId,
1243 ) -> InferenceResult<SolutionSet<'db, NegativeImplId<'db>>> {
1244 let negative_impl_var = self.negative_impl_var(var).clone();
1245 let concrete_trait_id = self.rewrite(negative_impl_var.concrete_trait_id).no_err();
1246
1247 let solution_set =
1248 self.validate_no_solution_set(concrete_trait_id, negative_impl_var.lookup_context)?;
1249 Ok(match solution_set {
1250 SolutionSet::Unique(concrete_trait_id) => {
1251 SolutionSet::Unique(NegativeImplLongId::Solved(concrete_trait_id).intern(self.db))
1252 }
1253 SolutionSet::Ambiguous(ambiguity) => SolutionSet::Ambiguous(ambiguity),
1254 SolutionSet::None => SolutionSet::None,
1255 })
1256 }
1257
1258 fn validate_no_solution_set(
1260 &mut self,
1261 concrete_trait_id: ConcreteTraitId<'db>,
1262 lookup_context: ImplLookupContextId<'db>,
1263 ) -> InferenceResult<SolutionSet<'db, ConcreteTraitId<'db>>> {
1264 for negative_impl in &lookup_context.long(self.db).negative_impls {
1265 let generic_param = self
1266 .db
1267 .generic_param_semantic(*negative_impl)
1268 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
1269 if let GenericParam::NegImpl(neg_impl) = generic_param
1270 && Ok(concrete_trait_id) == neg_impl.concrete_trait
1271 {
1272 return Ok(SolutionSet::Unique(concrete_trait_id));
1273 }
1274 }
1275
1276 let generic_args = concrete_trait_id.generic_args(self.db);
1277 if generic_args.iter().any(|garg| {
1281 matches!(
1282 garg,
1283 GenericArgumentId::Type(ty)
1284 if !matches!(
1285 ty.long(self.db),
1286 TypeLongId::Closure(_) | TypeLongId::NumericLiteral(_)
1287 )
1288 && !ty.is_var_free(self.db)
1289 )
1290 }) {
1291 return Ok(SolutionSet::Ambiguous(Ambiguity::WillNotInfer(concrete_trait_id)));
1292 }
1293
1294 let mut neg_impl_generic_params = OrderedHashSet::default();
1295 let mut visited_types = OrderedHashSet::default();
1296 for garg in generic_args {
1297 if garg
1298 .extract_generic_params(self.db, &mut neg_impl_generic_params, &mut visited_types)
1299 .is_err()
1300 {
1301 return Ok(SolutionSet::Ambiguous(
1302 Ambiguity::NegativeImplWithUnsupportedExtractedArgs(*garg),
1303 ));
1304 }
1305 }
1306
1307 let solution_set = if neg_impl_generic_params.is_empty() {
1308 self.trait_solution_set(
1309 concrete_trait_id,
1310 ImplVarTraitItemMappings::default(),
1311 lookup_context,
1312 )?
1313 } else {
1314 let mut substitution: OrderedHashMap<GenericParamId<'db>, GenericArgumentId<'db>> =
1315 Default::default();
1316
1317 for param in neg_impl_generic_params {
1318 let garg = match param.kind(self.db) {
1319 GenericKind::Type => GenericArgumentId::Type(
1320 self.new_type_var(Some(param.stable_ptr(self.db).untyped())),
1321 ),
1322 GenericKind::Const | GenericKind::Impl | GenericKind::NegImpl => {
1323 return Ok(SolutionSet::Ambiguous(
1324 Ambiguity::NegativeImplWithUnsupportedGenericParam(param),
1325 ));
1326 }
1327 };
1328
1329 substitution.insert(param, garg);
1330 }
1331 let rewritten_concrete_trait_id =
1332 GenericSubstitution { param_to_arg: substitution.clone(), self_impl: None }
1333 .substitute(self.db, concrete_trait_id)
1334 .unwrap();
1335
1336 let solution_set = self.trait_solution_set(
1337 rewritten_concrete_trait_id,
1338 ImplVarTraitItemMappings::default(),
1339 lookup_context,
1340 )?;
1341
1342 let db = self.db;
1345 for (generic_param, garg) in substitution {
1346 let GenericArgumentId::Type(ty) = garg else {
1347 panic!("Expected a type variable");
1348 };
1349 let (TypeLongId::Var(var) | TypeLongId::NumericLiteral(var)) = ty.long(self.db)
1350 else {
1351 panic!("Expected a type variable");
1352 };
1353 self.type_assignment
1354 .entry(var.id)
1355 .or_insert_with(|| TypeLongId::GenericParameter(generic_param).intern(db));
1356 }
1357
1358 solution_set
1359 };
1360
1361 if !matches!(solution_set, SolutionSet::None) {
1362 return Ok(SolutionSet::None);
1363 }
1364
1365 Ok(SolutionSet::Unique(concrete_trait_id))
1366 }
1367
1368 pub fn trait_solution_set(
1370 &mut self,
1371 concrete_trait_id: ConcreteTraitId<'db>,
1372 impl_var_trait_item_mappings: ImplVarTraitItemMappings<'db>,
1373 lookup_context_id: ImplLookupContextId<'db>,
1374 ) -> InferenceResult<SolutionSet<'db, (CanonicalImpl<'db>, CanonicalMapping<'db>)>> {
1375 let impl_var_trait_item_mappings = self.rewrite(impl_var_trait_item_mappings).no_err();
1376 let concrete_trait_id = self.rewrite(concrete_trait_id).no_err();
1378 let lookup_context = lookup_context_id.enriched(self.db, concrete_trait_id);
1379
1380 let generic_args = concrete_trait_id.generic_args(self.db);
1382 match generic_args.first() {
1383 Some(GenericArgumentId::Type(ty)) => {
1384 if let TypeLongId::Var(_) = ty.long(self.db) {
1385 return Ok(SolutionSet::Ambiguous(Ambiguity::WillNotInfer(concrete_trait_id)));
1387 }
1388 }
1389 Some(GenericArgumentId::Impl(imp)) => {
1390 if let ImplLongId::ImplVar(_) = imp.long(self.db) {
1392 return Ok(SolutionSet::Ambiguous(Ambiguity::WillNotInfer(concrete_trait_id)));
1393 }
1394 }
1395 Some(GenericArgumentId::Constant(const_value)) => {
1396 if let ConstValue::Var(_, _) = const_value.long(self.db) {
1397 return Ok(SolutionSet::Ambiguous(Ambiguity::WillNotInfer(concrete_trait_id)));
1399 }
1400 }
1401 _ => {}
1402 };
1403 let (canonical_trait, canonicalizer) = CanonicalTrait::canonicalize(
1404 self.db,
1405 self.inference_id,
1406 concrete_trait_id,
1407 impl_var_trait_item_mappings,
1408 );
1409 let solution_set = match self.db.canonic_trait_solutions(
1412 canonical_trait,
1413 lookup_context,
1414 (*self.data.impl_type_bounds).clone(),
1415 ) {
1416 Ok(solution_set) => solution_set,
1417 Err(err) => return Err(self.set_error(err)),
1418 };
1419 match solution_set {
1420 SolutionSet::None => Ok(SolutionSet::None),
1421 SolutionSet::Unique(canonical_impl) => {
1422 Ok(SolutionSet::Unique((canonical_impl, canonicalizer)))
1423 }
1424 SolutionSet::Ambiguous(ambiguity) => Ok(SolutionSet::Ambiguous(ambiguity)),
1425 }
1426 }
1427
1428 pub fn set_error(&mut self, err: InferenceError<'db>) -> ErrorSet {
1435 self.set_error_ex(err, None)
1436 }
1437
1438 pub fn set_error_ex(
1442 &mut self,
1443 err: InferenceError<'db>,
1444 stable_ptr: Option<SyntaxStablePtrId<'db>>,
1445 ) -> ErrorSet {
1446 if self.error_status.is_err() {
1447 return ErrorSet;
1448 }
1449 self.error_status = Err(if let InferenceError::Reported(diag_added) = err {
1450 InferenceErrorStatus::Consumed(diag_added)
1451 } else {
1452 InferenceErrorStatus::Pending(PendingInferenceError { err, stable_ptr })
1453 });
1454 ErrorSet
1455 }
1456
1457 pub fn set_error_on_var(&mut self, err: InferenceError<'db>, var: InferenceVar) -> ErrorSet {
1461 self.set_error_ex(err, self.stable_ptrs.get(&var).cloned())
1462 }
1463
1464 pub fn is_error_set(&self) -> InferenceResult<()> {
1466 self.error_status.as_ref().copied().map_err(|_| ErrorSet)
1467 }
1468
1469 fn add_error_stable_ptr(&mut self, var: InferenceVar) {
1471 let var_stable_ptr = self.stable_ptrs.get(&var).copied();
1472 if let Err(InferenceErrorStatus::Pending(PendingInferenceError { err: _, stable_ptr })) =
1473 &mut self.error_status
1474 && stable_ptr.is_none()
1475 {
1476 *stable_ptr = var_stable_ptr;
1477 }
1478 }
1479
1480 pub fn consume_error_without_reporting(
1486 &mut self,
1487 err_set: ErrorSet,
1488 ) -> Option<InferenceError<'db>> {
1489 Some(self.consume_error_inner(err_set, skip_diagnostic())?.err)
1490 }
1491
1492 pub fn consume_reported_error(&mut self, err_set: ErrorSet, diag_added: DiagnosticAdded) {
1499 self.consume_error_inner(err_set, diag_added);
1500 }
1501
1502 fn consume_error_inner(
1509 &mut self,
1510 _err_set: ErrorSet,
1511 diag_added: DiagnosticAdded,
1512 ) -> Option<PendingInferenceError<'db>> {
1513 match &mut self.error_status {
1514 Err(InferenceErrorStatus::Pending(error)) => {
1515 let pending_error = std::mem::replace(
1516 error,
1517 PendingInferenceError {
1518 err: InferenceError::Reported(diag_added),
1519 stable_ptr: None,
1520 },
1521 );
1522 self.error_status = Err(InferenceErrorStatus::Consumed(diag_added));
1523 Some(pending_error)
1524 }
1525 _ => None,
1527 }
1528 }
1529
1530 pub fn report_on_pending_error(
1536 &mut self,
1537 _err_set: ErrorSet,
1538 diagnostics: &mut SemanticDiagnostics<'db>,
1539 stable_ptr: SyntaxStablePtrId<'db>,
1540 ) -> DiagnosticAdded {
1541 let Err(state_error) = &self.error_status else {
1542 panic!("report_on_pending_error should be called only on error");
1543 };
1544 match state_error {
1545 InferenceErrorStatus::Consumed(diag_added) => *diag_added,
1546 InferenceErrorStatus::Pending(pending) => {
1547 let diag_added = match &pending.err {
1548 InferenceError::TypeNotInferred(_) if diagnostics.error_count > 0 => {
1549 skip_diagnostic()
1554 }
1555 diag => diag.report(diagnostics, pending.stable_ptr.unwrap_or(stable_ptr)),
1556 };
1557 self.error_status = Err(InferenceErrorStatus::Consumed(diag_added));
1558 diag_added
1559 }
1560 }
1561 }
1562
1563 pub fn report_modified_if_pending(
1566 &mut self,
1567 err_set: ErrorSet,
1568 report: impl FnOnce() -> DiagnosticAdded,
1569 ) {
1570 if matches!(self.error_status, Err(InferenceErrorStatus::Pending { .. })) {
1571 self.consume_reported_error(err_set, report());
1572 }
1573 }
1574}
1575
1576impl<'a, 'mt> HasDb<&'a dyn Database> for Inference<'a, 'mt> {
1577 fn get_db(&self) -> &'a dyn Database {
1578 self.db
1579 }
1580}
1581add_basic_rewrites!(<'a, 'mt>, Inference<'a, 'mt>, NoError, @exclude TypeLongId TypeId ImplLongId ImplId ConstValue NegativeImplLongId NegativeImplId);
1582add_expr_rewrites!(<'a, 'mt>, Inference<'a, 'mt>, NoError, @exclude);
1583add_rewrite!(<'a, 'mt>, Inference<'a, 'mt>, NoError, Ambiguity<'a>);
1584impl<'db, 'mt> SemanticRewriter<TypeId<'db>, NoError> for Inference<'db, 'mt> {
1585 fn internal_rewrite(&mut self, value: &mut TypeId<'db>) -> Result<RewriteResult, NoError> {
1586 if value.is_var_free(self.db) {
1587 return Ok(RewriteResult::NoChange);
1588 }
1589 value.default_rewrite(self)
1590 }
1591}
1592impl<'db, 'mt> SemanticRewriter<ImplId<'db>, NoError> for Inference<'db, 'mt> {
1593 fn internal_rewrite(&mut self, value: &mut ImplId<'db>) -> Result<RewriteResult, NoError> {
1594 if value.is_var_free(self.db) {
1595 return Ok(RewriteResult::NoChange);
1596 }
1597 value.default_rewrite(self)
1598 }
1599}
1600impl<'db, 'mt> SemanticRewriter<NegativeImplId<'db>, NoError> for Inference<'db, 'mt> {
1601 fn internal_rewrite(
1602 &mut self,
1603 value: &mut NegativeImplId<'db>,
1604 ) -> Result<RewriteResult, NoError> {
1605 if value.is_var_free(self.db) {
1606 return Ok(RewriteResult::NoChange);
1607 }
1608 value.default_rewrite(self)
1609 }
1610}
1611
1612impl<'db, 'mt> SemanticRewriter<TypeLongId<'db>, NoError> for Inference<'db, 'mt> {
1613 fn internal_rewrite(&mut self, value: &mut TypeLongId<'db>) -> Result<RewriteResult, NoError> {
1614 match value {
1615 TypeLongId::Var(var) | TypeLongId::NumericLiteral(var) => {
1616 if let Some(type_id) = self.type_assignment.get(&var.id) {
1617 let mut long_type_id = type_id.long(self.db).clone();
1618 if let RewriteResult::Modified = self.internal_rewrite(&mut long_type_id)? {
1619 *self.type_assignment.get_mut(&var.id).unwrap() =
1620 long_type_id.clone().intern(self.db);
1621 }
1622 *value = long_type_id;
1623 return Ok(RewriteResult::Modified);
1624 }
1625 }
1626 TypeLongId::ImplType(impl_type_id) => {
1627 if let Some(type_id) = self.impl_type_bounds.get(impl_type_id) {
1628 *value = type_id.long(self.db).clone();
1629 self.internal_rewrite(value)?;
1630 return Ok(RewriteResult::Modified);
1631 }
1632 let impl_type_id_rewrite_result = self.internal_rewrite(impl_type_id)?;
1633 let impl_id = impl_type_id.impl_id();
1634 let trait_ty = impl_type_id.ty();
1635 return Ok(match impl_id.long(self.db) {
1636 ImplLongId::GenericParameter(_)
1637 | ImplLongId::SelfImpl(_)
1638 | ImplLongId::ImplImpl(_) => impl_type_id_rewrite_result,
1639 ImplLongId::Concrete(_) => {
1640 if let Ok(ty) = self.db.impl_type_concrete_implized(ImplTypeId::new(
1641 impl_id, trait_ty, self.db,
1642 )) {
1643 *value = self.rewrite(ty).no_err().long(self.db).clone();
1644 RewriteResult::Modified
1645 } else {
1646 impl_type_id_rewrite_result
1647 }
1648 }
1649 ImplLongId::ImplVar(var) => {
1650 *value = self.rewritten_impl_type(*var, trait_ty).long(self.db).clone();
1651 return Ok(RewriteResult::Modified);
1652 }
1653 ImplLongId::GeneratedImpl(generated) => {
1654 *value = self
1655 .rewrite(
1656 *generated
1657 .long(self.db)
1658 .impl_items
1659 .0
1660 .get(&impl_type_id.ty())
1661 .unwrap(),
1662 )
1663 .no_err()
1664 .long(self.db)
1665 .clone();
1666 RewriteResult::Modified
1667 }
1668 });
1669 }
1670 _ => {}
1671 }
1672 value.default_rewrite(self)
1673 }
1674}
1675impl<'db, 'mt> SemanticRewriter<ConstValue<'db>, NoError> for Inference<'db, 'mt> {
1676 fn internal_rewrite(&mut self, value: &mut ConstValue<'db>) -> Result<RewriteResult, NoError> {
1677 match value {
1678 ConstValue::Var(var, _) => {
1679 return Ok(if let Some(const_value_id) = self.const_assignment.get(&var.id) {
1680 let mut const_value = const_value_id.long(self.db).clone();
1681 if let RewriteResult::Modified = self.internal_rewrite(&mut const_value)? {
1682 *self.const_assignment.get_mut(&var.id).unwrap() =
1683 const_value.clone().intern(self.db);
1684 }
1685 *value = const_value;
1686 RewriteResult::Modified
1687 } else {
1688 RewriteResult::NoChange
1689 });
1690 }
1691 ConstValue::ImplConstant(impl_constant_id) => {
1692 let impl_constant_id_rewrite_result = self.internal_rewrite(impl_constant_id)?;
1693 let impl_id = impl_constant_id.impl_id();
1694 let trait_constant = impl_constant_id.trait_constant_id();
1695 return Ok(match impl_id.long(self.db) {
1696 ImplLongId::GenericParameter(_)
1697 | ImplLongId::SelfImpl(_)
1698 | ImplLongId::GeneratedImpl(_)
1699 | ImplLongId::ImplImpl(_) => impl_constant_id_rewrite_result,
1700 ImplLongId::Concrete(_) => {
1701 if let Ok(constant) = self.db.impl_constant_concrete_implized_value(
1702 ImplConstantId::new(impl_id, trait_constant, self.db),
1703 ) {
1704 *value = self.rewrite(constant).no_err().long(self.db).clone();
1705 RewriteResult::Modified
1706 } else {
1707 impl_constant_id_rewrite_result
1708 }
1709 }
1710 ImplLongId::ImplVar(var) => {
1711 *value = self
1712 .rewritten_impl_constant(*var, trait_constant)
1713 .long(self.db)
1714 .clone();
1715 return Ok(RewriteResult::Modified);
1716 }
1717 });
1718 }
1719 _ => {}
1720 }
1721 value.default_rewrite(self)
1722 }
1723}
1724impl<'db, 'mt> SemanticRewriter<ImplLongId<'db>, NoError> for Inference<'db, 'mt> {
1725 fn internal_rewrite(&mut self, value: &mut ImplLongId<'db>) -> Result<RewriteResult, NoError> {
1726 match value {
1727 ImplLongId::ImplVar(var) => {
1728 let long_id = var.long(self.db);
1729 let impl_var_id = long_id.id;
1731 if let Some(impl_id) = self.impl_assignment(impl_var_id) {
1732 let mut long_impl_id = impl_id.long(self.db).clone();
1733 if let RewriteResult::Modified = self.internal_rewrite(&mut long_impl_id)? {
1734 *self.impl_assignment.get_mut(&impl_var_id).unwrap() =
1735 long_impl_id.clone().intern(self.db);
1736 }
1737 *value = long_impl_id;
1738 return Ok(RewriteResult::Modified);
1739 }
1740 }
1741 ImplLongId::GeneratedImpl(generated) => {
1742 let inner_result = generated.default_rewrite(self)?;
1744 let concrete_trait = generated.concrete_trait(self.db);
1745 if let Some(GenericArgumentId::Type(first_ty)) =
1746 concrete_trait.generic_args(self.db).first().copied()
1747 && !matches!(
1748 first_ty.long(self.db),
1749 TypeLongId::Closure(_)
1750 | TypeLongId::Var(_)
1751 | TypeLongId::NumericLiteral(_)
1752 | TypeLongId::ImplType(_)
1753 )
1754 {
1755 let info = self.db.core_info();
1756 let trait_id = concrete_trait.trait_id(self.db);
1757 if [info.drop_trt, info.copy_trt, info.destruct_trt, info.panic_destruct_trt]
1758 .contains(&trait_id)
1759 {
1760 let lookup_context =
1763 ImplLookupContext::new_from_type(first_ty, self.db).intern(self.db);
1764 if let Ok(real_impl) =
1765 get_impl_at_context(self.db, lookup_context, concrete_trait, None)
1766 {
1767 *value = real_impl.long(self.db).clone();
1768 return Ok(RewriteResult::Modified);
1769 }
1770 }
1771 }
1772 return Ok(inner_result);
1773 }
1774 ImplLongId::ImplImpl(impl_impl_id) => {
1775 let impl_impl_id_rewrite_result = self.internal_rewrite(impl_impl_id)?;
1776 let impl_id = impl_impl_id.impl_id();
1777 return Ok(match impl_id.long(self.db) {
1778 ImplLongId::GenericParameter(_)
1779 | ImplLongId::SelfImpl(_)
1780 | ImplLongId::GeneratedImpl(_)
1781 | ImplLongId::ImplImpl(_) => impl_impl_id_rewrite_result,
1782 ImplLongId::Concrete(_) => {
1783 if let Ok(imp) = self.db.impl_impl_concrete_implized(*impl_impl_id) {
1784 *value = self.rewrite(imp).no_err().long(self.db).clone();
1785 RewriteResult::Modified
1786 } else {
1787 impl_impl_id_rewrite_result
1788 }
1789 }
1790 ImplLongId::ImplVar(var) => {
1791 if let Ok(concrete_trait_impl) =
1792 impl_impl_id.concrete_trait_impl_id(self.db)
1793 {
1794 *value = self
1795 .rewritten_impl_impl(*var, concrete_trait_impl)
1796 .long(self.db)
1797 .clone();
1798 return Ok(RewriteResult::Modified);
1799 } else {
1800 impl_impl_id_rewrite_result
1801 }
1802 }
1803 });
1804 }
1805
1806 _ => {}
1807 }
1808 if value.is_var_free(self.db) {
1809 return Ok(RewriteResult::NoChange);
1810 }
1811 value.default_rewrite(self)
1812 }
1813}
1814
1815impl<'db, 'mt> SemanticRewriter<NegativeImplLongId<'db>, NoError> for Inference<'db, 'mt> {
1816 fn internal_rewrite(
1817 &mut self,
1818 value: &mut NegativeImplLongId<'db>,
1819 ) -> Result<RewriteResult, NoError> {
1820 if let NegativeImplLongId::NegativeImplVar(var) = value {
1821 let long_id = var.long(self.db);
1822 let neg_impl_var_id = long_id.id;
1824 if let Some(impl_id) = self.negative_impl_assignment(neg_impl_var_id) {
1825 let mut long_neg_impl_id = impl_id.long(self.db).clone();
1826 if let RewriteResult::Modified = self.internal_rewrite(&mut long_neg_impl_id)? {
1827 *self.negative_impl_assignment.get_mut(&neg_impl_var_id).unwrap() =
1828 long_neg_impl_id.clone().intern(self.db);
1829 }
1830 *value = long_neg_impl_id;
1831 return Ok(RewriteResult::Modified);
1832 }
1833 }
1834
1835 if value.is_var_free(self.db) {
1836 return Ok(RewriteResult::NoChange);
1837 }
1838 value.default_rewrite(self)
1839 }
1840}
1841
1842struct InferenceIdReplacer<'a> {
1843 db: &'a dyn Database,
1844 from_inference_id: InferenceId<'a>,
1845 to_inference_id: InferenceId<'a>,
1846}
1847impl<'a> InferenceIdReplacer<'a> {
1848 fn new(
1849 db: &'a dyn Database,
1850 from_inference_id: InferenceId<'a>,
1851 to_inference_id: InferenceId<'a>,
1852 ) -> Self {
1853 Self { db, from_inference_id, to_inference_id }
1854 }
1855}
1856impl<'a> HasDb<&'a dyn Database> for InferenceIdReplacer<'a> {
1857 fn get_db(&self) -> &'a dyn Database {
1858 self.db
1859 }
1860}
1861add_basic_rewrites!(<'a>, InferenceIdReplacer<'a>, NoError, @exclude InferenceId);
1862add_expr_rewrites!(<'a>, InferenceIdReplacer<'a>, NoError, @exclude);
1863add_rewrite!(<'a>, InferenceIdReplacer<'a>, NoError, Ambiguity<'a>);
1864impl<'a> SemanticRewriter<InferenceId<'a>, NoError> for InferenceIdReplacer<'a> {
1865 fn internal_rewrite(&mut self, value: &mut InferenceId<'a>) -> Result<RewriteResult, NoError> {
1866 if value == &self.from_inference_id {
1867 *value = self.to_inference_id;
1868 Ok(RewriteResult::Modified)
1869 } else {
1870 Ok(RewriteResult::NoChange)
1871 }
1872 }
1873}