diff options
author | Florian Diebold <[email protected]> | 2019-05-04 17:25:07 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-05-04 17:25:36 +0100 |
commit | f43e69a64eea0caf8b9f5ced31e7f77dc0d33d65 (patch) | |
tree | 08a4e6edf39302e086fe6495fee4de1545e1f8f0 /crates/ra_hir/src/ty/infer | |
parent | 5795d773dbcce67577851da02e4d659f0daf1a12 (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.rs | 16 |
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 | ||
24 | pub(super) struct Canonicalized<T> { | 28 | pub(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); |