1 //! Unification and canonicalization logic.
2
3 use std::{fmt, iter, mem};
4
5 use chalk_ir::{
6 cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
7 IntTy, TyVariableKind, UniverseIndex,
8 };
9 use chalk_solve::infer::ParameterEnaVariableExt;
10 use either::Either;
11 use ena::unify::UnifyKey;
12 use hir_expand::name;
13 use stdx::never;
14 use triomphe::Arc;
15
16 use super::{InferOk, InferResult, InferenceContext, TypeError};
17 use crate::{
18 consteval::unknown_const, db::HirDatabase, fold_tys_and_consts, static_lifetime,
19 to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
20 DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment, InferenceVar,
21 Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution,
22 TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
23 };
24
25 impl<'a> InferenceContext<'a> {
canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>( &mut self, t: T, ) -> Canonicalized<T> where T: HasInterner<Interner = Interner>,26 pub(super) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
27 &mut self,
28 t: T,
29 ) -> Canonicalized<T>
30 where
31 T: HasInterner<Interner = Interner>,
32 {
33 self.table.canonicalize(t)
34 }
35 }
36
37 #[derive(Debug, Clone)]
38 pub(crate) struct Canonicalized<T>
39 where
40 T: HasInterner<Interner = Interner>,
41 {
42 pub(crate) value: Canonical<T>,
43 free_vars: Vec<GenericArg>,
44 }
45
46 impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
apply_solution( &self, ctx: &mut InferenceTable<'_>, solution: Canonical<Substitution>, )47 pub(super) fn apply_solution(
48 &self,
49 ctx: &mut InferenceTable<'_>,
50 solution: Canonical<Substitution>,
51 ) {
52 // the solution may contain new variables, which we need to convert to new inference vars
53 let new_vars = Substitution::from_iter(
54 Interner,
55 solution.binders.iter(Interner).map(|k| match &k.kind {
56 VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner),
57 VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner),
58 VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner),
59 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
60 VariableKind::Lifetime => static_lifetime().cast(Interner),
61 VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner),
62 }),
63 );
64 for (i, v) in solution.value.iter(Interner).enumerate() {
65 let var = self.free_vars[i].clone();
66 if let Some(ty) = v.ty(Interner) {
67 // eagerly replace projections in the type; we may be getting types
68 // e.g. from where clauses where this hasn't happened yet
69 let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner));
70 ctx.unify(var.assert_ty_ref(Interner), &ty);
71 } else {
72 let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), Interner));
73 }
74 }
75 }
76 }
77
could_unify( db: &dyn HirDatabase, env: Arc<TraitEnvironment>, tys: &Canonical<(Ty, Ty)>, ) -> bool78 pub fn could_unify(
79 db: &dyn HirDatabase,
80 env: Arc<TraitEnvironment>,
81 tys: &Canonical<(Ty, Ty)>,
82 ) -> bool {
83 unify(db, env, tys).is_some()
84 }
85
unify( db: &dyn HirDatabase, env: Arc<TraitEnvironment>, tys: &Canonical<(Ty, Ty)>, ) -> Option<Substitution>86 pub(crate) fn unify(
87 db: &dyn HirDatabase,
88 env: Arc<TraitEnvironment>,
89 tys: &Canonical<(Ty, Ty)>,
90 ) -> Option<Substitution> {
91 let mut table = InferenceTable::new(db, env);
92 let vars = Substitution::from_iter(
93 Interner,
94 tys.binders.iter(Interner).map(|x| match &x.kind {
95 chalk_ir::VariableKind::Ty(_) => {
96 GenericArgData::Ty(table.new_type_var()).intern(Interner)
97 }
98 chalk_ir::VariableKind::Lifetime => {
99 GenericArgData::Ty(table.new_type_var()).intern(Interner)
100 } // FIXME: maybe wrong?
101 chalk_ir::VariableKind::Const(ty) => {
102 GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
103 }
104 }),
105 );
106 let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
107 let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
108 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
109 return None;
110 }
111 // default any type vars that weren't unified back to their original bound vars
112 // (kind of hacky)
113 let find_var = |iv| {
114 vars.iter(Interner).position(|v| match v.interned() {
115 chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
116 chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
117 chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
118 } == Some(iv))
119 };
120 let fallback = |iv, kind, default, binder| match kind {
121 chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
122 .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
123 chalk_ir::VariableKind::Lifetime => find_var(iv)
124 .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
125 chalk_ir::VariableKind::Const(ty) => find_var(iv)
126 .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
127 };
128 Some(Substitution::from_iter(
129 Interner,
130 vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)),
131 ))
132 }
133
134 bitflags::bitflags! {
135 #[derive(Default, Clone, Copy)]
136 pub(crate) struct TypeVariableFlags: u8 {
137 const DIVERGING = 1 << 0;
138 const INTEGER = 1 << 1;
139 const FLOAT = 1 << 2;
140 }
141 }
142
143 type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
144
145 #[derive(Clone)]
146 pub(crate) struct InferenceTable<'a> {
147 pub(crate) db: &'a dyn HirDatabase,
148 pub(crate) trait_env: Arc<TraitEnvironment>,
149 var_unification_table: ChalkInferenceTable,
150 type_variable_table: Vec<TypeVariableFlags>,
151 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
152 }
153
154 pub(crate) struct InferenceTableSnapshot {
155 var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
156 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
157 type_variable_table_snapshot: Vec<TypeVariableFlags>,
158 }
159
160 impl<'a> InferenceTable<'a> {
new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self161 pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
162 InferenceTable {
163 db,
164 trait_env,
165 var_unification_table: ChalkInferenceTable::new(),
166 type_variable_table: Vec::new(),
167 pending_obligations: Vec::new(),
168 }
169 }
170
171 /// Chalk doesn't know about the `diverging` flag, so when it unifies two
172 /// type variables of which one is diverging, the chosen root might not be
173 /// diverging and we have no way of marking it as such at that time. This
174 /// function goes through all type variables and make sure their root is
175 /// marked as diverging if necessary, so that resolving them gives the right
176 /// result.
propagate_diverging_flag(&mut self)177 pub(super) fn propagate_diverging_flag(&mut self) {
178 for i in 0..self.type_variable_table.len() {
179 if !self.type_variable_table[i].contains(TypeVariableFlags::DIVERGING) {
180 continue;
181 }
182 let v = InferenceVar::from(i as u32);
183 let root = self.var_unification_table.inference_var_root(v);
184 if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) {
185 *data |= TypeVariableFlags::DIVERGING;
186 }
187 }
188 }
189
set_diverging(&mut self, iv: InferenceVar, diverging: bool)190 pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
191 self.type_variable_table[iv.index() as usize].set(TypeVariableFlags::DIVERGING, diverging);
192 }
193
fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty194 fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
195 match kind {
196 _ if self
197 .type_variable_table
198 .get(iv.index() as usize)
199 .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING)) =>
200 {
201 TyKind::Never
202 }
203 TyVariableKind::General => TyKind::Error,
204 TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
205 TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
206 }
207 .intern(Interner)
208 }
209
canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>( &mut self, t: T, ) -> Canonicalized<T> where T: HasInterner<Interner = Interner>,210 pub(crate) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
211 &mut self,
212 t: T,
213 ) -> Canonicalized<T>
214 where
215 T: HasInterner<Interner = Interner>,
216 {
217 // try to resolve obligations before canonicalizing, since this might
218 // result in new knowledge about variables
219 self.resolve_obligations_as_possible();
220 let result = self.var_unification_table.canonicalize(Interner, t);
221 let free_vars = result
222 .free_vars
223 .into_iter()
224 .map(|free_var| free_var.to_generic_arg(Interner))
225 .collect();
226 Canonicalized { value: result.quantified, free_vars }
227 }
228
229 /// Recurses through the given type, normalizing associated types mentioned
230 /// in it by replacing them by type variables and registering obligations to
231 /// resolve later. This should be done once for every type we get from some
232 /// type annotation (e.g. from a let type annotation, field type or function
233 /// call). `make_ty` handles this already, but e.g. for field types we need
234 /// to do it as well.
normalize_associated_types_in<T>(&mut self, ty: T) -> T where T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,235 pub(crate) fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
236 where
237 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
238 {
239 fold_tys_and_consts(
240 ty,
241 |e, _| match e {
242 Either::Left(ty) => Either::Left(match ty.kind(Interner) {
243 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
244 self.normalize_projection_ty(proj_ty.clone())
245 }
246 _ => ty,
247 }),
248 Either::Right(c) => Either::Right(match &c.data(Interner).value {
249 chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
250 crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
251 // FIXME: Ideally here we should do everything that we do with type alias, i.e. adding a variable
252 // and registering an obligation. But it needs chalk support, so we handle the most basic
253 // case (a non associated const without generic parameters) manually.
254 if subst.len(Interner) == 0 {
255 if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone())
256 {
257 eval
258 } else {
259 unknown_const(c.data(Interner).ty.clone())
260 }
261 } else {
262 unknown_const(c.data(Interner).ty.clone())
263 }
264 }
265 _ => c,
266 },
267 _ => c,
268 }),
269 },
270 DebruijnIndex::INNERMOST,
271 )
272 }
273
normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty274 pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
275 let var = self.new_type_var();
276 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
277 let obligation = alias_eq.cast(Interner);
278 self.register_obligation(obligation);
279 var
280 }
281
extend_type_variable_table(&mut self, to_index: usize)282 fn extend_type_variable_table(&mut self, to_index: usize) {
283 let count = to_index - self.type_variable_table.len() + 1;
284 self.type_variable_table.extend(iter::repeat(TypeVariableFlags::default()).take(count));
285 }
286
new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty287 fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
288 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
289 // Chalk might have created some type variables for its own purposes that we don't know about...
290 self.extend_type_variable_table(var.index() as usize);
291 assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
292 let flags = self.type_variable_table.get_mut(var.index() as usize).unwrap();
293 if diverging {
294 *flags |= TypeVariableFlags::DIVERGING;
295 }
296 if matches!(kind, TyVariableKind::Integer) {
297 *flags |= TypeVariableFlags::INTEGER;
298 } else if matches!(kind, TyVariableKind::Float) {
299 *flags |= TypeVariableFlags::FLOAT;
300 }
301 var.to_ty_with_kind(Interner, kind)
302 }
303
new_type_var(&mut self) -> Ty304 pub(crate) fn new_type_var(&mut self) -> Ty {
305 self.new_var(TyVariableKind::General, false)
306 }
307
new_integer_var(&mut self) -> Ty308 pub(crate) fn new_integer_var(&mut self) -> Ty {
309 self.new_var(TyVariableKind::Integer, false)
310 }
311
new_float_var(&mut self) -> Ty312 pub(crate) fn new_float_var(&mut self) -> Ty {
313 self.new_var(TyVariableKind::Float, false)
314 }
315
new_maybe_never_var(&mut self) -> Ty316 pub(crate) fn new_maybe_never_var(&mut self) -> Ty {
317 self.new_var(TyVariableKind::General, true)
318 }
319
new_const_var(&mut self, ty: Ty) -> Const320 pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const {
321 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
322 var.to_const(Interner, ty)
323 }
324
new_lifetime_var(&mut self) -> Lifetime325 pub(crate) fn new_lifetime_var(&mut self) -> Lifetime {
326 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
327 var.to_lifetime(Interner)
328 }
329
resolve_with_fallback<T>( &mut self, t: T, fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, ) -> T where T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,330 pub(crate) fn resolve_with_fallback<T>(
331 &mut self,
332 t: T,
333 fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
334 ) -> T
335 where
336 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
337 {
338 self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
339 }
340
fresh_subst(&mut self, binders: &[CanonicalVarKind<Interner>]) -> Substitution341 pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind<Interner>]) -> Substitution {
342 Substitution::from_iter(
343 Interner,
344 binders.iter().map(|kind| {
345 let param_infer_var =
346 kind.map_ref(|&ui| self.var_unification_table.new_variable(ui));
347 param_infer_var.to_generic_arg(Interner)
348 }),
349 )
350 }
351
instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T where T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + std::fmt::Debug,352 pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T
353 where
354 T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + std::fmt::Debug,
355 {
356 let subst = self.fresh_subst(canonical.binders.as_slice(Interner));
357 subst.apply(canonical.value, Interner)
358 }
359
resolve_with_fallback_inner<T>( &mut self, var_stack: &mut Vec<InferenceVar>, t: T, fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, ) -> T where T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,360 fn resolve_with_fallback_inner<T>(
361 &mut self,
362 var_stack: &mut Vec<InferenceVar>,
363 t: T,
364 fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
365 ) -> T
366 where
367 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
368 {
369 t.fold_with(
370 &mut resolve::Resolver { table: self, var_stack, fallback },
371 DebruijnIndex::INNERMOST,
372 )
373 }
374
resolve_completely<T>(&mut self, t: T) -> T where T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,375 pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
376 where
377 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
378 {
379 self.resolve_with_fallback(t, &|_, _, d, _| d)
380 }
381
382 /// Apply a fallback to unresolved scalar types. Integer type variables and float type
383 /// variables are replaced with i32 and f64, respectively.
384 ///
385 /// This method is only intended to be called just before returning inference results (i.e. in
386 /// `InferenceContext::resolve_all()`).
387 ///
388 /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
389 /// whereas rustc replaces them with `()` or `!`.
fallback_if_possible(&mut self)390 pub(super) fn fallback_if_possible(&mut self) {
391 let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
392 let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
393
394 let scalar_vars: Vec<_> = self
395 .type_variable_table
396 .iter()
397 .enumerate()
398 .filter_map(|(index, flags)| {
399 let kind = if flags.contains(TypeVariableFlags::INTEGER) {
400 TyVariableKind::Integer
401 } else if flags.contains(TypeVariableFlags::FLOAT) {
402 TyVariableKind::Float
403 } else {
404 return None;
405 };
406
407 // FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
408 // without directly constructing them from `index`?
409 let var = InferenceVar::from(index as u32).to_ty(Interner, kind);
410 Some(var)
411 })
412 .collect();
413
414 for var in scalar_vars {
415 let maybe_resolved = self.resolve_ty_shallow(&var);
416 if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
417 let fallback = match kind {
418 TyVariableKind::Integer => &int_fallback,
419 TyVariableKind::Float => &float_fallback,
420 TyVariableKind::General => unreachable!(),
421 };
422 self.unify(&var, fallback);
423 }
424 }
425 }
426
427 /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool428 pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
429 let result = match self.try_unify(ty1, ty2) {
430 Ok(r) => r,
431 Err(_) => return false,
432 };
433 self.register_infer_ok(result);
434 true
435 }
436
437 /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
438 /// caller needs to deal with them.
try_unify<T: ?Sized + Zip<Interner>>( &mut self, t1: &T, t2: &T, ) -> InferResult<()>439 pub(crate) fn try_unify<T: ?Sized + Zip<Interner>>(
440 &mut self,
441 t1: &T,
442 t2: &T,
443 ) -> InferResult<()> {
444 match self.var_unification_table.relate(
445 Interner,
446 &self.db,
447 &self.trait_env.env,
448 chalk_ir::Variance::Invariant,
449 t1,
450 t2,
451 ) {
452 Ok(result) => Ok(InferOk { goals: result.goals, value: () }),
453 Err(chalk_ir::NoSolution) => Err(TypeError),
454 }
455 }
456
457 /// If `ty` is a type variable with known type, returns that type;
458 /// otherwise, return ty.
resolve_ty_shallow(&mut self, ty: &Ty) -> Ty459 pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
460 self.resolve_obligations_as_possible();
461 self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone())
462 }
463
snapshot(&mut self) -> InferenceTableSnapshot464 pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
465 let var_table_snapshot = self.var_unification_table.snapshot();
466 let type_variable_table_snapshot = self.type_variable_table.clone();
467 let pending_obligations = self.pending_obligations.clone();
468 InferenceTableSnapshot {
469 var_table_snapshot,
470 pending_obligations,
471 type_variable_table_snapshot,
472 }
473 }
474
rollback_to(&mut self, snapshot: InferenceTableSnapshot)475 pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
476 self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
477 self.type_variable_table = snapshot.type_variable_table_snapshot;
478 self.pending_obligations = snapshot.pending_obligations;
479 }
480
run_in_snapshot<T>(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T481 pub(crate) fn run_in_snapshot<T>(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T {
482 let snapshot = self.snapshot();
483 let result = f(self);
484 self.rollback_to(snapshot);
485 result
486 }
487
488 /// Checks an obligation without registering it. Useful mostly to check
489 /// whether a trait *might* be implemented before deciding to 'lock in' the
490 /// choice (during e.g. method resolution or deref).
try_obligation(&mut self, goal: Goal) -> Option<Solution>491 pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
492 let in_env = InEnvironment::new(&self.trait_env.env, goal);
493 let canonicalized = self.canonicalize(in_env);
494 let solution =
495 self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value);
496 solution
497 }
498
register_obligation(&mut self, goal: Goal)499 pub(crate) fn register_obligation(&mut self, goal: Goal) {
500 let in_env = InEnvironment::new(&self.trait_env.env, goal);
501 self.register_obligation_in_env(in_env)
502 }
503
register_obligation_in_env(&mut self, goal: InEnvironment<Goal>)504 fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
505 let canonicalized = self.canonicalize(goal);
506 if !self.try_resolve_obligation(&canonicalized) {
507 self.pending_obligations.push(canonicalized);
508 }
509 }
510
register_infer_ok<T>(&mut self, infer_ok: InferOk<T>)511 pub(crate) fn register_infer_ok<T>(&mut self, infer_ok: InferOk<T>) {
512 infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal));
513 }
514
resolve_obligations_as_possible(&mut self)515 pub(crate) fn resolve_obligations_as_possible(&mut self) {
516 let _span = profile::span("resolve_obligations_as_possible");
517 let mut changed = true;
518 let mut obligations = Vec::new();
519 while changed {
520 changed = false;
521 mem::swap(&mut self.pending_obligations, &mut obligations);
522 for canonicalized in obligations.drain(..) {
523 if !self.check_changed(&canonicalized) {
524 self.pending_obligations.push(canonicalized);
525 continue;
526 }
527 changed = true;
528 let uncanonical = chalk_ir::Substitute::apply(
529 &canonicalized.free_vars,
530 canonicalized.value.value,
531 Interner,
532 );
533 self.register_obligation_in_env(uncanonical);
534 }
535 }
536 }
537
fudge_inference<T: TypeFoldable<Interner>>( &mut self, f: impl FnOnce(&mut Self) -> T, ) -> T538 pub(crate) fn fudge_inference<T: TypeFoldable<Interner>>(
539 &mut self,
540 f: impl FnOnce(&mut Self) -> T,
541 ) -> T {
542 use chalk_ir::fold::TypeFolder;
543
544 #[derive(chalk_derive::FallibleTypeFolder)]
545 #[has_interner(Interner)]
546 struct VarFudger<'a, 'b> {
547 table: &'a mut InferenceTable<'b>,
548 highest_known_var: InferenceVar,
549 }
550 impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
551 fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
552 self
553 }
554
555 fn interner(&self) -> Interner {
556 Interner
557 }
558
559 fn fold_inference_ty(
560 &mut self,
561 var: chalk_ir::InferenceVar,
562 kind: TyVariableKind,
563 _outer_binder: chalk_ir::DebruijnIndex,
564 ) -> chalk_ir::Ty<Interner> {
565 if var < self.highest_known_var {
566 var.to_ty(Interner, kind)
567 } else {
568 self.table.new_type_var()
569 }
570 }
571
572 fn fold_inference_lifetime(
573 &mut self,
574 var: chalk_ir::InferenceVar,
575 _outer_binder: chalk_ir::DebruijnIndex,
576 ) -> chalk_ir::Lifetime<Interner> {
577 if var < self.highest_known_var {
578 var.to_lifetime(Interner)
579 } else {
580 self.table.new_lifetime_var()
581 }
582 }
583
584 fn fold_inference_const(
585 &mut self,
586 ty: chalk_ir::Ty<Interner>,
587 var: chalk_ir::InferenceVar,
588 _outer_binder: chalk_ir::DebruijnIndex,
589 ) -> chalk_ir::Const<Interner> {
590 if var < self.highest_known_var {
591 var.to_const(Interner, ty)
592 } else {
593 self.table.new_const_var(ty)
594 }
595 }
596 }
597
598 let snapshot = self.snapshot();
599 let highest_known_var = self.new_type_var().inference_var(Interner).expect("inference_var");
600 let result = f(self);
601 self.rollback_to(snapshot);
602 result
603 .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
604 }
605
606 /// This checks whether any of the free variables in the `canonicalized`
607 /// have changed (either been unified with another variable, or with a
608 /// value). If this is not the case, we don't need to try to solve the goal
609 /// again -- it'll give the same result as last time.
check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool610 fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
611 canonicalized.free_vars.iter().any(|var| {
612 let iv = match var.data(Interner) {
613 chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
614 chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
615 chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
616 }
617 .expect("free var is not inference var");
618 if self.var_unification_table.probe_var(iv).is_some() {
619 return true;
620 }
621 let root = self.var_unification_table.inference_var_root(iv);
622 iv != root
623 })
624 }
625
try_resolve_obligation( &mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>, ) -> bool626 fn try_resolve_obligation(
627 &mut self,
628 canonicalized: &Canonicalized<InEnvironment<Goal>>,
629 ) -> bool {
630 let solution = self.db.trait_solve(
631 self.trait_env.krate,
632 self.trait_env.block,
633 canonicalized.value.clone(),
634 );
635
636 match solution {
637 Some(Solution::Unique(canonical_subst)) => {
638 canonicalized.apply_solution(
639 self,
640 Canonical {
641 binders: canonical_subst.binders,
642 // FIXME: handle constraints
643 value: canonical_subst.value.subst,
644 },
645 );
646 true
647 }
648 Some(Solution::Ambig(Guidance::Definite(substs))) => {
649 canonicalized.apply_solution(self, substs);
650 false
651 }
652 Some(_) => {
653 // FIXME use this when trying to resolve everything at the end
654 false
655 }
656 None => {
657 // FIXME obligation cannot be fulfilled => diagnostic
658 true
659 }
660 }
661 }
662
callable_sig( &mut self, ty: &Ty, num_args: usize, ) -> Option<(Option<FnTrait>, Vec<Ty>, Ty)>663 pub(crate) fn callable_sig(
664 &mut self,
665 ty: &Ty,
666 num_args: usize,
667 ) -> Option<(Option<FnTrait>, Vec<Ty>, Ty)> {
668 match ty.callable_sig(self.db) {
669 Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())),
670 None => {
671 let (f, args_ty, return_ty) = self.callable_sig_from_fn_trait(ty, num_args)?;
672 Some((Some(f), args_ty, return_ty))
673 }
674 }
675 }
676
callable_sig_from_fn_trait( &mut self, ty: &Ty, num_args: usize, ) -> Option<(FnTrait, Vec<Ty>, Ty)>677 fn callable_sig_from_fn_trait(
678 &mut self,
679 ty: &Ty,
680 num_args: usize,
681 ) -> Option<(FnTrait, Vec<Ty>, Ty)> {
682 let krate = self.trait_env.krate;
683 let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
684 let trait_data = self.db.trait_data(fn_once_trait);
685 let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?;
686
687 let mut arg_tys = vec![];
688 let arg_ty = TyBuilder::tuple(num_args)
689 .fill(|x| {
690 let arg = match x {
691 ParamKind::Type => self.new_type_var(),
692 ParamKind::Const(ty) => {
693 never!("Tuple with const parameter");
694 return GenericArgData::Const(self.new_const_var(ty.clone()))
695 .intern(Interner);
696 }
697 };
698 arg_tys.push(arg.clone());
699 GenericArgData::Ty(arg).intern(Interner)
700 })
701 .build();
702
703 let projection = {
704 let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
705 if b.remaining() != 2 {
706 return None;
707 }
708 let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
709
710 TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
711 .build()
712 };
713
714 let trait_env = self.trait_env.env.clone();
715 let mut trait_ref = projection.trait_ref(self.db);
716 let obligation = InEnvironment {
717 goal: trait_ref.clone().cast(Interner),
718 environment: trait_env.clone(),
719 };
720 let canonical = self.canonicalize(obligation.clone());
721 if self
722 .db
723 .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
724 .is_some()
725 {
726 self.register_obligation(obligation.goal);
727 let return_ty = self.normalize_projection_ty(projection);
728 for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
729 let fn_x_trait = fn_x.get_id(self.db, krate)?;
730 trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
731 let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment {
732 goal: trait_ref.clone().cast(Interner),
733 environment: trait_env.clone(),
734 };
735 let canonical = self.canonicalize(obligation.clone());
736 if self
737 .db
738 .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
739 .is_some()
740 {
741 return Some((fn_x, arg_tys, return_ty));
742 }
743 }
744 unreachable!("It should at least implement FnOnce at this point");
745 } else {
746 None
747 }
748 }
749
insert_type_vars<T>(&mut self, ty: T) -> T where T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,750 pub(super) fn insert_type_vars<T>(&mut self, ty: T) -> T
751 where
752 T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
753 {
754 fold_tys_and_consts(
755 ty,
756 |x, _| match x {
757 Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
758 Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
759 },
760 DebruijnIndex::INNERMOST,
761 )
762 }
763
764 /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
insert_type_vars_shallow(&mut self, ty: Ty) -> Ty765 pub(super) fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
766 match ty.kind(Interner) {
767 TyKind::Error => self.new_type_var(),
768 TyKind::InferenceVar(..) => {
769 let ty_resolved = self.resolve_ty_shallow(&ty);
770 if ty_resolved.is_unknown() {
771 self.new_type_var()
772 } else {
773 ty
774 }
775 }
776 _ => ty,
777 }
778 }
779
780 /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
insert_const_vars_shallow(&mut self, c: Const) -> Const781 pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
782 let data = c.data(Interner);
783 match &data.value {
784 ConstValue::Concrete(cc) => match &cc.interned {
785 crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()),
786 // try to evaluate unevaluated const. Replace with new var if const eval failed.
787 crate::ConstScalar::UnevaluatedConst(id, subst) => {
788 if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
789 eval
790 } else {
791 self.new_const_var(data.ty.clone())
792 }
793 }
794 _ => c,
795 },
796 _ => c,
797 }
798 }
799 }
800
801 impl<'a> fmt::Debug for InferenceTable<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
803 f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish()
804 }
805 }
806
807 mod resolve {
808 use super::InferenceTable;
809 use crate::{
810 ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg,
811 InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind,
812 };
813 use chalk_ir::{
814 cast::Cast,
815 fold::{TypeFoldable, TypeFolder},
816 };
817
818 #[derive(chalk_derive::FallibleTypeFolder)]
819 #[has_interner(Interner)]
820 pub(super) struct Resolver<
821 'a,
822 'b,
823 F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
824 > {
825 pub(super) table: &'a mut InferenceTable<'b>,
826 pub(super) var_stack: &'a mut Vec<InferenceVar>,
827 pub(super) fallback: F,
828 }
829 impl<'a, 'b, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
830 where
831 F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
832 {
as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error>833 fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
834 self
835 }
836
interner(&self) -> Interner837 fn interner(&self) -> Interner {
838 Interner
839 }
840
fold_inference_ty( &mut self, var: InferenceVar, kind: TyVariableKind, outer_binder: DebruijnIndex, ) -> Ty841 fn fold_inference_ty(
842 &mut self,
843 var: InferenceVar,
844 kind: TyVariableKind,
845 outer_binder: DebruijnIndex,
846 ) -> Ty {
847 let var = self.table.var_unification_table.inference_var_root(var);
848 if self.var_stack.contains(&var) {
849 // recursive type
850 let default = self.table.fallback_value(var, kind).cast(Interner);
851 return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
852 .assert_ty_ref(Interner)
853 .clone();
854 }
855 let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
856 // known_ty may contain other variables that are known by now
857 self.var_stack.push(var);
858 let result = known_ty.fold_with(self, outer_binder);
859 self.var_stack.pop();
860 result.assert_ty_ref(Interner).clone()
861 } else {
862 let default = self.table.fallback_value(var, kind).cast(Interner);
863 (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
864 .assert_ty_ref(Interner)
865 .clone()
866 };
867 result
868 }
869
fold_inference_const( &mut self, ty: Ty, var: InferenceVar, outer_binder: DebruijnIndex, ) -> Const870 fn fold_inference_const(
871 &mut self,
872 ty: Ty,
873 var: InferenceVar,
874 outer_binder: DebruijnIndex,
875 ) -> Const {
876 let var = self.table.var_unification_table.inference_var_root(var);
877 let default = ConstData {
878 ty: ty.clone(),
879 value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
880 }
881 .intern(Interner)
882 .cast(Interner);
883 if self.var_stack.contains(&var) {
884 // recursive
885 return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
886 .assert_const_ref(Interner)
887 .clone();
888 }
889 if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
890 // known_ty may contain other variables that are known by now
891 self.var_stack.push(var);
892 let result = known_ty.fold_with(self, outer_binder);
893 self.var_stack.pop();
894 result.assert_const_ref(Interner).clone()
895 } else {
896 (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
897 .assert_const_ref(Interner)
898 .clone()
899 }
900 }
901
fold_inference_lifetime( &mut self, _var: InferenceVar, _outer_binder: DebruijnIndex, ) -> Lifetime902 fn fold_inference_lifetime(
903 &mut self,
904 _var: InferenceVar,
905 _outer_binder: DebruijnIndex,
906 ) -> Lifetime {
907 // fall back all lifetimes to 'static -- currently we don't deal
908 // with any lifetimes, but we can sometimes get some lifetime
909 // variables through Chalk's unification, and this at least makes
910 // sure we don't leak them outside of inference
911 crate::static_lifetime()
912 }
913 }
914 }
915