aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/infer/unify.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/infer/unify.rs')
-rw-r--r--crates/hir_ty/src/infer/unify.rs119
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
3use std::borrow::Cow; 3use std::borrow::Cow;
4 4
5use chalk_ir::{FloatTy, IntTy, TyVariableKind}; 5use chalk_ir::{FloatTy, IntTy, TyVariableKind, UniverseIndex, VariableKind};
6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7 7
8use super::{InferenceContext, Obligation}; 8use super::{DomainGoal, InferenceContext};
9use crate::{ 9use 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
14impl<'a> InferenceContext<'a> { 14impl<'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> {
150pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { 160pub(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 }