about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/build/matches/test.rs8
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs60
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs26
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr33
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-pass.rs40
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-pass.stderr8
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs51
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr80
8 files changed, 291 insertions, 15 deletions
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 07c5d640a32..c893d6f4856 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -84,10 +84,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
+            PatKind::Or { .. } => {
+                self.hir.tcx().sess.span_fatal(
+                    match_pair.pattern.span,
+                    "or-patterns are not fully implemented yet"
+                )
+            }
+
             PatKind::AscribeUserType { .. } |
             PatKind::Array { .. } |
             PatKind::Wild |
-            PatKind::Or { .. } |
             PatKind::Binding { .. } |
             PatKind::Leaf { .. } |
             PatKind::Deref { .. } => {
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 5db567dae29..f2c5bf1bf6d 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -400,6 +400,25 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         self.0.iter().map(|p| *p)
     }
 
+    // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
+    fn expand_or_pat(&self) -> Option<Vec<Self>> {
+        if self.is_empty() {
+            None
+        } else if let PatKind::Or { pats } = &*self.head().kind {
+            Some(
+                pats.iter()
+                    .map(|pat| {
+                        let mut new_patstack = PatStack::from_pattern(pat);
+                        new_patstack.0.extend_from_slice(&self.0[1..]);
+                        new_patstack
+                    })
+                    .collect(),
+            )
+        } else {
+            None
+        }
+    }
+
     /// This computes `D(self)`. See top of the file for explanations.
     fn specialize_wildcard(&self) -> Option<Self> {
         if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
@@ -447,8 +466,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         Matrix(vec![])
     }
 
+    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
     pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
-        self.0.push(row)
+        if let Some(rows) = row.expand_or_pat() {
+            self.0.extend(rows);
+        } else {
+            self.0.push(row);
+        }
     }
 
     /// Iterate over the first component of each row
@@ -472,12 +496,10 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         'a: 'q,
         'p: 'q,
     {
-        Matrix(
-            self.0
-                .iter()
-                .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
-                .collect(),
-        )
+        self.0
+            .iter()
+            .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
+            .collect()
     }
 }
 
@@ -529,7 +551,12 @@ impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
     where
         T: IntoIterator<Item = PatStack<'p, 'tcx>>,
     {
-        Matrix(iter.into_iter().collect())
+        let mut matrix = Matrix::empty();
+        for x in iter {
+            // Using `push` ensures we correctly expand or-patterns.
+            matrix.push(x);
+        }
+        matrix
     }
 }
 
@@ -1602,6 +1629,15 @@ pub fn is_useful<'p, 'a, 'tcx>(
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
+    // If the first pattern is an or-pattern, expand it.
+    if let Some(vs) = v.expand_or_pat() {
+        return vs
+            .into_iter()
+            .map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
+            .find(|result| result.is_useful())
+            .unwrap_or(NotUseful);
+    }
+
     let (ty, span) = matrix
         .heads()
         .map(|r| (r.ty, r.span))
@@ -1813,9 +1849,7 @@ fn pat_constructor<'tcx>(
                 if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
             Some(Slice(Slice { array_len, kind }))
         }
-        PatKind::Or { .. } => {
-            bug!("support for or-patterns has not been fully implemented yet.");
-        }
+        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
     }
 }
 
@@ -2404,9 +2438,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
             _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
         },
 
-        PatKind::Or { .. } => {
-            bug!("support for or-patterns has not been fully implemented yet.");
-        }
+        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
     };
     debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
 
diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
new file mode 100644
index 00000000000..d7c191bb5a2
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
@@ -0,0 +1,26 @@
+#![feature(or_patterns)]
+#![feature(slice_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
+fn main() {
+    // Get the fatal error out of the way
+    match (0u8,) {
+        (0 | _,) => {}
+        //~^ ERROR or-patterns are not fully implemented yet
+    }
+
+    match (0u8, 0u8) {
+        //~^ ERROR non-exhaustive patterns: `(2u8..=std::u8::MAX, _)`
+        (0 | 1, 2 | 3) => {}
+    }
+    match ((0u8,),) {
+        //~^ ERROR non-exhaustive patterns: `((4u8..=std::u8::MAX))`
+        ((0 | 1,) | (2 | 3,),) => {},
+    }
+    match (Some(0u8),) {
+        //~^ ERROR non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))`
+        (None | Some(0 | 1),) => {}
+    }
+}
diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
new file mode 100644
index 00000000000..e6aa157d278
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
@@ -0,0 +1,33 @@
+error[E0004]: non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` not covered
+  --> $DIR/exhaustiveness-non-exhaustive.rs:14:11
+   |
+LL |     match (0u8, 0u8) {
+   |           ^^^^^^^^^^ pattern `(2u8..=std::u8::MAX, _)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `((4u8..=std::u8::MAX))` not covered
+  --> $DIR/exhaustiveness-non-exhaustive.rs:18:11
+   |
+LL |     match ((0u8,),) {
+   |           ^^^^^^^^^ pattern `((4u8..=std::u8::MAX))` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` not covered
+  --> $DIR/exhaustiveness-non-exhaustive.rs:22:11
+   |
+LL |     match (Some(0u8),) {
+   |           ^^^^^^^^^^^^ pattern `(Some(2u8..=std::u8::MAX))` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: or-patterns are not fully implemented yet
+  --> $DIR/exhaustiveness-non-exhaustive.rs:10:10
+   |
+LL |         (0 | _,) => {}
+   |          ^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.rs b/src/test/ui/or-patterns/exhaustiveness-pass.rs
new file mode 100644
index 00000000000..62a851719f9
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-pass.rs
@@ -0,0 +1,40 @@
+#![feature(or_patterns)]
+#![feature(slice_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
+fn main() {
+    // Get the fatal error out of the way
+    match (0u8,) {
+        (0 | _,) => {}
+        //~^ ERROR or-patterns are not fully implemented yet
+    }
+
+    match (0u8,) {
+        (1 | 2,) => {}
+        _ => {}
+    }
+
+    match (0u8,) {
+        (1 | 1,) => {} // FIXME(or_patterns): redundancy not detected for now.
+        _ => {}
+    }
+    match (0u8, 0u8) {
+        (1 | 2, 3 | 4) => {}
+        (1, 2) => {}
+        (2, 1) => {}
+        _ => {}
+    }
+    match (Some(0u8),) {
+        (None | Some(0 | 1),) => {}
+        (Some(2..=255),) => {}
+    }
+    match ((0u8,),) {
+        ((0 | 1,) | (2 | 3,),) => {},
+        ((_,),) => {},
+    }
+    match (&[0u8][..],) {
+        ([] | [0 | 1..=255] | [_, ..],) => {},
+    }
+}
diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.stderr b/src/test/ui/or-patterns/exhaustiveness-pass.stderr
new file mode 100644
index 00000000000..1f4278c4b80
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-pass.stderr
@@ -0,0 +1,8 @@
+error: or-patterns are not fully implemented yet
+  --> $DIR/exhaustiveness-pass.rs:10:10
+   |
+LL |         (0 | _,) => {}
+   |          ^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
new file mode 100644
index 00000000000..2cd8ca2dbac
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -0,0 +1,51 @@
+#![feature(or_patterns)]
+#![feature(slice_patterns)]
+#![allow(incomplete_features)]
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
+fn main() {
+    // Get the fatal error out of the way
+    match (0u8,) {
+        (0 | _,) => {}
+        //~^ ERROR or-patterns are not fully implemented yet
+    }
+
+    match (0u8,) {
+        (1 | 2,) => {}
+        (1,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (0u8,) {
+        (1 | 2,) => {}
+        (2,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (0u8,) {
+        (1,) => {}
+        (2,) => {}
+        (1 | 2,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (0u8, 0u8) {
+        (1 | 2, 3 | 4) => {}
+        (1, 3) => {} //~ ERROR unreachable pattern
+        (1, 4) => {} //~ ERROR unreachable pattern
+        (2, 4) => {} //~ ERROR unreachable pattern
+        (2 | 1, 4) => {} //~ ERROR unreachable pattern
+        (1, 5 | 6) => {}
+        (1, 4 | 5) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match (Some(0u8),) {
+        (None | Some(1 | 2),) => {}
+        (Some(1),) => {} //~ ERROR unreachable pattern
+        (None,) => {} //~ ERROR unreachable pattern
+        _ => {}
+    }
+    match ((0u8,),) {
+        ((1 | 2,) | (3 | 4,),) => {},
+        ((1..=4,),) => {}, //~ ERROR unreachable pattern
+        _ => {},
+    }
+}
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
new file mode 100644
index 00000000000..a4d55d805c3
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -0,0 +1,80 @@
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:16:9
+   |
+LL |         (1,) => {}
+   |         ^^^^
+   |
+note: lint level defined here
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:4:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:21:9
+   |
+LL |         (2,) => {}
+   |         ^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
+   |
+LL |         (1 | 2,) => {}
+   |         ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:32:9
+   |
+LL |         (1, 3) => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:33:9
+   |
+LL |         (1, 4) => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:34:9
+   |
+LL |         (2, 4) => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:35:9
+   |
+LL |         (2 | 1, 4) => {}
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
+   |
+LL |         (1, 4 | 5) => {}
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
+   |
+LL |         (Some(1),) => {}
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
+   |
+LL |         (None,) => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:48:9
+   |
+LL |         ((1..=4,),) => {},
+   |         ^^^^^^^^^^^
+
+error: or-patterns are not fully implemented yet
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:10:10
+   |
+LL |         (0 | _,) => {}
+   |          ^^^^^
+
+error: aborting due to 12 previous errors
+