diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer')
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index 820a64789..c9c8959c4 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs | |||
@@ -13,14 +13,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
13 | } | 13 | } |
14 | } | 14 | } |
15 | 15 | ||
16 | // TODO improve the interface of this | ||
17 | |||
18 | pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase> | 16 | pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase> |
19 | where | 17 | where |
20 | 'a: 'b, | 18 | 'a: 'b, |
21 | { | 19 | { |
22 | pub ctx: &'b mut InferenceContext<'a, D>, | 20 | ctx: &'b mut InferenceContext<'a, D>, |
23 | pub free_vars: Vec<InferTy>, | 21 | free_vars: Vec<InferTy>, |
22 | } | ||
23 | |||
24 | pub(super) struct Canonicalized<T> { | ||
25 | pub value: Canonical<T>, | ||
26 | free_vars: Vec<InferTy>, | ||
24 | } | 27 | } |
25 | 28 | ||
26 | impl<'a, 'b, D: HirDatabase> Canonicalizer<'a, 'b, D> | 29 | impl<'a, 'b, D: HirDatabase> Canonicalizer<'a, 'b, D> |
@@ -35,13 +38,13 @@ where | |||
35 | }) | 38 | }) |
36 | } | 39 | } |
37 | 40 | ||
38 | pub fn canonicalize_ty(&mut self, ty: Ty) -> Canonical<Ty> { | 41 | fn do_canonicalize_ty(&mut self, ty: Ty) -> Ty { |
39 | let value = ty.fold(&mut |ty| match ty { | 42 | ty.fold(&mut |ty| match ty { |
40 | Ty::Infer(tv) => { | 43 | Ty::Infer(tv) => { |
41 | let inner = tv.to_inner(); | 44 | let inner = tv.to_inner(); |
42 | // TODO prevent infinite loops? => keep var stack | 45 | // TODO prevent infinite loops? => keep var stack |
43 | if let Some(known_ty) = self.ctx.var_unification_table.probe_value(inner).known() { | 46 | if let Some(known_ty) = self.ctx.var_unification_table.probe_value(inner).known() { |
44 | self.canonicalize_ty(known_ty.clone()).value | 47 | self.do_canonicalize_ty(known_ty.clone()) |
45 | } else { | 48 | } else { |
46 | let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner)); | 49 | let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner)); |
47 | let position = self.add(free_var); | 50 | let position = self.add(free_var); |
@@ -49,20 +52,37 @@ where | |||
49 | } | 52 | } |
50 | } | 53 | } |
51 | _ => ty, | 54 | _ => ty, |
52 | }); | 55 | }) |
53 | Canonical { value, num_vars: self.free_vars.len() } | ||
54 | } | 56 | } |
55 | 57 | ||
56 | pub fn canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> Canonical<TraitRef> { | 58 | fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef { |
57 | let substs = trait_ref | 59 | let substs = trait_ref |
58 | .substs | 60 | .substs |
59 | .iter() | 61 | .iter() |
60 | .map(|ty| self.canonicalize_ty(ty.clone()).value) | 62 | .map(|ty| self.do_canonicalize_ty(ty.clone())) |
61 | .collect::<Vec<_>>(); | 63 | .collect::<Vec<_>>(); |
62 | let value = TraitRef { trait_: trait_ref.trait_, substs: substs.into() }; | 64 | TraitRef { trait_: trait_ref.trait_, substs: substs.into() } |
63 | Canonical { value, num_vars: self.free_vars.len() } | ||
64 | } | 65 | } |
65 | 66 | ||
67 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | ||
68 | Canonicalized { | ||
69 | value: Canonical { value: result, num_vars: self.free_vars.len() }, | ||
70 | free_vars: self.free_vars, | ||
71 | } | ||
72 | } | ||
73 | |||
74 | pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | ||
75 | let result = self.do_canonicalize_ty(ty); | ||
76 | self.into_canonicalized(result) | ||
77 | } | ||
78 | |||
79 | pub fn canonicalize_trait_ref(mut self, trait_ref: TraitRef) -> Canonicalized<TraitRef> { | ||
80 | let result = self.do_canonicalize_trait_ref(trait_ref); | ||
81 | self.into_canonicalized(result) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl<T> Canonicalized<T> { | ||
66 | pub fn decanonicalize_ty(&self, ty: Ty) -> Ty { | 86 | pub fn decanonicalize_ty(&self, ty: Ty) -> Ty { |
67 | ty.fold(&mut |ty| match ty { | 87 | ty.fold(&mut |ty| match ty { |
68 | Ty::Bound(idx) => { | 88 | Ty::Bound(idx) => { |
@@ -76,13 +96,17 @@ where | |||
76 | }) | 96 | }) |
77 | } | 97 | } |
78 | 98 | ||
79 | pub fn apply_solution(&mut self, solution: Canonical<Vec<Ty>>) { | 99 | pub fn apply_solution( |
100 | &self, | ||
101 | ctx: &mut InferenceContext<'_, impl HirDatabase>, | ||
102 | solution: Canonical<Vec<Ty>>, | ||
103 | ) { | ||
80 | // the solution may contain new variables, which we need to convert to new inference vars | 104 | // the solution may contain new variables, which we need to convert to new inference vars |
81 | let new_vars = | 105 | let new_vars = |
82 | (0..solution.num_vars).map(|_| self.ctx.new_type_var()).collect::<Vec<_>>().into(); | 106 | (0..solution.num_vars).map(|_| ctx.new_type_var()).collect::<Vec<_>>().into(); |
83 | for (i, ty) in solution.value.into_iter().enumerate() { | 107 | for (i, ty) in solution.value.into_iter().enumerate() { |
84 | let var = self.free_vars[i].clone(); | 108 | let var = self.free_vars[i].clone(); |
85 | self.ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); | 109 | ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); |
86 | } | 110 | } |
87 | } | 111 | } |
88 | } | 112 | } |