1use std::{fmt, mem};
4
5use chalk_ir::{
6 CanonicalVarKind, FloatTy, IntTy, TyVariableKind, UniverseIndex, cast::Cast,
7 fold::TypeFoldable, interner::HasInterner, zip::Zip,
8};
9use chalk_solve::infer::ParameterEnaVariableExt;
10use either::Either;
11use ena::unify::UnifyKey;
12use hir_def::{AdtId, lang_item::LangItem};
13use hir_expand::name::Name;
14use intern::sym;
15use rustc_hash::FxHashMap;
16use smallvec::SmallVec;
17use triomphe::Arc;
18
19use super::{InferOk, InferResult, InferenceContext, TypeError};
20use crate::{
21 AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal,
22 GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime,
23 OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment,
24 TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause,
25 consteval::unknown_const,
26 db::HirDatabase,
27 fold_generic_args, fold_tys_and_consts, to_chalk_trait_id,
28 traits::{FnTrait, NextTraitSolveResult},
29};
30
31impl InferenceContext<'_> {
32 pub(super) fn canonicalize<T>(&mut self, t: T) -> Canonical<T>
33 where
34 T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
35 {
36 self.table.canonicalize(t)
37 }
38
39 pub(super) fn clauses_for_self_ty(
40 &mut self,
41 self_ty: InferenceVar,
42 ) -> SmallVec<[WhereClause; 4]> {
43 self.table.resolve_obligations_as_possible();
44
45 let root = self.table.var_unification_table.inference_var_root(self_ty);
46 let pending_obligations = mem::take(&mut self.table.pending_obligations);
47 let obligations = pending_obligations
48 .iter()
49 .filter_map(|obligation| match obligation.value.value.goal.data(Interner) {
50 GoalData::DomainGoal(DomainGoal::Holds(clause)) => {
51 let ty = match clause {
52 WhereClause::AliasEq(AliasEq {
53 alias: AliasTy::Projection(projection),
54 ..
55 }) => projection.self_type_parameter(self.db),
56 WhereClause::Implemented(trait_ref) => {
57 trait_ref.self_type_parameter(Interner)
58 }
59 WhereClause::TypeOutlives(to) => to.ty.clone(),
60 _ => return None,
61 };
62
63 let uncanonical =
64 chalk_ir::Substitute::apply(&obligation.free_vars, ty, Interner);
65 if matches!(
66 self.resolve_ty_shallow(&uncanonical).kind(Interner),
67 TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root,
68 ) {
69 Some(chalk_ir::Substitute::apply(
70 &obligation.free_vars,
71 clause.clone(),
72 Interner,
73 ))
74 } else {
75 None
76 }
77 }
78 _ => None,
79 })
80 .collect();
81 self.table.pending_obligations = pending_obligations;
82
83 obligations
84 }
85}
86
87#[derive(Debug, Clone)]
88pub(crate) struct Canonicalized<T>
89where
90 T: HasInterner<Interner = Interner>,
91{
92 pub(crate) value: Canonical<T>,
93 free_vars: Vec<GenericArg>,
94}
95
96impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
97 pub(crate) fn apply_solution(
98 &self,
99 ctx: &mut InferenceTable<'_>,
100 solution: Canonical<Substitution>,
101 ) {
102 let new_vars = Substitution::from_iter(
104 Interner,
105 solution.binders.iter(Interner).map(|k| match &k.kind {
106 VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner),
107 VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner),
108 VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner),
109 VariableKind::Lifetime => ctx.new_lifetime_var().cast(Interner),
112 VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner),
113 }),
114 );
115 for (i, v) in solution.value.iter(Interner).enumerate() {
116 let var = &self.free_vars[i];
117 if let Some(ty) = v.ty(Interner) {
118 let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner));
121 tracing::debug!("unifying {:?} {:?}", var, ty);
122 ctx.unify(var.assert_ty_ref(Interner), &ty);
123 } else {
124 let v = new_vars.apply(v.clone(), Interner);
125 tracing::debug!("try_unifying {:?} {:?}", var, v);
126 let _ = ctx.try_unify(var, &v);
127 }
128 }
129 }
130}
131
132pub fn could_unify(
139 db: &dyn HirDatabase,
140 env: Arc<TraitEnvironment>,
141 tys: &Canonical<(Ty, Ty)>,
142) -> bool {
143 unify(db, env, tys).is_some()
144}
145
146pub fn could_unify_deeply(
151 db: &dyn HirDatabase,
152 env: Arc<TraitEnvironment>,
153 tys: &Canonical<(Ty, Ty)>,
154) -> bool {
155 let mut table = InferenceTable::new(db, env);
156 let vars = make_substitutions(tys, &mut table);
157 let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
158 let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
159 let ty1_with_vars = table.normalize_associated_types_in(ty1_with_vars);
160 let ty2_with_vars = table.normalize_associated_types_in(ty2_with_vars);
161 table.resolve_obligations_as_possible();
162 table.propagate_diverging_flag();
163 let ty1_with_vars = table.resolve_completely(ty1_with_vars);
164 let ty2_with_vars = table.resolve_completely(ty2_with_vars);
165 table.unify_deeply(&ty1_with_vars, &ty2_with_vars)
166}
167
168pub(crate) fn unify(
169 db: &dyn HirDatabase,
170 env: Arc<TraitEnvironment>,
171 tys: &Canonical<(Ty, Ty)>,
172) -> Option<Substitution> {
173 let mut table = InferenceTable::new(db, env);
174 let vars = make_substitutions(tys, &mut table);
175 let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
176 let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
177 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
178 return None;
179 }
180 let find_var = |iv| {
183 vars.iter(Interner).position(|v| match v.data(Interner) {
184 GenericArgData::Ty(ty) => ty.inference_var(Interner),
185 GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
186 GenericArgData::Const(c) => c.inference_var(Interner),
187 } == Some(iv))
188 };
189 let fallback = |iv, kind, default, binder| match kind {
190 chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
191 .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
192 chalk_ir::VariableKind::Lifetime => find_var(iv)
193 .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
194 chalk_ir::VariableKind::Const(ty) => find_var(iv)
195 .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
196 };
197 Some(Substitution::from_iter(
198 Interner,
199 vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)),
200 ))
201}
202
203fn make_substitutions(
204 tys: &chalk_ir::Canonical<(chalk_ir::Ty<Interner>, chalk_ir::Ty<Interner>)>,
205 table: &mut InferenceTable<'_>,
206) -> chalk_ir::Substitution<Interner> {
207 Substitution::from_iter(
208 Interner,
209 tys.binders.iter(Interner).map(|it| match &it.kind {
210 chalk_ir::VariableKind::Ty(_) => table.new_type_var().cast(Interner),
211 chalk_ir::VariableKind::Lifetime => table.new_type_var().cast(Interner),
213 chalk_ir::VariableKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
214 }),
215 )
216}
217
218bitflags::bitflags! {
219 #[derive(Default, Clone, Copy)]
220 pub(crate) struct TypeVariableFlags: u8 {
221 const DIVERGING = 1 << 0;
222 const INTEGER = 1 << 1;
223 const FLOAT = 1 << 2;
224 }
225}
226
227type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
228
229#[derive(Clone)]
230pub(crate) struct InferenceTable<'a> {
231 pub(crate) db: &'a dyn HirDatabase,
232 pub(crate) trait_env: Arc<TraitEnvironment>,
233 pub(crate) tait_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>,
234 var_unification_table: ChalkInferenceTable,
235 type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
236 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
237 resolve_obligations_buffer: Vec<Canonicalized<InEnvironment<Goal>>>,
240}
241
242pub(crate) struct InferenceTableSnapshot {
243 var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
244 type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
245 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
246}
247
248impl<'a> InferenceTable<'a> {
249 pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
250 InferenceTable {
251 db,
252 trait_env,
253 tait_coercion_table: None,
254 var_unification_table: ChalkInferenceTable::new(),
255 type_variable_table: SmallVec::new(),
256 pending_obligations: Vec::new(),
257 resolve_obligations_buffer: Vec::new(),
258 }
259 }
260
261 pub(super) fn propagate_diverging_flag(&mut self) {
268 for i in 0..self.type_variable_table.len() {
269 if !self.type_variable_table[i].contains(TypeVariableFlags::DIVERGING) {
270 continue;
271 }
272 let v = InferenceVar::from(i as u32);
273 let root = self.var_unification_table.inference_var_root(v);
274 self.modify_type_variable_flag(root, |f| {
275 *f |= TypeVariableFlags::DIVERGING;
276 });
277 }
278 }
279
280 pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
281 self.modify_type_variable_flag(iv, |f| {
282 f.set(TypeVariableFlags::DIVERGING, diverging);
283 });
284 }
285
286 fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
287 let is_diverging = self
288 .type_variable_table
289 .get(iv.index() as usize)
290 .is_some_and(|data| data.contains(TypeVariableFlags::DIVERGING));
291 if is_diverging {
292 return TyKind::Never.intern(Interner);
293 }
294 match kind {
295 TyVariableKind::General => TyKind::Error,
296 TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
297 TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
298 }
299 .intern(Interner)
300 }
301
302 pub(crate) fn canonicalize_with_free_vars<T>(&mut self, t: T) -> Canonicalized<T>
303 where
304 T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
305 {
306 self.resolve_obligations_as_possible();
309 let result = self.var_unification_table.canonicalize(Interner, t);
310 let free_vars = result
311 .free_vars
312 .into_iter()
313 .map(|free_var| free_var.to_generic_arg(Interner))
314 .collect();
315 Canonicalized { value: result.quantified, free_vars }
316 }
317
318 pub(crate) fn canonicalize<T>(&mut self, t: T) -> Canonical<T>
319 where
320 T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
321 {
322 self.resolve_obligations_as_possible();
325 self.var_unification_table.canonicalize(Interner, t).quantified
326 }
327
328 #[tracing::instrument(skip(self), ret)]
335 pub(crate) fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
336 where
337 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
338 {
339 fold_tys_and_consts(
340 ty,
341 |e, _| match e {
342 Either::Left(ty) => {
343 let ty = self.resolve_ty_shallow(&ty);
344 tracing::debug!(?ty);
345 Either::Left(match ty.kind(Interner) {
346 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
347 let ty = self.normalize_projection_ty(proj_ty.clone());
348 self.resolve_ty_shallow(&ty)
349 }
350 TyKind::AssociatedType(id, subst) => {
351 if ty.data(Interner).flags.intersects(
352 chalk_ir::TypeFlags::HAS_TY_INFER
353 | chalk_ir::TypeFlags::HAS_CT_INFER,
354 ) {
355 return Either::Left(ty);
356 }
357 let var = self.new_type_var();
358 let proj_ty = chalk_ir::ProjectionTy {
359 associated_ty_id: *id,
360 substitution: subst.clone(),
361 };
362 let normalize = chalk_ir::Normalize {
363 alias: AliasTy::Projection(proj_ty),
364 ty: var.clone(),
365 };
366 let goal = chalk_ir::Goal::new(
367 Interner,
368 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Normalize(
369 normalize,
370 )),
371 );
372 let in_env = InEnvironment::new(&self.trait_env.env, goal);
373
374 let canonicalized = {
375 let result =
376 self.var_unification_table.canonicalize(Interner, in_env);
377 let free_vars = result
378 .free_vars
379 .into_iter()
380 .map(|free_var| free_var.to_generic_arg(Interner))
381 .collect();
382 Canonicalized { value: result.quantified, free_vars }
383 };
384 let solution = self.db.trait_solve(
385 self.trait_env.krate,
386 self.trait_env.block,
387 canonicalized.value.clone(),
388 );
389 if let NextTraitSolveResult::Certain(canonical_subst) = solution {
390 if canonical_subst.value.subst.len(Interner) != 1 {
392 ty
393 } else {
394 let normalized = canonical_subst.value.subst.as_slice(Interner)
395 [0]
396 .assert_ty_ref(Interner);
397 match normalized.kind(Interner) {
398 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
399 if id == &proj_ty.associated_ty_id
400 && subst == &proj_ty.substitution
401 {
402 ty
403 } else {
404 normalized.clone()
405 }
406 }
407 TyKind::AssociatedType(new_id, new_subst) => {
408 if new_id == id && new_subst == subst {
409 ty
410 } else {
411 normalized.clone()
412 }
413 }
414 _ => normalized.clone(),
415 }
416 }
417 } else {
418 ty
419 }
420 }
421 _ => ty,
422 })
423 }
424 Either::Right(c) => Either::Right(match &c.data(Interner).value {
425 chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
426 crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
427 if subst.len(Interner) == 0 {
431 if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) {
432 eval
433 } else {
434 unknown_const(c.data(Interner).ty.clone())
435 }
436 } else {
437 unknown_const(c.data(Interner).ty.clone())
438 }
439 }
440 _ => c,
441 },
442 _ => c,
443 }),
444 },
445 DebruijnIndex::INNERMOST,
446 )
447 }
448
449 pub(crate) fn eagerly_normalize_and_resolve_shallow_in<T>(&mut self, ty: T) -> T
452 where
453 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
454 {
455 fn eagerly_resolve_ty<const N: usize>(
456 table: &mut InferenceTable<'_>,
457 ty: Ty,
458 mut tys: SmallVec<[Ty; N]>,
459 ) -> Ty {
460 if tys.contains(&ty) {
461 return ty;
462 }
463 tys.push(ty.clone());
464
465 match ty.kind(Interner) {
466 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
467 let ty = table.normalize_projection_ty(proj_ty.clone());
468 eagerly_resolve_ty(table, ty, tys)
469 }
470 TyKind::InferenceVar(..) => {
471 let ty = table.resolve_ty_shallow(&ty);
472 eagerly_resolve_ty(table, ty, tys)
473 }
474 _ => ty,
475 }
476 }
477
478 fold_tys_and_consts(
479 ty,
480 |e, _| match e {
481 Either::Left(ty) => {
482 Either::Left(eagerly_resolve_ty::<8>(self, ty, SmallVec::new()))
483 }
484 Either::Right(c) => Either::Right(match &c.data(Interner).value {
485 chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
486 crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
487 if subst.len(Interner) == 0 {
489 if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) {
490 eval
491 } else {
492 unknown_const(c.data(Interner).ty.clone())
493 }
494 } else {
495 unknown_const(c.data(Interner).ty.clone())
496 }
497 }
498 _ => c,
499 },
500 _ => c,
501 }),
502 },
503 DebruijnIndex::INNERMOST,
504 )
505 }
506
507 pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
508 let var = self.new_type_var();
509 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
510 let obligation = alias_eq.cast(Interner);
511 self.register_obligation(obligation);
512 var
513 }
514
515 fn modify_type_variable_flag<F>(&mut self, var: InferenceVar, cb: F)
516 where
517 F: FnOnce(&mut TypeVariableFlags),
518 {
519 let idx = var.index() as usize;
520 if self.type_variable_table.len() <= idx {
521 self.extend_type_variable_table(idx);
522 }
523 if let Some(f) = self.type_variable_table.get_mut(idx) {
524 cb(f);
525 }
526 }
527 fn extend_type_variable_table(&mut self, to_index: usize) {
528 let count = to_index - self.type_variable_table.len() + 1;
529 self.type_variable_table.extend(std::iter::repeat_n(TypeVariableFlags::default(), count));
530 }
531
532 fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
533 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
534 self.extend_type_variable_table(var.index() as usize);
536 assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
537 let flags = self.type_variable_table.get_mut(var.index() as usize).unwrap();
538 if diverging {
539 *flags |= TypeVariableFlags::DIVERGING;
540 }
541 if matches!(kind, TyVariableKind::Integer) {
542 *flags |= TypeVariableFlags::INTEGER;
543 } else if matches!(kind, TyVariableKind::Float) {
544 *flags |= TypeVariableFlags::FLOAT;
545 }
546 var.to_ty_with_kind(Interner, kind)
547 }
548
549 pub(crate) fn new_type_var(&mut self) -> Ty {
550 self.new_var(TyVariableKind::General, false)
551 }
552
553 pub(crate) fn new_integer_var(&mut self) -> Ty {
554 self.new_var(TyVariableKind::Integer, false)
555 }
556
557 pub(crate) fn new_float_var(&mut self) -> Ty {
558 self.new_var(TyVariableKind::Float, false)
559 }
560
561 pub(crate) fn new_maybe_never_var(&mut self) -> Ty {
562 self.new_var(TyVariableKind::General, true)
563 }
564
565 pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const {
566 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
567 var.to_const(Interner, ty)
568 }
569
570 pub(crate) fn new_lifetime_var(&mut self) -> Lifetime {
571 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
572 var.to_lifetime(Interner)
573 }
574
575 pub(crate) fn resolve_with_fallback<T>(
576 &mut self,
577 t: T,
578 fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
579 ) -> T
580 where
581 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
582 {
583 self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
584 }
585
586 pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind<Interner>]) -> Substitution {
587 Substitution::from_iter(
588 Interner,
589 binders.iter().map(|kind| {
590 let param_infer_var =
591 kind.map_ref(|&ui| self.var_unification_table.new_variable(ui));
592 param_infer_var.to_generic_arg(Interner)
593 }),
594 )
595 }
596
597 pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T
598 where
599 T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + std::fmt::Debug,
600 {
601 let subst = self.fresh_subst(canonical.binders.as_slice(Interner));
602 subst.apply(canonical.value, Interner)
603 }
604
605 fn resolve_with_fallback_inner<T>(
606 &mut self,
607 var_stack: &mut Vec<InferenceVar>,
608 t: T,
609 fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
610 ) -> T
611 where
612 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
613 {
614 t.fold_with(
615 &mut resolve::Resolver { table: self, var_stack, fallback },
616 DebruijnIndex::INNERMOST,
617 )
618 }
619
620 pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
621 where
622 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
623 {
624 let t = self.resolve_with_fallback(t, &|_, _, d, _| d);
625 let t = self.normalize_associated_types_in(t);
626 self.resolve_with_fallback(t, &|_, _, d, _| d)
628 }
629
630 pub(super) fn fallback_if_possible(&mut self) {
639 let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
640 let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
641
642 let scalar_vars: Vec<_> = self
643 .type_variable_table
644 .iter()
645 .enumerate()
646 .filter_map(|(index, flags)| {
647 let kind = if flags.contains(TypeVariableFlags::INTEGER) {
648 TyVariableKind::Integer
649 } else if flags.contains(TypeVariableFlags::FLOAT) {
650 TyVariableKind::Float
651 } else {
652 return None;
653 };
654
655 let var = InferenceVar::from(index as u32).to_ty(Interner, kind);
658 Some(var)
659 })
660 .collect();
661
662 for var in scalar_vars {
663 let maybe_resolved = self.resolve_ty_shallow(&var);
664 if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
665 let fallback = match kind {
666 TyVariableKind::Integer => &int_fallback,
667 TyVariableKind::Float => &float_fallback,
668 TyVariableKind::General => unreachable!(),
669 };
670 self.unify(&var, fallback);
671 }
672 }
673 }
674
675 pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
677 let result = match self.try_unify(ty1, ty2) {
678 Ok(r) => r,
679 Err(_) => return false,
680 };
681 self.register_infer_ok(result);
682 true
683 }
684
685 pub(crate) fn unify_deeply<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
687 let result = match self.try_unify(ty1, ty2) {
688 Ok(r) => r,
689 Err(_) => return false,
690 };
691 result.goals.iter().all(|goal| {
692 let canonicalized = self.canonicalize_with_free_vars(goal.clone());
693 self.try_resolve_obligation(&canonicalized).certain()
694 })
695 }
696
697 pub(crate) fn try_unify<T: ?Sized + Zip<Interner>>(
700 &mut self,
701 t1: &T,
702 t2: &T,
703 ) -> InferResult<()> {
704 match self.var_unification_table.relate(
705 Interner,
706 &self.db,
707 &self.trait_env.env,
708 chalk_ir::Variance::Invariant,
709 t1,
710 t2,
711 ) {
712 Ok(result) => Ok(InferOk { goals: result.goals, value: () }),
713 Err(chalk_ir::NoSolution) => Err(TypeError),
714 }
715 }
716
717 pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
720 if !ty.data(Interner).flags.intersects(chalk_ir::TypeFlags::HAS_FREE_LOCAL_NAMES) {
721 return ty.clone();
722 }
723 self.resolve_obligations_as_possible();
724 self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone())
725 }
726
727 pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
728 let var_table_snapshot = self.var_unification_table.snapshot();
729 let type_variable_table = self.type_variable_table.clone();
730 let pending_obligations = self.pending_obligations.clone();
731 InferenceTableSnapshot { var_table_snapshot, pending_obligations, type_variable_table }
732 }
733
734 #[tracing::instrument(skip_all)]
735 pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
736 self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
737 self.type_variable_table = snapshot.type_variable_table;
738 self.pending_obligations = snapshot.pending_obligations;
739 }
740
741 #[tracing::instrument(skip_all)]
742 pub(crate) fn run_in_snapshot<T>(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T {
743 let snapshot = self.snapshot();
744 let result = f(self);
745 self.rollback_to(snapshot);
746 result
747 }
748
749 #[tracing::instrument(level = "debug", skip(self))]
753 pub(crate) fn try_obligation(&mut self, goal: Goal) -> NextTraitSolveResult {
754 let in_env = InEnvironment::new(&self.trait_env.env, goal);
755 let canonicalized = self.canonicalize(in_env);
756
757 self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized)
758 }
759
760 pub(crate) fn register_obligation(&mut self, goal: Goal) {
761 let in_env = InEnvironment::new(&self.trait_env.env, goal);
762 self.register_obligation_in_env(in_env)
763 }
764
765 #[tracing::instrument(level = "debug", skip(self))]
766 fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
767 match goal.goal.data(Interner) {
768 chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
769 chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }),
770 )) => {
771 if ty.inference_var(Interner).is_some() {
772 match alias {
773 chalk_ir::AliasTy::Opaque(opaque) => {
774 if self.unify(
775 &chalk_ir::TyKind::OpaqueType(
776 opaque.opaque_ty_id,
777 opaque.substitution.clone(),
778 )
779 .intern(Interner),
780 ty,
781 ) {
782 return;
783 }
784 }
785 _ => {}
786 }
787 }
788 }
789 _ => {}
790 }
791 let canonicalized = {
792 let result = self.var_unification_table.canonicalize(Interner, goal);
793 let free_vars = result
794 .free_vars
795 .into_iter()
796 .map(|free_var| free_var.to_generic_arg(Interner))
797 .collect();
798 Canonicalized { value: result.quantified, free_vars }
799 };
800 tracing::debug!(?canonicalized);
801 let solution = self.try_resolve_obligation(&canonicalized);
802 tracing::debug!(?solution);
803 if solution.uncertain() {
804 self.pending_obligations.push(canonicalized);
805 }
806 }
807
808 pub(crate) fn register_infer_ok<T>(&mut self, infer_ok: InferOk<T>) {
809 infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal));
810 }
811
812 pub(crate) fn resolve_obligations_as_possible(&mut self) {
813 let _span = tracing::info_span!("resolve_obligations_as_possible").entered();
814 let mut changed = true;
815 let mut obligations = mem::take(&mut self.resolve_obligations_buffer);
816 while mem::take(&mut changed) {
817 mem::swap(&mut self.pending_obligations, &mut obligations);
818
819 for canonicalized in obligations.drain(..) {
820 tracing::debug!(obligation = ?canonicalized);
821 if !self.check_changed(&canonicalized) {
822 tracing::debug!("not changed");
823 self.pending_obligations.push(canonicalized);
824 continue;
825 }
826 changed = true;
827 let uncanonical = chalk_ir::Substitute::apply(
828 &canonicalized.free_vars,
829 canonicalized.value.value,
830 Interner,
831 );
832 self.register_obligation_in_env(uncanonical);
833 }
834 }
835 self.resolve_obligations_buffer = obligations;
836 self.resolve_obligations_buffer.clear();
837 }
838
839 pub(crate) fn fudge_inference<T: TypeFoldable<Interner>>(
840 &mut self,
841 f: impl FnOnce(&mut Self) -> T,
842 ) -> T {
843 use chalk_ir::fold::TypeFolder;
844
845 #[derive(chalk_derive::FallibleTypeFolder)]
846 #[has_interner(Interner)]
847 struct VarFudger<'a, 'b> {
848 table: &'a mut InferenceTable<'b>,
849 highest_known_var: InferenceVar,
850 }
851 impl TypeFolder<Interner> for VarFudger<'_, '_> {
852 fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
853 self
854 }
855
856 fn interner(&self) -> Interner {
857 Interner
858 }
859
860 fn fold_inference_ty(
861 &mut self,
862 var: chalk_ir::InferenceVar,
863 kind: TyVariableKind,
864 _outer_binder: chalk_ir::DebruijnIndex,
865 ) -> chalk_ir::Ty<Interner> {
866 if var < self.highest_known_var {
867 var.to_ty(Interner, kind)
868 } else {
869 self.table.new_type_var()
870 }
871 }
872
873 fn fold_inference_lifetime(
874 &mut self,
875 var: chalk_ir::InferenceVar,
876 _outer_binder: chalk_ir::DebruijnIndex,
877 ) -> chalk_ir::Lifetime<Interner> {
878 if var < self.highest_known_var {
879 var.to_lifetime(Interner)
880 } else {
881 self.table.new_lifetime_var()
882 }
883 }
884
885 fn fold_inference_const(
886 &mut self,
887 ty: chalk_ir::Ty<Interner>,
888 var: chalk_ir::InferenceVar,
889 _outer_binder: chalk_ir::DebruijnIndex,
890 ) -> chalk_ir::Const<Interner> {
891 if var < self.highest_known_var {
892 var.to_const(Interner, ty)
893 } else {
894 self.table.new_const_var(ty)
895 }
896 }
897 }
898
899 let snapshot = self.snapshot();
900 let highest_known_var = self.new_type_var().inference_var(Interner).expect("inference_var");
901 let result = f(self);
902 self.rollback_to(snapshot);
903 result
904 .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
905 }
906
907 fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
912 canonicalized.free_vars.iter().any(|var| {
913 let iv = match var.data(Interner) {
914 GenericArgData::Ty(ty) => ty.inference_var(Interner),
915 GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
916 GenericArgData::Const(c) => c.inference_var(Interner),
917 }
918 .expect("free var is not inference var");
919 if self.var_unification_table.probe_var(iv).is_some() {
920 return true;
921 }
922 let root = self.var_unification_table.inference_var_root(iv);
923 iv != root
924 })
925 }
926
927 #[tracing::instrument(level = "debug", skip(self))]
928 fn try_resolve_obligation(
929 &mut self,
930 canonicalized: &Canonicalized<InEnvironment<Goal>>,
931 ) -> NextTraitSolveResult {
932 let solution = self.db.trait_solve(
933 self.trait_env.krate,
934 self.trait_env.block,
935 canonicalized.value.clone(),
936 );
937
938 tracing::debug!(?solution, ?canonicalized);
939 match &solution {
940 NextTraitSolveResult::Certain(v) => {
941 canonicalized.apply_solution(
942 self,
943 Canonical {
944 binders: v.binders.clone(),
945 value: v.value.subst.clone(),
947 },
948 );
949 }
950 NextTraitSolveResult::Uncertain(v) => {
952 canonicalized.apply_solution(self, v.clone());
953 }
954 NextTraitSolveResult::NoSolution => {}
955 }
956
957 solution
958 }
959
960 pub(crate) fn callable_sig(
961 &mut self,
962 ty: &Ty,
963 num_args: usize,
964 ) -> Option<(Option<FnTrait>, Vec<Ty>, Ty)> {
965 match ty.callable_sig(self.db) {
966 Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())),
967 None => {
968 let (f, args_ty, return_ty) = self.callable_sig_from_fn_trait(ty, num_args)?;
969 Some((Some(f), args_ty, return_ty))
970 }
971 }
972 }
973
974 fn callable_sig_from_fn_trait(
975 &mut self,
976 ty: &Ty,
977 num_args: usize,
978 ) -> Option<(FnTrait, Vec<Ty>, Ty)> {
979 for (fn_trait_name, output_assoc_name, subtraits) in [
980 (FnTrait::FnOnce, sym::Output, &[FnTrait::Fn, FnTrait::FnMut][..]),
981 (FnTrait::AsyncFnMut, sym::CallRefFuture, &[FnTrait::AsyncFn]),
982 (FnTrait::AsyncFnOnce, sym::CallOnceFuture, &[]),
983 ] {
984 let krate = self.trait_env.krate;
985 let fn_trait = fn_trait_name.get_id(self.db, krate)?;
986 let trait_data = fn_trait.trait_items(self.db);
987 let output_assoc_type =
988 trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?;
989
990 let mut arg_tys = Vec::with_capacity(num_args);
991 let arg_ty = TyBuilder::tuple(num_args)
992 .fill(|it| {
993 let arg = match it {
994 ParamKind::Type => self.new_type_var(),
995 ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"),
996 ParamKind::Const(_) => unreachable!("Tuple with const parameter"),
997 };
998 arg_tys.push(arg.clone());
999 arg.cast(Interner)
1000 })
1001 .build();
1002
1003 let b = TyBuilder::trait_ref(self.db, fn_trait);
1004 if b.remaining() != 2 {
1005 return None;
1006 }
1007 let mut trait_ref = b.push(ty.clone()).push(arg_ty).build();
1008
1009 let projection = TyBuilder::assoc_type_projection(
1010 self.db,
1011 output_assoc_type,
1012 Some(trait_ref.substitution.clone()),
1013 )
1014 .fill_with_unknown()
1015 .build();
1016
1017 let trait_env = self.trait_env.env.clone();
1018 let obligation = InEnvironment {
1019 goal: trait_ref.clone().cast(Interner),
1020 environment: trait_env.clone(),
1021 };
1022 let canonical = self.canonicalize(obligation.clone());
1023 if !self
1024 .db
1025 .trait_solve(krate, self.trait_env.block, canonical.cast(Interner))
1026 .no_solution()
1027 {
1028 self.register_obligation(obligation.goal);
1029 let return_ty = self.normalize_projection_ty(projection);
1030 for &fn_x in subtraits {
1031 let fn_x_trait = fn_x.get_id(self.db, krate)?;
1032 trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
1033 let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> =
1034 InEnvironment {
1035 goal: trait_ref.clone().cast(Interner),
1036 environment: trait_env.clone(),
1037 };
1038 let canonical = self.canonicalize(obligation.clone());
1039 if !self
1040 .db
1041 .trait_solve(krate, self.trait_env.block, canonical.cast(Interner))
1042 .no_solution()
1043 {
1044 return Some((fn_x, arg_tys, return_ty));
1045 }
1046 }
1047 return Some((fn_trait_name, arg_tys, return_ty));
1048 }
1049 }
1050 None
1051 }
1052
1053 pub(super) fn insert_type_vars<T>(&mut self, ty: T) -> T
1054 where
1055 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
1056 {
1057 fold_generic_args(
1058 ty,
1059 |arg, _| match arg {
1060 GenericArgData::Ty(ty) => GenericArgData::Ty(self.insert_type_vars_shallow(ty)),
1061 GenericArgData::Lifetime(lt) => GenericArgData::Lifetime(lt),
1064 GenericArgData::Const(c) => {
1065 GenericArgData::Const(self.insert_const_vars_shallow(c))
1066 }
1067 },
1068 DebruijnIndex::INNERMOST,
1069 )
1070 }
1071
1072 pub(super) fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
1074 match ty.kind(Interner) {
1075 TyKind::Error => self.new_type_var(),
1076 TyKind::InferenceVar(..) => {
1077 let ty_resolved = self.resolve_ty_shallow(&ty);
1078 if ty_resolved.is_unknown() { self.new_type_var() } else { ty }
1079 }
1080 _ => ty,
1081 }
1082 }
1083
1084 pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
1086 let data = c.data(Interner);
1087 match &data.value {
1088 ConstValue::Concrete(cc) => match &cc.interned {
1089 crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()),
1090 crate::ConstScalar::UnevaluatedConst(id, subst) => {
1092 if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
1093 eval
1094 } else {
1095 self.new_const_var(data.ty.clone())
1096 }
1097 }
1098 _ => c,
1099 },
1100 _ => c,
1101 }
1102 }
1103
1104 pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
1106 fn short_circuit_trivial_tys(ty: &Ty) -> Option<bool> {
1107 match ty.kind(Interner) {
1108 TyKind::Scalar(..)
1109 | TyKind::Ref(..)
1110 | TyKind::Raw(..)
1111 | TyKind::Never
1112 | TyKind::FnDef(..)
1113 | TyKind::Array(..)
1114 | TyKind::Function(..) => Some(true),
1115 TyKind::Slice(..) | TyKind::Str | TyKind::Dyn(..) => Some(false),
1116 _ => None,
1117 }
1118 }
1119
1120 let mut ty = ty.clone();
1121 ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
1122 if let Some(sized) = short_circuit_trivial_tys(&ty) {
1123 return sized;
1124 }
1125
1126 {
1127 let mut structs = SmallVec::<[_; 8]>::new();
1128 while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
1131 let struct_data = id.fields(self.db);
1132 if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
1133 let last_field_ty = self.db.field_types(id.into())[last_field]
1134 .clone()
1135 .substitute(Interner, subst);
1136 if structs.contains(&ty) {
1137 return true; }
1140 structs.push(ty);
1141 ty = last_field_ty;
1144 ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
1145 if let Some(sized) = short_circuit_trivial_tys(&ty) {
1146 return sized;
1147 }
1148 } else {
1149 break;
1150 };
1151 }
1152 }
1153
1154 let Some(sized) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else {
1155 return false;
1156 };
1157 let sized_pred = WhereClause::Implemented(TraitRef {
1158 trait_id: to_chalk_trait_id(sized),
1159 substitution: Substitution::from1(Interner, ty),
1160 });
1161 let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner);
1162 self.try_obligation(goal).certain()
1163 }
1164}
1165
1166impl fmt::Debug for InferenceTable<'_> {
1167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1168 f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish()
1169 }
1170}
1171
1172mod resolve {
1173 use super::InferenceTable;
1174 use crate::{
1175 ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg,
1176 InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind,
1177 };
1178 use chalk_ir::{
1179 cast::Cast,
1180 fold::{TypeFoldable, TypeFolder},
1181 };
1182
1183 #[derive(chalk_derive::FallibleTypeFolder)]
1184 #[has_interner(Interner)]
1185 pub(super) struct Resolver<
1186 'a,
1187 'b,
1188 F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
1189 > {
1190 pub(super) table: &'a mut InferenceTable<'b>,
1191 pub(super) var_stack: &'a mut Vec<InferenceVar>,
1192 pub(super) fallback: F,
1193 }
1194 impl<F> TypeFolder<Interner> for Resolver<'_, '_, F>
1195 where
1196 F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
1197 {
1198 fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
1199 self
1200 }
1201
1202 fn interner(&self) -> Interner {
1203 Interner
1204 }
1205
1206 fn fold_inference_ty(
1207 &mut self,
1208 var: InferenceVar,
1209 kind: TyVariableKind,
1210 outer_binder: DebruijnIndex,
1211 ) -> Ty {
1212 let var = self.table.var_unification_table.inference_var_root(var);
1213 if self.var_stack.contains(&var) {
1214 let default = self.table.fallback_value(var, kind).cast(Interner);
1216 return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
1217 .assert_ty_ref(Interner)
1218 .clone();
1219 }
1220 if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
1221 self.var_stack.push(var);
1223 let result = known_ty.fold_with(self, outer_binder);
1224 self.var_stack.pop();
1225 result.assert_ty_ref(Interner).clone()
1226 } else {
1227 let default = self.table.fallback_value(var, kind).cast(Interner);
1228 (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
1229 .assert_ty_ref(Interner)
1230 .clone()
1231 }
1232 }
1233
1234 fn fold_inference_const(
1235 &mut self,
1236 ty: Ty,
1237 var: InferenceVar,
1238 outer_binder: DebruijnIndex,
1239 ) -> Const {
1240 let var = self.table.var_unification_table.inference_var_root(var);
1241 let default = ConstData {
1242 ty: ty.clone(),
1243 value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
1244 }
1245 .intern(Interner)
1246 .cast(Interner);
1247 if self.var_stack.contains(&var) {
1248 return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
1250 .assert_const_ref(Interner)
1251 .clone();
1252 }
1253 if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
1254 self.var_stack.push(var);
1256 let result = known_ty.fold_with(self, outer_binder);
1257 self.var_stack.pop();
1258 result.assert_const_ref(Interner).clone()
1259 } else {
1260 (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
1261 .assert_const_ref(Interner)
1262 .clone()
1263 }
1264 }
1265
1266 fn fold_inference_lifetime(
1267 &mut self,
1268 _var: InferenceVar,
1269 _outer_binder: DebruijnIndex,
1270 ) -> Lifetime {
1271 crate::error_lifetime()
1276 }
1277 }
1278}