From f43e69a64eea0caf8b9f5ced31e7f77dc0d33d65 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 4 May 2019 18:25:07 +0200 Subject: Handle recursive types in canonicalization --- crates/ra_hir/src/source_binder.rs | 2 +- crates/ra_hir/src/ty/infer/unify.rs | 16 +++++++++++++--- crates/ra_hir/src/ty/traits/chalk.rs | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir') 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 { callback: impl FnMut(&Ty, Function) -> Option, ) -> Option { // There should be no inference vars in types passed here - // TODO check that? + // FIXME check that? let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; crate::ty::method_resolution::iterate_method_candidates( &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> { where 'a: 'b, { - Canonicalizer { ctx: self, free_vars: Vec::new() } + Canonicalizer { ctx: self, free_vars: Vec::new(), var_stack: Vec::new() } } } @@ -19,6 +19,10 @@ where { ctx: &'b mut InferenceContext<'a, D>, free_vars: Vec, + /// A stack of type variables that is used to detect recursive types (which + /// are an error, but we need to protect against them to avoid stack + /// overflows). + var_stack: Vec, } pub(super) struct Canonicalized { @@ -42,9 +46,15 @@ where ty.fold(&mut |ty| match ty { Ty::Infer(tv) => { let inner = tv.to_inner(); - // TODO prevent infinite loops? => keep var stack + if self.var_stack.contains(&inner) { + // recursive type + return tv.fallback_value(); + } if let Some(known_ty) = self.ctx.var_unification_table.probe_value(inner).known() { - self.do_canonicalize_ty(known_ty.clone()) + self.var_stack.push(inner); + let result = self.do_canonicalize_ty(known_ty.clone()); + self.var_stack.pop(); + result } else { let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner)); 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 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc { debug!("struct_datum {:?}", struct_id); let type_ctor = from_chalk(self.db, struct_id); - // TODO might be nicer if we can create a fake GenericParams for the TypeCtor + // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor let (num_params, upstream) = match type_ctor { TypeCtor::Bool | TypeCtor::Char -- cgit v1.2.3