diff options
Diffstat (limited to 'crates/hir_ty/src/infer/unify.rs')
-rw-r--r-- | crates/hir_ty/src/infer/unify.rs | 119 |
1 files changed, 72 insertions, 47 deletions
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index b2d4f67b3..75250a369 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -2,13 +2,13 @@ | |||
2 | 2 | ||
3 | use std::borrow::Cow; | 3 | use std::borrow::Cow; |
4 | 4 | ||
5 | use chalk_ir::{FloatTy, IntTy, TyVariableKind}; | 5 | use chalk_ir::{FloatTy, IntTy, TyVariableKind, UniverseIndex, VariableKind}; |
6 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | 6 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; |
7 | 7 | ||
8 | use super::{InferenceContext, Obligation}; | 8 | use super::{DomainGoal, InferenceContext}; |
9 | use crate::{ | 9 | use crate::{ |
10 | BoundVar, Canonical, DebruijnIndex, FnPointer, GenericPredicate, InEnvironment, InferenceVar, | 10 | AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, |
11 | Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, | 11 | InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, WhereClause, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | impl<'a> InferenceContext<'a> { | 14 | impl<'a> InferenceContext<'a> { |
@@ -76,8 +76,17 @@ impl<'a, 'b> Canonicalizer<'a, 'b> { | |||
76 | } | 76 | } |
77 | 77 | ||
78 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | 78 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { |
79 | let kinds = self.free_vars.iter().map(|&(_, k)| k).collect(); | 79 | let kinds = self |
80 | Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars } | 80 | .free_vars |
81 | .iter() | ||
82 | .map(|&(_, k)| chalk_ir::WithKind::new(VariableKind::Ty(k), UniverseIndex::ROOT)); | ||
83 | Canonicalized { | ||
84 | value: Canonical { | ||
85 | value: result, | ||
86 | binders: CanonicalVarKinds::from_iter(&Interner, kinds), | ||
87 | }, | ||
88 | free_vars: self.free_vars, | ||
89 | } | ||
81 | } | 90 | } |
82 | 91 | ||
83 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 92 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
@@ -87,20 +96,14 @@ impl<'a, 'b> Canonicalizer<'a, 'b> { | |||
87 | 96 | ||
88 | pub(crate) fn canonicalize_obligation( | 97 | pub(crate) fn canonicalize_obligation( |
89 | mut self, | 98 | mut self, |
90 | obligation: InEnvironment<Obligation>, | 99 | obligation: InEnvironment<DomainGoal>, |
91 | ) -> Canonicalized<InEnvironment<Obligation>> { | 100 | ) -> Canonicalized<InEnvironment<DomainGoal>> { |
92 | let result = match obligation.value { | 101 | let result = match obligation.goal { |
93 | Obligation::Trait(tr) => { | 102 | DomainGoal::Holds(wc) => { |
94 | Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST)) | 103 | DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST)) |
95 | } | ||
96 | Obligation::Projection(pr) => { | ||
97 | Obligation::Projection(self.do_canonicalize(pr, DebruijnIndex::INNERMOST)) | ||
98 | } | 104 | } |
99 | }; | 105 | }; |
100 | self.into_canonicalized(InEnvironment { | 106 | self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment }) |
101 | value: result, | ||
102 | environment: obligation.environment, | ||
103 | }) | ||
104 | } | 107 | } |
105 | } | 108 | } |
106 | 109 | ||
@@ -128,12 +131,19 @@ impl<T> Canonicalized<T> { | |||
128 | // the solution may contain new variables, which we need to convert to new inference vars | 131 | // the solution may contain new variables, which we need to convert to new inference vars |
129 | let new_vars = Substitution( | 132 | let new_vars = Substitution( |
130 | solution | 133 | solution |
131 | .kinds | 134 | .binders |
132 | .iter() | 135 | .iter(&Interner) |
133 | .map(|k| match k { | 136 | .map(|k| match k.kind { |
134 | TyVariableKind::General => ctx.table.new_type_var(), | 137 | VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(), |
135 | TyVariableKind::Integer => ctx.table.new_integer_var(), | 138 | VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(), |
136 | TyVariableKind::Float => ctx.table.new_float_var(), | 139 | VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(), |
140 | // HACK: Chalk can sometimes return new lifetime variables. We | ||
141 | // want to just skip them, but to not mess up the indices of | ||
142 | // other variables, we'll just create a new type variable in | ||
143 | // their place instead. This should not matter (we never see the | ||
144 | // actual *uses* of the lifetime variable). | ||
145 | VariableKind::Lifetime => ctx.table.new_type_var(), | ||
146 | _ => panic!("const variable in solution"), | ||
137 | }) | 147 | }) |
138 | .collect(), | 148 | .collect(), |
139 | ); | 149 | ); |
@@ -150,8 +160,8 @@ impl<T> Canonicalized<T> { | |||
150 | pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { | 160 | pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { |
151 | let mut table = InferenceTable::new(); | 161 | let mut table = InferenceTable::new(); |
152 | let vars = Substitution( | 162 | let vars = Substitution( |
153 | tys.kinds | 163 | tys.binders |
154 | .iter() | 164 | .iter(&Interner) |
155 | // we always use type vars here because we want everything to | 165 | // we always use type vars here because we want everything to |
156 | // fallback to Unknown in the end (kind of hacky, as below) | 166 | // fallback to Unknown in the end (kind of hacky, as below) |
157 | .map(|_| table.new_type_var()) | 167 | .map(|_| table.new_type_var()) |
@@ -173,7 +183,7 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { | |||
173 | } | 183 | } |
174 | } | 184 | } |
175 | Some( | 185 | Some( |
176 | Substitution::builder(tys.kinds.len()) | 186 | Substitution::builder(tys.binders.len(&Interner)) |
177 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) | 187 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) |
178 | .build(), | 188 | .build(), |
179 | ) | 189 | ) |
@@ -313,9 +323,18 @@ impl InferenceTable { | |||
313 | 323 | ||
314 | (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true, | 324 | (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true, |
315 | 325 | ||
316 | (TyKind::Dyn(dyn1), TyKind::Dyn(dyn2)) if dyn1.len() == dyn2.len() => { | 326 | (TyKind::Dyn(dyn1), TyKind::Dyn(dyn2)) |
317 | for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) { | 327 | if dyn1.bounds.skip_binders().interned().len() |
318 | if !self.unify_preds(pred1, pred2, depth + 1) { | 328 | == dyn2.bounds.skip_binders().interned().len() => |
329 | { | ||
330 | for (pred1, pred2) in dyn1 | ||
331 | .bounds | ||
332 | .skip_binders() | ||
333 | .interned() | ||
334 | .iter() | ||
335 | .zip(dyn2.bounds.skip_binders().interned().iter()) | ||
336 | { | ||
337 | if !self.unify_preds(pred1.skip_binders(), pred2.skip_binders(), depth + 1) { | ||
319 | return false; | 338 | return false; |
320 | } | 339 | } |
321 | } | 340 | } |
@@ -382,26 +401,32 @@ impl InferenceTable { | |||
382 | } | 401 | } |
383 | } | 402 | } |
384 | 403 | ||
385 | fn unify_preds( | 404 | fn unify_preds(&mut self, pred1: &WhereClause, pred2: &WhereClause, depth: usize) -> bool { |
386 | &mut self, | ||
387 | pred1: &GenericPredicate, | ||
388 | pred2: &GenericPredicate, | ||
389 | depth: usize, | ||
390 | ) -> bool { | ||
391 | match (pred1, pred2) { | 405 | match (pred1, pred2) { |
392 | (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2)) | 406 | (WhereClause::Implemented(tr1), WhereClause::Implemented(tr2)) |
393 | if tr1.trait_ == tr2.trait_ => | 407 | if tr1.trait_id == tr2.trait_id => |
394 | { | 408 | { |
395 | self.unify_substs(&tr1.substs, &tr2.substs, depth + 1) | 409 | self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1) |
396 | } | 410 | } |
397 | (GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2)) | 411 | ( |
398 | if proj1.projection_ty.associated_ty_id == proj2.projection_ty.associated_ty_id => | 412 | WhereClause::AliasEq(AliasEq { alias: alias1, ty: ty1 }), |
399 | { | 413 | WhereClause::AliasEq(AliasEq { alias: alias2, ty: ty2 }), |
400 | self.unify_substs( | 414 | ) => { |
401 | &proj1.projection_ty.substitution, | 415 | let (substitution1, substitution2) = match (alias1, alias2) { |
402 | &proj2.projection_ty.substitution, | 416 | (AliasTy::Projection(projection_ty1), AliasTy::Projection(projection_ty2)) |
403 | depth + 1, | 417 | if projection_ty1.associated_ty_id == projection_ty2.associated_ty_id => |
404 | ) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1) | 418 | { |
419 | (&projection_ty1.substitution, &projection_ty2.substitution) | ||
420 | } | ||
421 | (AliasTy::Opaque(opaque1), AliasTy::Opaque(opaque2)) | ||
422 | if opaque1.opaque_ty_id == opaque2.opaque_ty_id => | ||
423 | { | ||
424 | (&opaque1.substitution, &opaque2.substitution) | ||
425 | } | ||
426 | _ => return false, | ||
427 | }; | ||
428 | self.unify_substs(&substitution1, &substitution2, depth + 1) | ||
429 | && self.unify_inner(&ty1, &ty2, depth + 1) | ||
405 | } | 430 | } |
406 | _ => false, | 431 | _ => false, |
407 | } | 432 | } |