diff options
author | Florian Diebold <[email protected]> | 2019-05-04 14:42:00 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-05-04 17:18:30 +0100 |
commit | 621864319f8e3149c08d4d0f99b975407ba00ffd (patch) | |
tree | cbb6f7a9aa414ec0770556899559e746c740d2c9 /crates/ra_hir/src/ty | |
parent | 0bcf47b22b01f66c2f2056f5871e32071ba95b01 (diff) |
Make canonicalization API a bit nicer
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 56 |
2 files changed, 56 insertions, 31 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 41ae569f7..cc74c6322 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -324,23 +324,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
324 | fn resolve_obligations_as_possible(&mut self) { | 324 | fn resolve_obligations_as_possible(&mut self) { |
325 | let obligations = mem::replace(&mut self.obligations, Vec::new()); | 325 | let obligations = mem::replace(&mut self.obligations, Vec::new()); |
326 | for obligation in obligations { | 326 | for obligation in obligations { |
327 | let mut canonicalizer = self.canonicalizer(); | 327 | let (solution, canonicalized) = match &obligation { |
328 | let solution = match &obligation { | ||
329 | Obligation::Trait(tr) => { | 328 | Obligation::Trait(tr) => { |
330 | let canonical = canonicalizer.canonicalize_trait_ref(tr.clone()); | 329 | let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); |
331 | super::traits::implements( | 330 | ( |
332 | canonicalizer.ctx.db, | 331 | super::traits::implements( |
333 | canonicalizer.ctx.resolver.krate().unwrap(), | 332 | self.db, |
334 | canonical, | 333 | self.resolver.krate().unwrap(), |
334 | canonicalized.value.clone(), | ||
335 | ), | ||
336 | canonicalized, | ||
335 | ) | 337 | ) |
336 | } | 338 | } |
337 | }; | 339 | }; |
338 | match solution { | 340 | match solution { |
339 | Some(Solution::Unique(substs)) => { | 341 | Some(Solution::Unique(substs)) => { |
340 | canonicalizer.apply_solution(substs.0); | 342 | canonicalized.apply_solution(self, substs.0); |
341 | } | 343 | } |
342 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | 344 | Some(Solution::Ambig(Guidance::Definite(substs))) => { |
343 | canonicalizer.apply_solution(substs.0); | 345 | canonicalized.apply_solution(self, substs.0); |
344 | self.obligations.push(obligation); | 346 | self.obligations.push(obligation); |
345 | } | 347 | } |
346 | Some(_) => { | 348 | Some(_) => { |
@@ -877,17 +879,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
877 | generic_args: Option<&GenericArgs>, | 879 | generic_args: Option<&GenericArgs>, |
878 | ) -> Ty { | 880 | ) -> Ty { |
879 | let receiver_ty = self.infer_expr(receiver, &Expectation::none()); | 881 | let receiver_ty = self.infer_expr(receiver, &Expectation::none()); |
880 | let mut canonicalizer = self.canonicalizer(); | 882 | let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone()); |
881 | let canonical_receiver = canonicalizer.canonicalize_ty(receiver_ty.clone()); | ||
882 | let resolved = method_resolution::lookup_method( | 883 | let resolved = method_resolution::lookup_method( |
883 | &canonical_receiver, | 884 | &canonicalized_receiver.value, |
884 | canonicalizer.ctx.db, | 885 | self.db, |
885 | method_name, | 886 | method_name, |
886 | &canonicalizer.ctx.resolver, | 887 | &self.resolver, |
887 | ); | 888 | ); |
888 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { | 889 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { |
889 | Some((ty, func)) => { | 890 | Some((ty, func)) => { |
890 | let ty = canonicalizer.decanonicalize_ty(ty); | 891 | let ty = canonicalized_receiver.decanonicalize_ty(ty); |
891 | self.write_method_resolution(tgt_expr, func); | 892 | self.write_method_resolution(tgt_expr, func); |
892 | ( | 893 | ( |
893 | ty, | 894 | ty, |
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 | } |