}
fn resolve_all(mut self) -> InferenceResult {
+ let mut tv_stack = Vec::new();
let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default());
for ty in expr_types.values_mut() {
- let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
+ let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown));
*ty = resolved;
}
let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default());
for ty in pat_types.values_mut() {
- let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
+ let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown));
*ty = resolved;
}
InferenceResult {
/// by their known types. All types returned by the infer_* functions should
/// be resolved as far as possible, i.e. contain no type variables with
/// known type.
- fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
+ fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty {
Ty::Infer(tv) => {
let inner = tv.to_inner();
+ if tv_stack.contains(&inner) {
+ // recursive type
+ return tv.fallback_value();
+ }
if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
// known_ty may contain other variables that are known by now
- self.resolve_ty_as_possible(known_ty.clone())
+ tv_stack.push(inner);
+ let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone());
+ tv_stack.pop();
+ result
} else {
ty
}
/// Resolves the type completely; type variables without known type are
/// replaced by Ty::Unknown.
- fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
+ fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty {
Ty::Infer(tv) => {
let inner = tv.to_inner();
+ if tv_stack.contains(&inner) {
+ // recursive type
+ return tv.fallback_value();
+ }
if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
// known_ty may contain other variables that are known by now
- self.resolve_ty_completely(known_ty.clone())
+ tv_stack.push(inner);
+ let result = self.resolve_ty_completely(tv_stack, known_ty.clone());
+ tv_stack.pop();
+ result
} else {
tv.fallback_value()
}
let name = path.as_ident().cloned().unwrap_or_else(Name::self_param);
if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) {
let ty = self.type_of_pat.get(scope_entry.pat())?;
- let ty = self.resolve_ty_as_possible(ty.clone());
+ let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone());
return Some(ty);
};
};
// use a new type variable if we got Ty::Unknown here
let ty = self.insert_type_vars_shallow(ty);
self.unify(&ty, expected);
- let ty = self.resolve_ty_as_possible(ty);
+ let ty = self.resolve_ty_as_possible(&mut vec![], ty);
self.write_pat_ty(pat, ty.clone());
ty
}
// use a new type variable if we got Ty::Unknown here
let ty = self.insert_type_vars_shallow(ty);
self.unify(&ty, &expected.ty);
- let ty = self.resolve_ty_as_possible(ty);
+ let ty = self.resolve_ty_as_possible(&mut vec![], ty);
self.write_expr_ty(tgt_expr, ty.clone());
ty
}
--- /dev/null
+---
+created: "2019-01-26T22:42:22.331805845+00:00"
+creator: insta@0.5.2
+expression: "&result"
+source: crates/ra_hir/src/ty/tests.rs
+---
+[11; 80) '{ ...x)]; }': ()
+[21; 22) 'x': &&[unknown]
+[25; 32) 'unknown': &&[unknown]
+[42; 43) 'y': &&[unknown]
+[46; 53) 'unknown': &&[unknown]
+[59; 77) '[(x, y..., &x)]': [(&&[unknown], &&[unknown])]
+[60; 66) '(x, y)': (&&[unknown], &&[unknown])
+[61; 62) 'x': &&[unknown]
+[64; 65) 'y': &&[unknown]
+[68; 76) '(&y, &x)': (&&&[unknown], &&&[unknown])
+[69; 71) '&y': &&&[unknown]
+[70; 71) 'y': &&[unknown]
+[73; 75) '&x': &&&[unknown]
+[74; 75) 'x': &&[unknown]
+