mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-07 13:25:45 +00:00
parent
e40d8d4032
commit
77f92674f9
@ -862,14 +862,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -1014,13 +1015,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
/// 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
|
||||
}
|
||||
@ -1049,13 +1057,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
|
||||
/// 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()
|
||||
}
|
||||
@ -1070,7 +1085,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
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);
|
||||
};
|
||||
};
|
||||
@ -1239,7 +1254,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
// 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
|
||||
}
|
||||
@ -1538,7 +1553,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
// 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
|
||||
}
|
||||
|
14
crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap
Normal file
14
crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
created: "2019-01-26T22:42:22.329980185+00:00"
|
||||
creator: insta@0.5.2
|
||||
expression: "&result"
|
||||
source: crates/ra_hir/src/ty/tests.rs
|
||||
---
|
||||
[11; 48) '{ ...&y]; }': ()
|
||||
[21; 22) 'y': &[unknown]
|
||||
[25; 32) 'unknown': &[unknown]
|
||||
[38; 45) '[y, &y]': [&&[unknown]]
|
||||
[39; 40) 'y': &[unknown]
|
||||
[42; 44) '&y': &&[unknown]
|
||||
[43; 44) 'y': &[unknown]
|
||||
|
21
crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap
Normal file
21
crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
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]
|
||||
|
@ -562,6 +562,33 @@ fn quux() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursive_vars() {
|
||||
check_inference(
|
||||
"recursive_vars",
|
||||
r#"
|
||||
fn test() {
|
||||
let y = unknown;
|
||||
[y, &y];
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursive_vars_2() {
|
||||
check_inference(
|
||||
"recursive_vars_2",
|
||||
r#"
|
||||
fn test() {
|
||||
let x = unknown;
|
||||
let y = unknown;
|
||||
[(x, y), (&y, &x)];
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
fn infer(content: &str) -> String {
|
||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||
let source_file = db.parse(file_id);
|
||||
|
Loading…
Reference in New Issue
Block a user