]> git.lizzy.rs Git - rust.git/commitdiff
Fix two crashes found by running inference on all of rustc
authorFlorian Diebold <flodiebold@gmail.com>
Sat, 9 Feb 2019 17:24:54 +0000 (18:24 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Sat, 9 Feb 2019 20:37:09 +0000 (21:37 +0100)
crates/ra_hir/src/ty.rs
crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap [new file with mode: 0644]
crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap [new file with mode: 0644]
crates/ra_hir/src/ty/tests.rs

index 453520bbe31ee2efa1f98bb6b0640aeff823a049..28cb32ac58ada14f7202c3eb0aa7127b9c637441 100644 (file)
@@ -989,19 +989,24 @@ fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> T
     /// If `ty` is a type variable with known type, returns that type;
     /// otherwise, return ty.
     fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
-        match ty {
-            Ty::Infer(tv) => {
-                let inner = tv.to_inner();
-                match self.var_unification_table.probe_value(inner).known() {
-                    Some(known_ty) => {
-                        // The known_ty can't be a type var itself
-                        Cow::Owned(known_ty.clone())
+        let mut ty = Cow::Borrowed(ty);
+        for _ in 0..3 {
+            // the type variable could resolve to a int/float variable
+            match &*ty {
+                Ty::Infer(tv) => {
+                    let inner = tv.to_inner();
+                    match self.var_unification_table.probe_value(inner).known() {
+                        Some(known_ty) => {
+                            // The known_ty can't be a type var itself
+                            ty = Cow::Owned(known_ty.clone());
+                        }
+                        _ => return ty,
                     }
-                    _ => Cow::Borrowed(ty),
                 }
+                _ => return ty,
             }
-            _ => Cow::Borrowed(ty),
         }
+        ty
     }
 
     /// Resolves the type completely; type variables without known type are
@@ -1185,17 +1190,21 @@ fn infer_pat(&mut self, pat: PatId, expected: &Ty) -> Ty {
                 self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown)
             }
             Pat::Bind { mode, name: _name, subpat } => {
-                let subty = if let Some(subpat) = subpat {
+                let inner_ty = if let Some(subpat) = subpat {
                     self.infer_pat(*subpat, expected)
                 } else {
                     expected.clone()
                 };
+                let inner_ty = self.insert_type_vars_shallow(inner_ty);
 
-                match mode {
-                    BindingAnnotation::Ref => Ty::Ref(subty.into(), Mutability::Shared),
-                    BindingAnnotation::RefMut => Ty::Ref(subty.into(), Mutability::Mut),
-                    BindingAnnotation::Mutable | BindingAnnotation::Unannotated => subty,
-                }
+                let bound_ty = match mode {
+                    BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared),
+                    BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut),
+                    BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(),
+                };
+                let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
+                self.write_pat_ty(pat, bound_ty);
+                return inner_ty;
             }
             _ => Ty::Unknown,
         };
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 (file)
index 0000000..4b99788
--- /dev/null
@@ -0,0 +1,13 @@
+---
+created: "2019-02-09T16:56:24.803326529Z"
+creator: insta@0.6.1
+source: crates/ra_hir/src/ty/tests.rs
+expression: "&result"
+---
+[54; 139) '{     ...   } }': ()
+[60; 137) 'match ...     }': ()
+[66; 83) 'someth...nknown': Maybe<[unknown]>
+[94; 124) 'Maybe:...thing)': Maybe<[unknown]>
+[106; 123) 'ref mu...ething': &mut [unknown]
+[128; 130) '()': ()
+
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 (file)
index 0000000..fd0b39b
--- /dev/null
@@ -0,0 +1,14 @@
+---
+created: "2019-02-09T17:03:11.974225590Z"
+creator: insta@0.6.1
+source: crates/ra_hir/src/ty/tests.rs
+expression: "&result"
+---
+[23; 53) '{     ...n']; }': ()
+[29; 50) '&[0, b...b'\n']': &[u8]
+[30; 50) '[0, b'...b'\n']': [u8]
+[31; 32) '0': u8
+[34; 39) 'b'\n'': u8
+[41; 42) '1': u8
+[44; 49) 'b'\n'': u8
+
index 2621d1b55211d12bf530c19cf3a0dc7c347fb050..3139eba0b47fc7650f4b50a1376b3bf63a78cddc 100644 (file)
@@ -630,6 +630,39 @@ fn test() {
     );
 }
 
+#[test]
+fn infer_std_crash_1() {
+    // caused stack overflow, taken from std
+    check_inference(
+        "infer_std_crash_1",
+        r#"
+enum Maybe<T> {
+    Real(T),
+    Fake,
+}
+
+fn write() {
+    match something_unknown {
+        Maybe::Real(ref mut something) => (),
+    }
+}
+"#,
+    );
+}
+
+#[test]
+fn infer_std_crash_2() {
+    // caused "equating two type variables, ...", taken from std
+    check_inference(
+        "infer_std_crash_2",
+        r#"
+fn test_line_buffer() {
+    &[0, b'\n', 1, b'\n'];
+}
+"#,
+    );
+}
+
 fn infer(content: &str) -> String {
     let (db, _, file_id) = MockDatabase::with_single_file(content);
     let source_file = db.parse(file_id);