diff options
author | Florian Diebold <[email protected]> | 2019-02-09 17:24:54 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-02-09 20:37:09 +0000 |
commit | 7ebde241c00cd9eb816b1aa7cb212a946afb0d3e (patch) | |
tree | ca49de264fa411c62216952b52b865fcce5bdabe | |
parent | 8bcb84ea681f982946a24b5e000ddde58247adba (diff) |
Fix two crashes found by running inference on all of rustc
-rw-r--r-- | crates/ra_hir/src/ty.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 33 |
4 files changed, 84 insertions, 15 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 453520bbe..28cb32ac5 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -989,19 +989,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
989 | /// If `ty` is a type variable with known type, returns that type; | 989 | /// If `ty` is a type variable with known type, returns that type; |
990 | /// otherwise, return ty. | 990 | /// otherwise, return ty. |
991 | fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { | 991 | fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { |
992 | match ty { | 992 | let mut ty = Cow::Borrowed(ty); |
993 | Ty::Infer(tv) => { | 993 | for _ in 0..3 { |
994 | let inner = tv.to_inner(); | 994 | // the type variable could resolve to a int/float variable |
995 | match self.var_unification_table.probe_value(inner).known() { | 995 | match &*ty { |
996 | Some(known_ty) => { | 996 | Ty::Infer(tv) => { |
997 | // The known_ty can't be a type var itself | 997 | let inner = tv.to_inner(); |
998 | Cow::Owned(known_ty.clone()) | 998 | match self.var_unification_table.probe_value(inner).known() { |
999 | Some(known_ty) => { | ||
1000 | // The known_ty can't be a type var itself | ||
1001 | ty = Cow::Owned(known_ty.clone()); | ||
1002 | } | ||
1003 | _ => return ty, | ||
999 | } | 1004 | } |
1000 | _ => Cow::Borrowed(ty), | ||
1001 | } | 1005 | } |
1006 | _ => return ty, | ||
1002 | } | 1007 | } |
1003 | _ => Cow::Borrowed(ty), | ||
1004 | } | 1008 | } |
1009 | ty | ||
1005 | } | 1010 | } |
1006 | 1011 | ||
1007 | /// Resolves the type completely; type variables without known type are | 1012 | /// Resolves the type completely; type variables without known type are |
@@ -1185,17 +1190,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1185 | self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) | 1190 | self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) |
1186 | } | 1191 | } |
1187 | Pat::Bind { mode, name: _name, subpat } => { | 1192 | Pat::Bind { mode, name: _name, subpat } => { |
1188 | let subty = if let Some(subpat) = subpat { | 1193 | let inner_ty = if let Some(subpat) = subpat { |
1189 | self.infer_pat(*subpat, expected) | 1194 | self.infer_pat(*subpat, expected) |
1190 | } else { | 1195 | } else { |
1191 | expected.clone() | 1196 | expected.clone() |
1192 | }; | 1197 | }; |
1198 | let inner_ty = self.insert_type_vars_shallow(inner_ty); | ||
1193 | 1199 | ||
1194 | match mode { | 1200 | let bound_ty = match mode { |
1195 | BindingAnnotation::Ref => Ty::Ref(subty.into(), Mutability::Shared), | 1201 | BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared), |
1196 | BindingAnnotation::RefMut => Ty::Ref(subty.into(), Mutability::Mut), | 1202 | BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut), |
1197 | BindingAnnotation::Mutable | BindingAnnotation::Unannotated => subty, | 1203 | BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(), |
1198 | } | 1204 | }; |
1205 | let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); | ||
1206 | self.write_pat_ty(pat, bound_ty); | ||
1207 | return inner_ty; | ||
1199 | } | 1208 | } |
1200 | _ => Ty::Unknown, | 1209 | _ => Ty::Unknown, |
1201 | }; | 1210 | }; |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap new file mode 100644 index 000000000..4b99788e4 --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap | |||
@@ -0,0 +1,13 @@ | |||
1 | --- | ||
2 | created: "2019-02-09T16:56:24.803326529Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [54; 139) '{ ... } }': () | ||
8 | [60; 137) 'match ... }': () | ||
9 | [66; 83) 'someth...nknown': Maybe<[unknown]> | ||
10 | [94; 124) 'Maybe:...thing)': Maybe<[unknown]> | ||
11 | [106; 123) 'ref mu...ething': &mut [unknown] | ||
12 | [128; 130) '()': () | ||
13 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap new file mode 100644 index 000000000..fd0b39b7d --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap | |||
@@ -0,0 +1,14 @@ | |||
1 | --- | ||
2 | created: "2019-02-09T17:03:11.974225590Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [23; 53) '{ ...n']; }': () | ||
8 | [29; 50) '&[0, b...b'\n']': &[u8] | ||
9 | [30; 50) '[0, b'...b'\n']': [u8] | ||
10 | [31; 32) '0': u8 | ||
11 | [34; 39) 'b'\n'': u8 | ||
12 | [41; 42) '1': u8 | ||
13 | [44; 49) 'b'\n'': u8 | ||
14 | |||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 2621d1b55..3139eba0b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -630,6 +630,39 @@ fn test() { | |||
630 | ); | 630 | ); |
631 | } | 631 | } |
632 | 632 | ||
633 | #[test] | ||
634 | fn infer_std_crash_1() { | ||
635 | // caused stack overflow, taken from std | ||
636 | check_inference( | ||
637 | "infer_std_crash_1", | ||
638 | r#" | ||
639 | enum Maybe<T> { | ||
640 | Real(T), | ||
641 | Fake, | ||
642 | } | ||
643 | |||
644 | fn write() { | ||
645 | match something_unknown { | ||
646 | Maybe::Real(ref mut something) => (), | ||
647 | } | ||
648 | } | ||
649 | "#, | ||
650 | ); | ||
651 | } | ||
652 | |||
653 | #[test] | ||
654 | fn infer_std_crash_2() { | ||
655 | // caused "equating two type variables, ...", taken from std | ||
656 | check_inference( | ||
657 | "infer_std_crash_2", | ||
658 | r#" | ||
659 | fn test_line_buffer() { | ||
660 | &[0, b'\n', 1, b'\n']; | ||
661 | } | ||
662 | "#, | ||
663 | ); | ||
664 | } | ||
665 | |||
633 | fn infer(content: &str) -> String { | 666 | fn infer(content: &str) -> String { |
634 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 667 | let (db, _, file_id) = MockDatabase::with_single_file(content); |
635 | let source_file = db.parse(file_id); | 668 | let source_file = db.parse(file_id); |