diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer/unify.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 164 |
1 files changed, 0 insertions, 164 deletions
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs deleted file mode 100644 index 64d9394cf..000000000 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
1 | //! Unification and canonicalization logic. | ||
2 | |||
3 | use super::{InferenceContext, Obligation}; | ||
4 | use crate::db::HirDatabase; | ||
5 | use crate::ty::{ | ||
6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, | ||
7 | TypeWalk, | ||
8 | }; | ||
9 | use crate::util::make_mut_slice; | ||
10 | |||
11 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | ||
12 | pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> | ||
13 | where | ||
14 | 'a: 'b, | ||
15 | { | ||
16 | Canonicalizer { ctx: self, free_vars: Vec::new(), var_stack: Vec::new() } | ||
17 | } | ||
18 | } | ||
19 | |||
20 | pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase> | ||
21 | where | ||
22 | 'a: 'b, | ||
23 | { | ||
24 | ctx: &'b mut InferenceContext<'a, D>, | ||
25 | free_vars: Vec<InferTy>, | ||
26 | /// A stack of type variables that is used to detect recursive types (which | ||
27 | /// are an error, but we need to protect against them to avoid stack | ||
28 | /// overflows). | ||
29 | var_stack: Vec<super::TypeVarId>, | ||
30 | } | ||
31 | |||
32 | pub(super) struct Canonicalized<T> { | ||
33 | pub value: Canonical<T>, | ||
34 | free_vars: Vec<InferTy>, | ||
35 | } | ||
36 | |||
37 | impl<'a, 'b, D: HirDatabase> Canonicalizer<'a, 'b, D> | ||
38 | where | ||
39 | 'a: 'b, | ||
40 | { | ||
41 | fn add(&mut self, free_var: InferTy) -> usize { | ||
42 | self.free_vars.iter().position(|&v| v == free_var).unwrap_or_else(|| { | ||
43 | let next_index = self.free_vars.len(); | ||
44 | self.free_vars.push(free_var); | ||
45 | next_index | ||
46 | }) | ||
47 | } | ||
48 | |||
49 | fn do_canonicalize_ty(&mut self, ty: Ty) -> Ty { | ||
50 | ty.fold(&mut |ty| match ty { | ||
51 | Ty::Infer(tv) => { | ||
52 | let inner = tv.to_inner(); | ||
53 | if self.var_stack.contains(&inner) { | ||
54 | // recursive type | ||
55 | return tv.fallback_value(); | ||
56 | } | ||
57 | if let Some(known_ty) = | ||
58 | self.ctx.var_unification_table.inlined_probe_value(inner).known() | ||
59 | { | ||
60 | self.var_stack.push(inner); | ||
61 | let result = self.do_canonicalize_ty(known_ty.clone()); | ||
62 | self.var_stack.pop(); | ||
63 | result | ||
64 | } else { | ||
65 | let root = self.ctx.var_unification_table.find(inner); | ||
66 | let free_var = match tv { | ||
67 | InferTy::TypeVar(_) => InferTy::TypeVar(root), | ||
68 | InferTy::IntVar(_) => InferTy::IntVar(root), | ||
69 | InferTy::FloatVar(_) => InferTy::FloatVar(root), | ||
70 | InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root), | ||
71 | }; | ||
72 | let position = self.add(free_var); | ||
73 | Ty::Bound(position as u32) | ||
74 | } | ||
75 | } | ||
76 | _ => ty, | ||
77 | }) | ||
78 | } | ||
79 | |||
80 | fn do_canonicalize_trait_ref(&mut self, mut trait_ref: TraitRef) -> TraitRef { | ||
81 | for ty in make_mut_slice(&mut trait_ref.substs.0) { | ||
82 | *ty = self.do_canonicalize_ty(ty.clone()); | ||
83 | } | ||
84 | trait_ref | ||
85 | } | ||
86 | |||
87 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | ||
88 | Canonicalized { | ||
89 | value: Canonical { value: result, num_vars: self.free_vars.len() }, | ||
90 | free_vars: self.free_vars, | ||
91 | } | ||
92 | } | ||
93 | |||
94 | fn do_canonicalize_projection_ty(&mut self, mut projection_ty: ProjectionTy) -> ProjectionTy { | ||
95 | for ty in make_mut_slice(&mut projection_ty.parameters.0) { | ||
96 | *ty = self.do_canonicalize_ty(ty.clone()); | ||
97 | } | ||
98 | projection_ty | ||
99 | } | ||
100 | |||
101 | fn do_canonicalize_projection_predicate( | ||
102 | &mut self, | ||
103 | projection: ProjectionPredicate, | ||
104 | ) -> ProjectionPredicate { | ||
105 | let ty = self.do_canonicalize_ty(projection.ty); | ||
106 | let projection_ty = self.do_canonicalize_projection_ty(projection.projection_ty); | ||
107 | |||
108 | ProjectionPredicate { ty, projection_ty } | ||
109 | } | ||
110 | |||
111 | // FIXME: add some point, we need to introduce a `Fold` trait that abstracts | ||
112 | // over all the things that can be canonicalized (like Chalk and rustc have) | ||
113 | |||
114 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | ||
115 | let result = self.do_canonicalize_ty(ty); | ||
116 | self.into_canonicalized(result) | ||
117 | } | ||
118 | |||
119 | pub(crate) fn canonicalize_obligation( | ||
120 | mut self, | ||
121 | obligation: InEnvironment<Obligation>, | ||
122 | ) -> Canonicalized<InEnvironment<Obligation>> { | ||
123 | let result = match obligation.value { | ||
124 | Obligation::Trait(tr) => Obligation::Trait(self.do_canonicalize_trait_ref(tr)), | ||
125 | Obligation::Projection(pr) => { | ||
126 | Obligation::Projection(self.do_canonicalize_projection_predicate(pr)) | ||
127 | } | ||
128 | }; | ||
129 | self.into_canonicalized(InEnvironment { | ||
130 | value: result, | ||
131 | environment: obligation.environment, | ||
132 | }) | ||
133 | } | ||
134 | } | ||
135 | |||
136 | impl<T> Canonicalized<T> { | ||
137 | pub fn decanonicalize_ty(&self, mut ty: Ty) -> Ty { | ||
138 | ty.walk_mut_binders( | ||
139 | &mut |ty, binders| match ty { | ||
140 | &mut Ty::Bound(idx) => { | ||
141 | if idx as usize >= binders && (idx as usize - binders) < self.free_vars.len() { | ||
142 | *ty = Ty::Infer(self.free_vars[idx as usize - binders]); | ||
143 | } | ||
144 | } | ||
145 | _ => {} | ||
146 | }, | ||
147 | 0, | ||
148 | ); | ||
149 | ty | ||
150 | } | ||
151 | |||
152 | pub fn apply_solution( | ||
153 | &self, | ||
154 | ctx: &mut InferenceContext<'_, impl HirDatabase>, | ||
155 | solution: Canonical<Vec<Ty>>, | ||
156 | ) { | ||
157 | // the solution may contain new variables, which we need to convert to new inference vars | ||
158 | let new_vars = Substs((0..solution.num_vars).map(|_| ctx.new_type_var()).collect()); | ||
159 | for (i, ty) in solution.value.into_iter().enumerate() { | ||
160 | let var = self.free_vars[i]; | ||
161 | ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); | ||
162 | } | ||
163 | } | ||
164 | } | ||