aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/infer/unify.rs
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-02-21 20:46:21 +0000
committerFlorian Diebold <[email protected]>2020-02-22 10:09:21 +0000
commitf126808b2ee79792631edc377bc8c2b0f329eebf (patch)
tree687760c2eec85bdad42f6c6c56ab32b17a03aa37 /crates/ra_hir_ty/src/infer/unify.rs
parent0dfbbaf03b03618dcb7ba203ddc453533bb8d1b4 (diff)
Fix handling of binders in canonicalization
I'm looking forward to getting rid of this in favor of Chalk's implementation.
Diffstat (limited to 'crates/ra_hir_ty/src/infer/unify.rs')
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs99
1 files changed, 35 insertions, 64 deletions
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index 2d03c5c33..aed527fe5 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -7,10 +7,7 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7use test_utils::tested_by; 7use test_utils::tested_by;
8 8
9use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
10use crate::{ 10use crate::{db::HirDatabase, Canonical, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk};
11 db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate,
12 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
13};
14 11
15impl<'a, D: HirDatabase> InferenceContext<'a, D> { 12impl<'a, D: HirDatabase> InferenceContext<'a, D> {
16 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> 13 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
@@ -50,42 +47,38 @@ where
50 }) 47 })
51 } 48 }
52 49
53 fn do_canonicalize_ty(&mut self, ty: Ty) -> Ty { 50 fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: usize) -> T {
54 ty.fold(&mut |ty| match ty { 51 t.fold_binders(
55 Ty::Infer(tv) => { 52 &mut |ty, binders| match ty {
56 let inner = tv.to_inner(); 53 Ty::Infer(tv) => {
57 if self.var_stack.contains(&inner) { 54 let inner = tv.to_inner();
58 // recursive type 55 if self.var_stack.contains(&inner) {
59 return tv.fallback_value(); 56 // recursive type
60 } 57 return tv.fallback_value();
61 if let Some(known_ty) = 58 }
62 self.ctx.table.var_unification_table.inlined_probe_value(inner).known() 59 if let Some(known_ty) =
63 { 60 self.ctx.table.var_unification_table.inlined_probe_value(inner).known()
64 self.var_stack.push(inner); 61 {
65 let result = self.do_canonicalize_ty(known_ty.clone()); 62 self.var_stack.push(inner);
66 self.var_stack.pop(); 63 let result = self.do_canonicalize(known_ty.clone(), binders);
67 result 64 self.var_stack.pop();
68 } else { 65 result
69 let root = self.ctx.table.var_unification_table.find(inner); 66 } else {
70 let free_var = match tv { 67 let root = self.ctx.table.var_unification_table.find(inner);
71 InferTy::TypeVar(_) => InferTy::TypeVar(root), 68 let free_var = match tv {
72 InferTy::IntVar(_) => InferTy::IntVar(root), 69 InferTy::TypeVar(_) => InferTy::TypeVar(root),
73 InferTy::FloatVar(_) => InferTy::FloatVar(root), 70 InferTy::IntVar(_) => InferTy::IntVar(root),
74 InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root), 71 InferTy::FloatVar(_) => InferTy::FloatVar(root),
75 }; 72 InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root),
76 let position = self.add(free_var); 73 };
77 Ty::Bound(position as u32) 74 let position = self.add(free_var);
75 Ty::Bound((position + binders) as u32)
76 }
78 } 77 }
79 } 78 _ => ty,
80 _ => ty, 79 },
81 }) 80 binders,
82 } 81 )
83
84 fn do_canonicalize_trait_ref(&mut self, mut trait_ref: TraitRef) -> TraitRef {
85 for ty in make_mut_slice(&mut trait_ref.substs.0) {
86 *ty = self.do_canonicalize_ty(ty.clone());
87 }
88 trait_ref
89 } 82 }
90 83
91 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 84 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
@@ -95,28 +88,8 @@ where
95 } 88 }
96 } 89 }
97 90
98 fn do_canonicalize_projection_ty(&mut self, mut projection_ty: ProjectionTy) -> ProjectionTy {
99 for ty in make_mut_slice(&mut projection_ty.parameters.0) {
100 *ty = self.do_canonicalize_ty(ty.clone());
101 }
102 projection_ty
103 }
104
105 fn do_canonicalize_projection_predicate(
106 &mut self,
107 projection: ProjectionPredicate,
108 ) -> ProjectionPredicate {
109 let ty = self.do_canonicalize_ty(projection.ty);
110 let projection_ty = self.do_canonicalize_projection_ty(projection.projection_ty);
111
112 ProjectionPredicate { ty, projection_ty }
113 }
114
115 // FIXME: add some point, we need to introduce a `Fold` trait that abstracts
116 // over all the things that can be canonicalized (like Chalk and rustc have)
117
118 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { 91 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
119 let result = self.do_canonicalize_ty(ty); 92 let result = self.do_canonicalize(ty, 0);
120 self.into_canonicalized(result) 93 self.into_canonicalized(result)
121 } 94 }
122 95
@@ -125,10 +98,8 @@ where
125 obligation: InEnvironment<Obligation>, 98 obligation: InEnvironment<Obligation>,
126 ) -> Canonicalized<InEnvironment<Obligation>> { 99 ) -> Canonicalized<InEnvironment<Obligation>> {
127 let result = match obligation.value { 100 let result = match obligation.value {
128 Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize_trait_ref(tr)), 101 Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize(tr, 0)),
129 Obligation::Projection(pr) => { 102 Obligation::Projection(pr) => Obligation::Projection(self.do_canonicalize(pr, 0)),
130 Obligation::Projection(self.do_canonicalize_projection_predicate(pr))
131 }
132 }; 103 };
133 self.into_canonicalized(InEnvironment { 104 self.into_canonicalized(InEnvironment {
134 value: result, 105 value: result,