aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/infer
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-05-04 17:25:07 +0100
committerFlorian Diebold <[email protected]>2019-05-04 17:25:36 +0100
commitf43e69a64eea0caf8b9f5ced31e7f77dc0d33d65 (patch)
tree08a4e6edf39302e086fe6495fee4de1545e1f8f0 /crates/ra_hir/src/ty/infer
parent5795d773dbcce67577851da02e4d659f0daf1a12 (diff)
Handle recursive types in canonicalization
Diffstat (limited to 'crates/ra_hir/src/ty/infer')
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs16
1 files changed, 13 insertions, 3 deletions
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index c9c8959c4..8ca7e957d 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -9,7 +9,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
9 where 9 where
10 'a: 'b, 10 'a: 'b,
11 { 11 {
12 Canonicalizer { ctx: self, free_vars: Vec::new() } 12 Canonicalizer { ctx: self, free_vars: Vec::new(), var_stack: Vec::new() }
13 } 13 }
14} 14}
15 15
@@ -19,6 +19,10 @@ where
19{ 19{
20 ctx: &'b mut InferenceContext<'a, D>, 20 ctx: &'b mut InferenceContext<'a, D>,
21 free_vars: Vec<InferTy>, 21 free_vars: Vec<InferTy>,
22 /// A stack of type variables that is used to detect recursive types (which
23 /// are an error, but we need to protect against them to avoid stack
24 /// overflows).
25 var_stack: Vec<super::TypeVarId>,
22} 26}
23 27
24pub(super) struct Canonicalized<T> { 28pub(super) struct Canonicalized<T> {
@@ -42,9 +46,15 @@ where
42 ty.fold(&mut |ty| match ty { 46 ty.fold(&mut |ty| match ty {
43 Ty::Infer(tv) => { 47 Ty::Infer(tv) => {
44 let inner = tv.to_inner(); 48 let inner = tv.to_inner();
45 // TODO prevent infinite loops? => keep var stack 49 if self.var_stack.contains(&inner) {
50 // recursive type
51 return tv.fallback_value();
52 }
46 if let Some(known_ty) = self.ctx.var_unification_table.probe_value(inner).known() { 53 if let Some(known_ty) = self.ctx.var_unification_table.probe_value(inner).known() {
47 self.do_canonicalize_ty(known_ty.clone()) 54 self.var_stack.push(inner);
55 let result = self.do_canonicalize_ty(known_ty.clone());
56 self.var_stack.pop();
57 result
48 } else { 58 } else {
49 let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner)); 59 let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner));
50 let position = self.add(free_var); 60 let position = self.add(free_var);