about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs23
-rw-r--r--src/test/ui/or-patterns/inner-or-pat.or3.stderr11
-rw-r--r--src/test/ui/or-patterns/inner-or-pat.or4.stderr11
-rw-r--r--src/test/ui/or-patterns/inner-or-pat.rs73
4 files changed, 114 insertions, 4 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 0a660ef30c8..443626d14b9 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -364,8 +364,8 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
 /// works well.
 #[derive(Clone)]
-struct PatStack<'p, 'tcx> {
-    pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
+pub(crate) struct PatStack<'p, 'tcx> {
+    pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
 }
 
 impl<'p, 'tcx> PatStack<'p, 'tcx> {
@@ -403,6 +403,21 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         })
     }
 
+    // Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix.
+    fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) {
+        if !self.is_empty() && self.head().is_or_pat() {
+            for pat in self.head().iter_fields() {
+                let mut new_patstack = PatStack::from_pattern(pat);
+                new_patstack.pats.extend_from_slice(&self.pats[1..]);
+                if !new_patstack.is_empty() && new_patstack.head().is_or_pat() {
+                    new_patstack.expand_and_extend(matrix);
+                } else if !new_patstack.is_empty() {
+                    matrix.push(new_patstack);
+                }
+            }
+        }
+    }
+
     /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations.
     ///
     /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
@@ -436,7 +451,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
 /// A 2D matrix.
 #[derive(Clone)]
 pub(super) struct Matrix<'p, 'tcx> {
-    patterns: Vec<PatStack<'p, 'tcx>>,
+    pub patterns: Vec<PatStack<'p, 'tcx>>,
 }
 
 impl<'p, 'tcx> Matrix<'p, 'tcx> {
@@ -453,7 +468,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
         if !row.is_empty() && row.head().is_or_pat() {
-            self.patterns.extend(row.expand_or_pat());
+            row.expand_and_extend(self);
         } else {
             self.patterns.push(row);
         }
diff --git a/src/test/ui/or-patterns/inner-or-pat.or3.stderr b/src/test/ui/or-patterns/inner-or-pat.or3.stderr
new file mode 100644
index 00000000000..2236a38c37b
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat.or3.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/inner-or-pat.rs:38:54
+   |
+LL |     match x {
+   |           - this expression has type `&str`
+LL |         x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
+   |                                                      ^^ expected `str`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/inner-or-pat.or4.stderr b/src/test/ui/or-patterns/inner-or-pat.or4.stderr
new file mode 100644
index 00000000000..058873ff5ff
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat.or4.stderr
@@ -0,0 +1,11 @@
+error[E0408]: variable `x` is not bound in all patterns
+  --> $DIR/inner-or-pat.rs:53:37
+   |
+LL |         (x @ "red" | (x @ "blue" |  "red")) => {
+   |                       -             ^^^^^ pattern doesn't bind `x`
+   |                       |
+   |                       variable not in all patterns
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0408`.
diff --git a/src/test/ui/or-patterns/inner-or-pat.rs b/src/test/ui/or-patterns/inner-or-pat.rs
new file mode 100644
index 00000000000..f4cf4b0c188
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat.rs
@@ -0,0 +1,73 @@
+// revisions: or1 or2 or3 or4 or5
+// [or1] run-pass
+// [or2] run-pass
+// [or5] run-pass
+
+#![allow(unreachable_patterns)]
+#![allow(unused_variables)]
+#![allow(unused_parens)]
+#![allow(dead_code)]
+
+
+
+fn foo() {
+    let x = "foo";
+    match x {
+        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) |
+        x @ ("black" | "pink") |
+        x @ ("red" | "blue") => {
+        }
+        _ => (),
+    }
+}
+
+fn bar() {
+    let x = "foo";
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" | x @ "red")) => {
+        }
+        _ => (),
+    }
+}
+
+#[cfg(or3)]
+fn zot() {
+    let x = "foo";
+    match x {
+        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
+        //[or3]~^ ERROR mismatched types
+        x @ ("black" | "pink") |
+        x @ ("red" | "blue") => {
+        }
+        _ => (),
+    }
+}
+
+
+#[cfg(or4)]
+fn hey() {
+    let x = "foo";
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" |  "red")) => {
+        //[or4]~^ variable `x` is not bound in all patterns
+        }
+        _ => (),
+    }
+}
+
+fn don() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+
+    match Foo::A {
+        | _foo @ (Foo::A | Foo::B) => {}
+        Foo::C => {}
+    };
+}
+
+fn main(){}