diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer/unify.rs')
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 55 |
1 files changed, 40 insertions, 15 deletions
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 269495ca0..2e895d911 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -9,7 +9,7 @@ use test_utils::mark; | |||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{ |
11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, | 11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, |
12 | TypeCtor, TypeWalk, | 12 | TyKind, TypeCtor, TypeWalk, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | impl<'a> InferenceContext<'a> { | 15 | impl<'a> InferenceContext<'a> { |
@@ -86,10 +86,20 @@ where | |||
86 | } | 86 | } |
87 | 87 | ||
88 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | 88 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { |
89 | Canonicalized { | 89 | let kinds = self |
90 | value: Canonical { value: result, num_vars: self.free_vars.len() }, | 90 | .free_vars |
91 | free_vars: self.free_vars, | 91 | .iter() |
92 | } | 92 | .map(|v| match v { |
93 | // mapping MaybeNeverTypeVar to the same kind as general ones | ||
94 | // should be fine, because as opposed to int or float type vars, | ||
95 | // they don't restrict what kind of type can go into them, they | ||
96 | // just affect fallback. | ||
97 | InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General, | ||
98 | InferTy::IntVar(_) => TyKind::Integer, | ||
99 | InferTy::FloatVar(_) => TyKind::Float, | ||
100 | }) | ||
101 | .collect(); | ||
102 | Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars } | ||
93 | } | 103 | } |
94 | 104 | ||
95 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 105 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
@@ -131,26 +141,41 @@ impl<T> Canonicalized<T> { | |||
131 | ty | 141 | ty |
132 | } | 142 | } |
133 | 143 | ||
134 | pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) { | 144 | pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) { |
135 | // the solution may contain new variables, which we need to convert to new inference vars | 145 | // the solution may contain new variables, which we need to convert to new inference vars |
136 | let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect()); | 146 | let new_vars = Substs( |
147 | solution | ||
148 | .kinds | ||
149 | .iter() | ||
150 | .map(|k| match k { | ||
151 | TyKind::General => ctx.table.new_type_var(), | ||
152 | TyKind::Integer => ctx.table.new_integer_var(), | ||
153 | TyKind::Float => ctx.table.new_float_var(), | ||
154 | }) | ||
155 | .collect(), | ||
156 | ); | ||
137 | for (i, ty) in solution.value.into_iter().enumerate() { | 157 | for (i, ty) in solution.value.into_iter().enumerate() { |
138 | let var = self.free_vars[i]; | 158 | let var = self.free_vars[i]; |
139 | // eagerly replace projections in the type; we may be getting types | 159 | // eagerly replace projections in the type; we may be getting types |
140 | // e.g. from where clauses where this hasn't happened yet | 160 | // e.g. from where clauses where this hasn't happened yet |
141 | let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars)); | 161 | let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars)); |
142 | ctx.table.unify(&Ty::Infer(var), &ty); | 162 | ctx.table.unify(&Ty::Infer(var), &ty); |
143 | } | 163 | } |
144 | } | 164 | } |
145 | } | 165 | } |
146 | 166 | ||
147 | pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | 167 | pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> { |
148 | let mut table = InferenceTable::new(); | 168 | let mut table = InferenceTable::new(); |
149 | let num_vars = ty1.num_vars.max(ty2.num_vars); | 169 | let vars = Substs( |
150 | let vars = | 170 | tys.kinds |
151 | Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); | 171 | .iter() |
152 | let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); | 172 | // we always use type vars here because we want everything to |
153 | let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); | 173 | // fallback to Unknown in the end (kind of hacky, as below) |
174 | .map(|_| table.new_type_var()) | ||
175 | .collect(), | ||
176 | ); | ||
177 | let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars); | ||
178 | let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars); | ||
154 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { | 179 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { |
155 | return None; | 180 | return None; |
156 | } | 181 | } |
@@ -162,7 +187,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | |||
162 | } | 187 | } |
163 | } | 188 | } |
164 | Some( | 189 | Some( |
165 | Substs::builder(ty1.num_vars) | 190 | Substs::builder(tys.kinds.len()) |
166 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) | 191 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) |
167 | .build(), | 192 | .build(), |
168 | ) | 193 | ) |