diff options
author | Florian Diebold <[email protected]> | 2019-01-26 22:48:01 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-01-26 22:48:01 +0000 |
commit | 77f92674f9a2ea8e8cd303d15710621a4f7839cb (patch) | |
tree | 769232968e82fc463b3c08c7108ff2394e01ed4a /crates | |
parent | e40d8d40321b191ee82b8b07910f8a0898c8914c (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.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 27 |
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 | --- | ||
2 | created: "2019-01-26T22:42:22.329980185+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: 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 | --- | ||
2 | created: "2019-01-26T22:42:22.331805845+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: 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] | ||
566 | fn recursive_vars() { | ||
567 | check_inference( | ||
568 | "recursive_vars", | ||
569 | r#" | ||
570 | fn test() { | ||
571 | let y = unknown; | ||
572 | [y, &y]; | ||
573 | } | ||
574 | "#, | ||
575 | ); | ||
576 | } | ||
577 | |||
578 | #[test] | ||
579 | fn recursive_vars_2() { | ||
580 | check_inference( | ||
581 | "recursive_vars_2", | ||
582 | r#" | ||
583 | fn test() { | ||
584 | let x = unknown; | ||
585 | let y = unknown; | ||
586 | [(x, y), (&y, &x)]; | ||
587 | } | ||
588 | "#, | ||
589 | ); | ||
590 | } | ||
591 | |||
565 | fn infer(content: &str) -> String { | 592 | fn 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); |