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 | |
parent | 5795d773dbcce67577851da02e4d659f0daf1a12 (diff) |
Handle recursive types in canonicalization
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 2 |
3 files changed, 15 insertions, 5 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 24350bda7..2ec1a7692 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -351,7 +351,7 @@ impl SourceAnalyzer { | |||
351 | callback: impl FnMut(&Ty, Function) -> Option<T>, | 351 | callback: impl FnMut(&Ty, Function) -> Option<T>, |
352 | ) -> Option<T> { | 352 | ) -> Option<T> { |
353 | // There should be no inference vars in types passed here | 353 | // There should be no inference vars in types passed here |
354 | // TODO check that? | 354 | // FIXME check that? |
355 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; | 355 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; |
356 | crate::ty::method_resolution::iterate_method_candidates( | 356 | crate::ty::method_resolution::iterate_method_candidates( |
357 | &canonical, | 357 | &canonical, |
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); |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 0c6e5a4f5..74370bae9 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -183,7 +183,7 @@ where | |||
183 | fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { | 183 | fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { |
184 | debug!("struct_datum {:?}", struct_id); | 184 | debug!("struct_datum {:?}", struct_id); |
185 | let type_ctor = from_chalk(self.db, struct_id); | 185 | let type_ctor = from_chalk(self.db, struct_id); |
186 | // TODO might be nicer if we can create a fake GenericParams for the TypeCtor | 186 | // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor |
187 | let (num_params, upstream) = match type_ctor { | 187 | let (num_params, upstream) = match type_ctor { |
188 | TypeCtor::Bool | 188 | TypeCtor::Bool |
189 | | TypeCtor::Char | 189 | | TypeCtor::Char |