aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-26 22:48:01 +0000
committerFlorian Diebold <[email protected]>2019-01-26 22:48:01 +0000
commit77f92674f9a2ea8e8cd303d15710621a4f7839cb (patch)
tree769232968e82fc463b3c08c7108ff2394e01ed4a /crates
parente40d8d40321b191ee82b8b07910f8a0898c8914c (diff)
Handle cycles in type vars
This might be the cause of #587.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ty.rs33
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap14
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap21
-rw-r--r--crates/ra_hir/src/ty/tests.rs27
4 files changed, 86 insertions, 9 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 179ebddee..67fcc5346 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -862,14 +862,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
862 } 862 }
863 863
864 fn resolve_all(mut self) -> InferenceResult { 864 fn resolve_all(mut self) -> InferenceResult {
865 let mut tv_stack = Vec::new();
865 let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default()); 866 let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default());
866 for ty in expr_types.values_mut() { 867 for ty in expr_types.values_mut() {
867 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); 868 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown));
868 *ty = resolved; 869 *ty = resolved;
869 } 870 }
870 let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default()); 871 let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default());
871 for ty in pat_types.values_mut() { 872 for ty in pat_types.values_mut() {
872 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); 873 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown));
873 *ty = resolved; 874 *ty = resolved;
874 } 875 }
875 InferenceResult { 876 InferenceResult {
@@ -1014,13 +1015,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1014 /// by their known types. All types returned by the infer_* functions should 1015 /// by their known types. All types returned by the infer_* functions should
1015 /// be resolved as far as possible, i.e. contain no type variables with 1016 /// be resolved as far as possible, i.e. contain no type variables with
1016 /// known type. 1017 /// known type.
1017 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { 1018 fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
1018 ty.fold(&mut |ty| match ty { 1019 ty.fold(&mut |ty| match ty {
1019 Ty::Infer(tv) => { 1020 Ty::Infer(tv) => {
1020 let inner = tv.to_inner(); 1021 let inner = tv.to_inner();
1022 if tv_stack.contains(&inner) {
1023 // recursive type
1024 return tv.fallback_value();
1025 }
1021 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { 1026 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
1022 // known_ty may contain other variables that are known by now 1027 // known_ty may contain other variables that are known by now
1023 self.resolve_ty_as_possible(known_ty.clone()) 1028 tv_stack.push(inner);
1029 let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone());
1030 tv_stack.pop();
1031 result
1024 } else { 1032 } else {
1025 ty 1033 ty
1026 } 1034 }
@@ -1049,13 +1057,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1049 1057
1050 /// Resolves the type completely; type variables without known type are 1058 /// Resolves the type completely; type variables without known type are
1051 /// replaced by Ty::Unknown. 1059 /// replaced by Ty::Unknown.
1052 fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { 1060 fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
1053 ty.fold(&mut |ty| match ty { 1061 ty.fold(&mut |ty| match ty {
1054 Ty::Infer(tv) => { 1062 Ty::Infer(tv) => {
1055 let inner = tv.to_inner(); 1063 let inner = tv.to_inner();
1064 if tv_stack.contains(&inner) {
1065 // recursive type
1066 return tv.fallback_value();
1067 }
1056 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { 1068 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
1057 // known_ty may contain other variables that are known by now 1069 // known_ty may contain other variables that are known by now
1058 self.resolve_ty_completely(known_ty.clone()) 1070 tv_stack.push(inner);
1071 let result = self.resolve_ty_completely(tv_stack, known_ty.clone());
1072 tv_stack.pop();
1073 result
1059 } else { 1074 } else {
1060 tv.fallback_value() 1075 tv.fallback_value()
1061 } 1076 }
@@ -1070,7 +1085,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1070 let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); 1085 let name = path.as_ident().cloned().unwrap_or_else(Name::self_param);
1071 if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { 1086 if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) {
1072 let ty = self.type_of_pat.get(scope_entry.pat())?; 1087 let ty = self.type_of_pat.get(scope_entry.pat())?;
1073 let ty = self.resolve_ty_as_possible(ty.clone()); 1088 let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone());
1074 return Some(ty); 1089 return Some(ty);
1075 }; 1090 };
1076 }; 1091 };
@@ -1239,7 +1254,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1239 // use a new type variable if we got Ty::Unknown here 1254 // use a new type variable if we got Ty::Unknown here
1240 let ty = self.insert_type_vars_shallow(ty); 1255 let ty = self.insert_type_vars_shallow(ty);
1241 self.unify(&ty, expected); 1256 self.unify(&ty, expected);
1242 let ty = self.resolve_ty_as_possible(ty); 1257 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1243 self.write_pat_ty(pat, ty.clone()); 1258 self.write_pat_ty(pat, ty.clone());
1244 ty 1259 ty
1245 } 1260 }
@@ -1538,7 +1553,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1538 // use a new type variable if we got Ty::Unknown here 1553 // use a new type variable if we got Ty::Unknown here
1539 let ty = self.insert_type_vars_shallow(ty); 1554 let ty = self.insert_type_vars_shallow(ty);
1540 self.unify(&ty, &expected.ty); 1555 self.unify(&ty, &expected.ty);
1541 let ty = self.resolve_ty_as_possible(ty); 1556 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1542 self.write_expr_ty(tgt_expr, ty.clone()); 1557 self.write_expr_ty(tgt_expr, ty.clone());
1543 ty 1558 ty
1544 } 1559 }
diff --git a/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap
new file mode 100644
index 000000000..c3227ff7e
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap
@@ -0,0 +1,14 @@
1---
2created: "2019-01-26T22:42:22.329980185+00:00"
3creator: [email protected]
4expression: "&result"
5source: crates/ra_hir/src/ty/tests.rs
6---
7[11; 48) '{ ...&y]; }': ()
8[21; 22) 'y': &[unknown]
9[25; 32) 'unknown': &[unknown]
10[38; 45) '[y, &y]': [&&[unknown]]
11[39; 40) 'y': &[unknown]
12[42; 44) '&y': &&[unknown]
13[43; 44) 'y': &[unknown]
14
diff --git a/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap
new file mode 100644
index 000000000..de124da5b
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap
@@ -0,0 +1,21 @@
1---
2created: "2019-01-26T22:42:22.331805845+00:00"
3creator: [email protected]
4expression: "&result"
5source: crates/ra_hir/src/ty/tests.rs
6---
7[11; 80) '{ ...x)]; }': ()
8[21; 22) 'x': &&[unknown]
9[25; 32) 'unknown': &&[unknown]
10[42; 43) 'y': &&[unknown]
11[46; 53) 'unknown': &&[unknown]
12[59; 77) '[(x, y..., &x)]': [(&&[unknown], &&[unknown])]
13[60; 66) '(x, y)': (&&[unknown], &&[unknown])
14[61; 62) 'x': &&[unknown]
15[64; 65) 'y': &&[unknown]
16[68; 76) '(&y, &x)': (&&&[unknown], &&&[unknown])
17[69; 71) '&y': &&&[unknown]
18[70; 71) 'y': &&[unknown]
19[73; 75) '&x': &&&[unknown]
20[74; 75) 'x': &&[unknown]
21
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index e1165f682..e34daa0f7 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -562,6 +562,33 @@ fn quux() {
562 ); 562 );
563} 563}
564 564
565#[test]
566fn recursive_vars() {
567 check_inference(
568 "recursive_vars",
569 r#"
570fn test() {
571 let y = unknown;
572 [y, &y];
573}
574"#,
575 );
576}
577
578#[test]
579fn recursive_vars_2() {
580 check_inference(
581 "recursive_vars_2",
582 r#"
583fn test() {
584 let x = unknown;
585 let y = unknown;
586 [(x, y), (&y, &x)];
587}
588"#,
589 );
590}
591
565fn infer(content: &str) -> String { 592fn infer(content: &str) -> String {
566 let (db, _, file_id) = MockDatabase::with_single_file(content); 593 let (db, _, file_id) = MockDatabase::with_single_file(content);
567 let source_file = db.parse(file_id); 594 let source_file = db.parse(file_id);