about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/pat.rs44
-rw-r--r--src/test/ui/const-generics/infer_arg_from_pat.rs27
-rw-r--r--src/test/ui/const-generics/infer_arg_from_pat.stderr8
-rw-r--r--src/test/ui/const-generics/infer_arr_len_from_pat.rs13
-rw-r--r--src/test/ui/const-generics/infer_arr_len_from_pat.stderr8
-rw-r--r--src/test/ui/error-codes/E0730.rs2
-rw-r--r--src/test/ui/error-codes/E0730.stderr9
7 files changed, 90 insertions, 21 deletions
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index fc91142dd7d..b3e8569f372 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -1355,16 +1355,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let err = self.tcx.types.err;
         let expected = self.structurally_resolved_type(span, expected);
-        let (inner_ty, slice_ty, expected) = match expected.kind {
+        let (element_ty, slice_ty, expected) = match expected.kind {
             // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
-            ty::Array(inner_ty, len) => {
+            ty::Array(element_ty, len) => {
                 let min = before.len() as u64 + after.len() as u64;
-                let slice_ty = self
-                    .check_array_pat_len(span, slice, len, min)
-                    .map_or(err, |len| self.tcx.mk_array(inner_ty, len));
-                (inner_ty, slice_ty, expected)
+                let (slice_ty, expected) =
+                    self.check_array_pat_len(span, element_ty, expected, slice, len, min);
+                (element_ty, slice_ty, expected)
             }
-            ty::Slice(inner_ty) => (inner_ty, expected, expected),
+            ty::Slice(element_ty) => (element_ty, expected, expected),
             // The expected type must be an array or slice, but was neither, so error.
             _ => {
                 if !expected.references_error() {
@@ -1376,7 +1375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Type check all the patterns before `slice`.
         for elt in before {
-            self.check_pat(&elt, inner_ty, def_bm, ti);
+            self.check_pat(&elt, element_ty, def_bm, ti);
         }
         // Type check the `slice`, if present, against its expected type.
         if let Some(slice) = slice {
@@ -1384,22 +1383,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         // Type check the elements after `slice`, if present.
         for elt in after {
-            self.check_pat(&elt, inner_ty, def_bm, ti);
+            self.check_pat(&elt, element_ty, def_bm, ti);
         }
         expected
     }
 
     /// Type check the length of an array pattern.
     ///
-    /// Return the length of the variable length pattern,
-    /// if it exists and there are no errors.
+    /// Returns both the type of the variable length pattern
+    /// (or `tcx.err` in case there is none),
+    /// and the potentially inferred array type.
     fn check_array_pat_len(
         &self,
         span: Span,
+        element_ty: Ty<'tcx>,
+        arr_ty: Ty<'tcx>,
         slice: Option<&'tcx Pat<'tcx>>,
         len: &ty::Const<'tcx>,
         min_len: u64,
-    ) -> Option<u64> {
+    ) -> (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() {
@@ -1409,21 +1411,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if min_len != len {
                     self.error_scrutinee_inconsistent_length(span, min_len, len);
                 }
-            } else if let r @ Some(_) = len.checked_sub(min_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 r;
+                return (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.
                 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len);
             }
+        } else if slice.is_none() {
+            // We have a pattern with a fixed length,
+            // which we can use to infer the length of the array.
+            // 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);
         } else {
-            // No idea what the length is, which happens if we have e.g.,
-            // `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`.
+            // 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);
         }
-        None
+        (self.tcx.types.err, arr_ty)
     }
 
     fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {
diff --git a/src/test/ui/const-generics/infer_arg_from_pat.rs b/src/test/ui/const-generics/infer_arg_from_pat.rs
new file mode 100644
index 00000000000..a4e3d3dee4a
--- /dev/null
+++ b/src/test/ui/const-generics/infer_arg_from_pat.rs
@@ -0,0 +1,27 @@
+// run-pass
+//
+// see issue #70529
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct A<const N: usize> {
+    arr: [u8; N],
+}
+
+impl<const N: usize> A<N> {
+    fn new() -> Self {
+        A {
+            arr: [0; N],
+        }
+    }
+
+    fn value(&self) -> usize {
+        N
+    }
+}
+
+fn main() {
+    let a = A::new();
+    let [_, _] = a.arr;
+    assert_eq!(a.value(), 2);
+}
diff --git a/src/test/ui/const-generics/infer_arg_from_pat.stderr b/src/test/ui/const-generics/infer_arg_from_pat.stderr
new file mode 100644
index 00000000000..ad6bf3e235a
--- /dev/null
+++ b/src/test/ui/const-generics/infer_arg_from_pat.stderr
@@ -0,0 +1,8 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/infer_arg_from_pat.rs:4:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/const-generics/infer_arr_len_from_pat.rs b/src/test/ui/const-generics/infer_arr_len_from_pat.rs
new file mode 100644
index 00000000000..70633bbb141
--- /dev/null
+++ b/src/test/ui/const-generics/infer_arr_len_from_pat.rs
@@ -0,0 +1,13 @@
+// check-pass
+//
+// see issue #70529
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+fn as_chunks<const N: usize>() -> [u8; N] {
+    loop {}
+}
+
+fn main() {
+    let [_, _] = as_chunks();
+}
diff --git a/src/test/ui/const-generics/infer_arr_len_from_pat.stderr b/src/test/ui/const-generics/infer_arr_len_from_pat.stderr
new file mode 100644
index 00000000000..6f5b601e14c
--- /dev/null
+++ b/src/test/ui/const-generics/infer_arr_len_from_pat.stderr
@@ -0,0 +1,8 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/infer_arr_len_from_pat.rs:4:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/error-codes/E0730.rs b/src/test/ui/error-codes/E0730.rs
index e5048d6e6e3..45fc7e13d17 100644
--- a/src/test/ui/error-codes/E0730.rs
+++ b/src/test/ui/error-codes/E0730.rs
@@ -3,7 +3,7 @@
 
 fn is_123<const N: usize>(x: [u32; N]) -> bool {
     match x {
-        [1, 2, 3] => true, //~ ERROR cannot pattern-match on an array without a fixed length
+        [1, 2, 3] => true, //~ ERROR mismatched types
         _ => false
     }
 }
diff --git a/src/test/ui/error-codes/E0730.stderr b/src/test/ui/error-codes/E0730.stderr
index 9309ee99064..834a3e96870 100644
--- a/src/test/ui/error-codes/E0730.stderr
+++ b/src/test/ui/error-codes/E0730.stderr
@@ -6,12 +6,15 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0730]: cannot pattern-match on an array without a fixed length
+error[E0308]: mismatched types
   --> $DIR/E0730.rs:6:9
    |
 LL |         [1, 2, 3] => true,
-   |         ^^^^^^^^^
+   |         ^^^^^^^^^ expected `3usize`, found `N`
+   |
+   = note: expected array `[u32; 3]`
+              found array `[u32; _]`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0730`.
+For more information about this error, try `rustc --explain E0308`.