hir_ty/infer/
unify.rs

1//! Unification and canonicalization logic.
2
3use 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        // the solution may contain new variables, which we need to convert to new inference vars
103        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                // Chalk can sometimes return new lifetime variables. We just replace them by errors
110                // for now.
111                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                // eagerly replace projections in the type; we may be getting types
119                // e.g. from where clauses where this hasn't happened yet
120                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
132/// Check if types unify.
133///
134/// Note that we consider placeholder types to unify with everything.
135/// This means that there may be some unresolved goals that actually set bounds for the placeholder
136/// type for the types to unify. For example `Option<T>` and `Option<U>` unify although there is
137/// unresolved goal `T = U`.
138pub 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
146/// Check if types unify eagerly making sure there are no unresolved goals.
147///
148/// This means that placeholder types are not considered to unify if there are any bounds set on
149/// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
150pub 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    // default any type vars that weren't unified back to their original bound vars
181    // (kind of hacky)
182    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            // FIXME: maybe wrong?
212            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    /// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on
238    /// temporary allocations.
239    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    /// Chalk doesn't know about the `diverging` flag, so when it unifies two
262    /// type variables of which one is diverging, the chosen root might not be
263    /// diverging and we have no way of marking it as such at that time. This
264    /// function goes through all type variables and make sure their root is
265    /// marked as diverging if necessary, so that resolving them gives the right
266    /// result.
267    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        // try to resolve obligations before canonicalizing, since this might
307        // result in new knowledge about variables
308        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        // try to resolve obligations before canonicalizing, since this might
323        // result in new knowledge about variables
324        self.resolve_obligations_as_possible();
325        self.var_unification_table.canonicalize(Interner, t).quantified
326    }
327
328    /// Recurses through the given type, normalizing associated types mentioned
329    /// in it by replacing them by type variables and registering obligations to
330    /// resolve later. This should be done once for every type we get from some
331    /// type annotation (e.g. from a let type annotation, field type or function
332    /// call). `make_ty` handles this already, but e.g. for field types we need
333    /// to do it as well.
334    #[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                                // This is not great :) But let's just assert this for now and come back to it later.
391                                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                            // FIXME: Ideally here we should do everything that we do with type alias, i.e. adding a variable
428                            // and registering an obligation. But it needs chalk support, so we handle the most basic
429                            // case (a non associated const without generic parameters) manually.
430                            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    /// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
450    /// the inference variables
451    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                            // FIXME: same as `normalize_associated_types_in`
488                            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        // Chalk might have created some type variables for its own purposes that we don't know about...
535        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        // Resolve again, because maybe normalization inserted infer vars.
627        self.resolve_with_fallback(t, &|_, _, d, _| d)
628    }
629
630    /// Apply a fallback to unresolved scalar types. Integer type variables and float type
631    /// variables are replaced with i32 and f64, respectively.
632    ///
633    /// This method is only intended to be called just before returning inference results (i.e. in
634    /// `InferenceContext::resolve_all()`).
635    ///
636    /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
637    /// whereas rustc replaces them with `()` or `!`.
638    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                // FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
656                // without directly constructing them from `index`?
657                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    /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
676    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    /// Unify two relatable values (e.g. `Ty`) and check whether trait goals which arise from that could be fulfilled
686    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    /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
698    /// caller needs to deal with them.
699    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    /// If `ty` is a type variable with known type, returns that type;
718    /// otherwise, return ty.
719    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    /// Checks an obligation without registering it. Useful mostly to check
750    /// whether a trait *might* be implemented before deciding to 'lock in' the
751    /// choice (during e.g. method resolution or deref).
752    #[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    /// This checks whether any of the free variables in the `canonicalized`
908    /// have changed (either been unified with another variable, or with a
909    /// value). If this is not the case, we don't need to try to solve the goal
910    /// again -- it'll give the same result as last time.
911    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                        // FIXME handle constraints
946                        value: v.value.subst.clone(),
947                    },
948                );
949            }
950            // ...so, should think about how to get some actually get some guidance here
951            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                // FIXME: insert lifetime vars once LifetimeData::InferenceVar
1062                // and specific error variant for lifetimes start being constructed
1063                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    /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
1073    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    /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
1085    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                // try to evaluate unevaluated const. Replace with new var if const eval failed.
1091                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    /// Check if given type is `Sized` or not
1105    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            // Must use a loop here and not recursion because otherwise users will conduct completely
1129            // artificial examples of structs that have themselves as the tail field and complain r-a crashes.
1130            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                        // A struct recursively contains itself as a tail field somewhere.
1138                        return true; // Don't overload the users with too many errors.
1139                    }
1140                    structs.push(ty);
1141                    // Structs can have DST as its last field and such cases are not handled
1142                    // as unsized by the chalk, so we do this manually.
1143                    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                // recursive type
1215                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                // known_ty may contain other variables that are known by now
1222                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                // recursive
1249                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                // known_ty may contain other variables that are known by now
1255                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            // fall back all lifetimes to 'error -- currently we don't deal
1272            // with any lifetimes, but we can sometimes get some lifetime
1273            // variables through Chalk's unification, and this at least makes
1274            // sure we don't leak them outside of inference
1275            crate::error_lifetime()
1276        }
1277    }
1278}