about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-04-10 12:48:47 +0200
committerGitHub <noreply@github.com>2020-04-10 12:48:47 +0200
commit5cd1599fc9d012e6337501239a1f10e7b9ca0ee1 (patch)
tree5086e6d8bd6ff8e2e98e06959e68569328bbb225
parent74e93bb8e6cd15dd262868b5e13605e9c595bef7 (diff)
parentf2e4709f2252103a2461991dba209f8ab4d76aca (diff)
downloadrust-5cd1599fc9d012e6337501239a1f10e7b9ca0ee1.tar.gz
rust-5cd1599fc9d012e6337501239a1f10e7b9ca0ee1.zip
Rollup merge of #70932 - mark-i-m:de-abuse-err-2, r=Centril
De-abuse TyKind::Error in pattern type checking

r? @eddyb

cc https://github.com/rust-lang/rust/issues/70866

In particular, I would appreciate extra scrutiny over the soundness of these changes.

Also, this will go a bit slowly because I'm going to use my other PR (#70551) to check if I missed anything.
-rw-r--r--src/librustc_typeck/check/pat.rs38
1 files changed, 22 insertions, 16 deletions
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index b3cace8298a..0335aba9144 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -1353,23 +1353,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
-        let err = self.tcx.types.err;
         let expected = self.structurally_resolved_type(span, expected);
-        let (element_ty, slice_ty, inferred) = match expected.kind {
+        let (element_ty, opt_slice_ty, inferred) = match expected.kind {
             // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
             ty::Array(element_ty, len) => {
                 let min = before.len() as u64 + after.len() as u64;
-                let (slice_ty, expected) =
+                let (opt_slice_ty, expected) =
                     self.check_array_pat_len(span, element_ty, expected, slice, len, min);
-                (element_ty, slice_ty, expected)
+                // `opt_slice_ty.is_none()` => `slice.is_none()`.
+                // Note, though, that opt_slice_ty could be `Some(error_ty)`.
+                assert!(opt_slice_ty.is_some() || slice.is_none());
+                (element_ty, opt_slice_ty, expected)
             }
-            ty::Slice(element_ty) => (element_ty, expected, expected),
+            ty::Slice(element_ty) => (element_ty, Some(expected), expected),
             // The expected type must be an array or slice, but was neither, so error.
             _ => {
                 if !expected.references_error() {
                     self.error_expected_array_or_slice(span, expected);
                 }
-                (err, err, err)
+                let err = self.tcx.types.err;
+                (err, Some(err), err)
             }
         };
 
@@ -1379,7 +1382,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         // Type check the `slice`, if present, against its expected type.
         if let Some(slice) = slice {
-            self.check_pat(&slice, slice_ty, def_bm, ti);
+            self.check_pat(&slice, opt_slice_ty.unwrap(), def_bm, ti);
         }
         // Type check the elements after `slice`, if present.
         for elt in after {
@@ -1390,9 +1393,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Type check the length of an array pattern.
     ///
-    /// Returns both the type of the variable length pattern
-    /// (or `tcx.err` in case there is none),
-    /// and the potentially inferred array type.
+    /// Returns both the type of the variable length pattern (or `None`), and the potentially
+    /// inferred array type. We only return `None` for the slice type if `slice.is_none()`.
     fn check_array_pat_len(
         &self,
         span: Span,
@@ -1401,20 +1403,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         slice: Option<&'tcx Pat<'tcx>>,
         len: &ty::Const<'tcx>,
         min_len: u64,
-    ) -> (Ty<'tcx>, Ty<'tcx>) {
+    ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
         if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) {
             // Now we know the length...
             if slice.is_none() {
                 // ...and since there is no variable-length pattern,
                 // we require an exact match between the number of elements
                 // in the array pattern and as provided by the matched type.
-                if min_len != len {
-                    self.error_scrutinee_inconsistent_length(span, min_len, len);
+                if min_len == len {
+                    return (None, arr_ty);
                 }
+
+                self.error_scrutinee_inconsistent_length(span, min_len, len);
             } else if let Some(pat_len) = len.checked_sub(min_len) {
                 // The variable-length pattern was there,
                 // so it has an array type with the remaining elements left as its size...
-                return (self.tcx.mk_array(element_ty, pat_len), arr_ty);
+                return (Some(self.tcx.mk_array(element_ty, pat_len)), arr_ty);
             } else {
                 // ...however, in this case, there were no remaining elements.
                 // That is, the slice pattern requires more than the array type offers.
@@ -1425,14 +1429,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // which we can use to infer the length of the array.
             let updated_arr_ty = self.tcx.mk_array(element_ty, min_len);
             self.demand_eqtype(span, updated_arr_ty, arr_ty);
-            return (self.tcx.types.err, updated_arr_ty);
+            return (None, updated_arr_ty);
         } else {
             // We have a variable-length pattern and don't know the array length.
             // This happens if we have e.g.,
             // `let [a, b, ..] = arr` where `arr: [T; N]` where `const N: usize`.
             self.error_scrutinee_unfixed_length(span);
         }
-        (self.tcx.types.err, arr_ty)
+
+        // If we get here, we must have emitted an error.
+        (Some(self.tcx.types.err), arr_ty)
     }
 
     fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {