mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 20:09:19 +00:00
Handle recursive types in canonicalization
This commit is contained in:
parent
5795d773db
commit
f43e69a64e
3 changed files with 15 additions and 5 deletions
|
@ -351,7 +351,7 @@ impl SourceAnalyzer {
|
||||||
callback: impl FnMut(&Ty, Function) -> Option<T>,
|
callback: impl FnMut(&Ty, Function) -> Option<T>,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
// There should be no inference vars in types passed here
|
// 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 };
|
let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
|
||||||
crate::ty::method_resolution::iterate_method_candidates(
|
crate::ty::method_resolution::iterate_method_candidates(
|
||||||
&canonical,
|
&canonical,
|
||||||
|
|
|
@ -9,7 +9,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
where
|
where
|
||||||
'a: 'b,
|
'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>,
|
ctx: &'b mut InferenceContext<'a, D>,
|
||||||
free_vars: Vec<InferTy>,
|
free_vars: Vec<InferTy>,
|
||||||
|
/// 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<super::TypeVarId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct Canonicalized<T> {
|
pub(super) struct Canonicalized<T> {
|
||||||
|
@ -42,9 +46,15 @@ where
|
||||||
ty.fold(&mut |ty| match ty {
|
ty.fold(&mut |ty| match ty {
|
||||||
Ty::Infer(tv) => {
|
Ty::Infer(tv) => {
|
||||||
let inner = tv.to_inner();
|
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() {
|
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 {
|
} else {
|
||||||
let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner));
|
let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner));
|
||||||
let position = self.add(free_var);
|
let position = self.add(free_var);
|
||||||
|
|
|
@ -183,7 +183,7 @@ where
|
||||||
fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
|
fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
|
||||||
debug!("struct_datum {:?}", struct_id);
|
debug!("struct_datum {:?}", struct_id);
|
||||||
let type_ctor = from_chalk(self.db, 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 {
|
let (num_params, upstream) = match type_ctor {
|
||||||
TypeCtor::Bool
|
TypeCtor::Bool
|
||||||
| TypeCtor::Char
|
| TypeCtor::Char
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue