aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-05-04 14:42:00 +0100
committerFlorian Diebold <[email protected]>2019-05-04 17:18:30 +0100
commit621864319f8e3149c08d4d0f99b975407ba00ffd (patch)
treecbb6f7a9aa414ec0770556899559e746c740d2c9 /crates/ra_hir/src/ty
parent0bcf47b22b01f66c2f2056f5871e32071ba95b01 (diff)
Make canonicalization API a bit nicer
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer.rs31
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs56
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
18pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase> 16pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase>
19where 17where
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
24pub(super) struct Canonicalized<T> {
25 pub value: Canonical<T>,
26 free_vars: Vec<InferTy>,
24} 27}
25 28
26impl<'a, 'b, D: HirDatabase> Canonicalizer<'a, 'b, D> 29impl<'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
85impl<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}