diff options
author | Florian Diebold <[email protected]> | 2020-02-21 20:46:21 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-02-22 10:09:21 +0000 |
commit | f126808b2ee79792631edc377bc8c2b0f329eebf (patch) | |
tree | 687760c2eec85bdad42f6c6c56ab32b17a03aa37 /crates | |
parent | 0dfbbaf03b03618dcb7ba203ddc453533bb8d1b4 (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')
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 99 |
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}; | |||
7 | use test_utils::tested_by; | 7 | use test_utils::tested_by; |
8 | 8 | ||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use 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 | ||
15 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 12 | impl<'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, |