summaryrefslogtreecommitdiffstats
path: root/src/test/ui/or-patterns
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/or-patterns')
-rw-r--r--src/test/ui/or-patterns/already-bound-name.rs43
-rw-r--r--src/test/ui/or-patterns/already-bound-name.stderr101
-rw-r--r--src/test/ui/or-patterns/basic-switch.rs31
-rw-r--r--src/test/ui/or-patterns/basic-switchint.rs52
-rw-r--r--src/test/ui/or-patterns/bindings-runpass-1.rs23
-rw-r--r--src/test/ui/or-patterns/bindings-runpass-2.rs30
-rw-r--r--src/test/ui/or-patterns/box-patterns.rs36
-rw-r--r--src/test/ui/or-patterns/consistent-bindings.rs39
-rw-r--r--src/test/ui/or-patterns/const-fn.rs29
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs17
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr42
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-pass.rs38
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs152
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr170
-rw-r--r--src/test/ui/or-patterns/fn-param-wrap-parens.fixed13
-rw-r--r--src/test/ui/or-patterns/fn-param-wrap-parens.rs13
-rw-r--r--src/test/ui/or-patterns/fn-param-wrap-parens.stderr8
-rw-r--r--src/test/ui/or-patterns/for-loop.rs16
-rw-r--r--src/test/ui/or-patterns/if-let-while-let.rs20
-rw-r--r--src/test/ui/or-patterns/inconsistent-modes.rs25
-rw-r--r--src/test/ui/or-patterns/inconsistent-modes.stderr80
-rw-r--r--src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs15
-rw-r--r--src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr19
-rw-r--r--src/test/ui/or-patterns/issue-67514-irrefutable-param.rs9
-rw-r--r--src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs12
-rw-r--r--src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs7
-rw-r--r--src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr31
-rw-r--r--src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs7
-rw-r--r--src/test/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs21
-rw-r--r--src/test/ui/or-patterns/let-pattern.rs17
-rw-r--r--src/test/ui/or-patterns/macro-pat.rs41
-rw-r--r--src/test/ui/or-patterns/mismatched-bindings-async-fn.rs14
-rw-r--r--src/test/ui/or-patterns/mismatched-bindings-async-fn.stderr35
-rw-r--r--src/test/ui/or-patterns/missing-bindings.rs81
-rw-r--r--src/test/ui/or-patterns/missing-bindings.stderr242
-rw-r--r--src/test/ui/or-patterns/mix-with-wild.rs18
-rw-r--r--src/test/ui/or-patterns/multiple-pattern-typo.rs44
-rw-r--r--src/test/ui/or-patterns/multiple-pattern-typo.stderr56
-rw-r--r--src/test/ui/or-patterns/nested-undelimited-precedence.rs44
-rw-r--r--src/test/ui/or-patterns/nested-undelimited-precedence.stderr86
-rw-r--r--src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs66
-rw-r--r--src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr257
-rw-r--r--src/test/ui/or-patterns/or-patterns-default-binding-modes.rs131
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs13
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr20
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail.rs30
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr46
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs12
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-pass.rs76
-rw-r--r--src/test/ui/or-patterns/remove-leading-vert.fixed48
-rw-r--r--src/test/ui/or-patterns/remove-leading-vert.rs48
-rw-r--r--src/test/ui/or-patterns/remove-leading-vert.stderr162
-rw-r--r--src/test/ui/or-patterns/search-via-bindings.rs63
-rw-r--r--src/test/ui/or-patterns/slice-patterns.rs51
-rw-r--r--src/test/ui/or-patterns/struct-like.rs40
-rw-r--r--src/test/ui/or-patterns/while-parsing-this-or-pattern.rs9
-rw-r--r--src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr10
57 files changed, 2859 insertions, 0 deletions
diff --git a/src/test/ui/or-patterns/already-bound-name.rs b/src/test/ui/or-patterns/already-bound-name.rs
new file mode 100644
index 000000000..65c25293d
--- /dev/null
+++ b/src/test/ui/or-patterns/already-bound-name.rs
@@ -0,0 +1,43 @@
+// This test ensures that the "already bound identifier in a product pattern"
+// correctly accounts for or-patterns.
+
+enum E<T> { A(T, T), B(T) }
+
+use E::*;
+
+fn main() {
+ let (a, a) = (0, 1); // Standard duplication without an or-pattern.
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+
+ let (a, A(a, _) | B(a)) = (0, A(1, 2));
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+
+ let (A(a, _) | B(a), a) = (A(0, 1), 2);
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+
+ let (A(a, a) | B(a)) = A(0, 1);
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+
+ let (B(a) | A(a, a)) = A(0, 1);
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+
+ match A(0, 1) {
+ B(a) | A(a, a) => {} // Let's ensure `match` has no funny business.
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ }
+
+ let (B(A(a, _) | B(a)) | A(a, A(a, _) | B(a))) = B(B(1));
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR mismatched types
+
+ let (B(_) | A(A(a, _) | B(a), A(a, _) | B(a))) = B(B(1));
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR variable `a` is not bound in all patterns
+
+ let (B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a))) = B(B(1));
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+}
diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr
new file mode 100644
index 000000000..368782c1e
--- /dev/null
+++ b/src/test/ui/or-patterns/already-bound-name.stderr
@@ -0,0 +1,101 @@
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:9:13
+ |
+LL | let (a, a) = (0, 1); // Standard duplication without an or-pattern.
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:12:15
+ |
+LL | let (a, A(a, _) | B(a)) = (0, A(1, 2));
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:12:25
+ |
+LL | let (a, A(a, _) | B(a)) = (0, A(1, 2));
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:16:26
+ |
+LL | let (A(a, _) | B(a), a) = (A(0, 1), 2);
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:19:15
+ |
+LL | let (A(a, a) | B(a)) = A(0, 1);
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:22:22
+ |
+LL | let (B(a) | A(a, a)) = A(0, 1);
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:26:21
+ |
+LL | B(a) | A(a, a) => {} // Let's ensure `match` has no funny business.
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:30:37
+ |
+LL | let (B(A(a, _) | B(a)) | A(a, A(a, _) | B(a))) = B(B(1));
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:30:47
+ |
+LL | let (B(A(a, _) | B(a)) | A(a, A(a, _) | B(a))) = B(B(1));
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:35:37
+ |
+LL | let (B(_) | A(A(a, _) | B(a), A(a, _) | B(a))) = B(B(1));
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:35:47
+ |
+LL | let (B(_) | A(A(a, _) | B(a), A(a, _) | B(a))) = B(B(1));
+ | ^ used in a pattern more than once
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/already-bound-name.rs:35:10
+ |
+LL | let (B(_) | A(A(a, _) | B(a), A(a, _) | B(a))) = B(B(1));
+ | ^^^^ pattern doesn't bind `a` - variable not in all patterns
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:40:50
+ |
+LL | let (B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a))) = B(B(1));
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/already-bound-name.rs:40:60
+ |
+LL | let (B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a))) = B(B(1));
+ | ^ used in a pattern more than once
+
+error[E0308]: mismatched types
+ --> $DIR/already-bound-name.rs:30:32
+ |
+LL | let (B(A(a, _) | B(a)) | A(a, A(a, _) | B(a))) = B(B(1));
+ | - ^ ------- this expression has type `E<E<{integer}>>`
+ | | |
+ | | expected integer, found enum `E`
+ | first introduced with type `{integer}` here
+ |
+ = note: expected type `{integer}`
+ found enum `E<{integer}>`
+ = note: a binding must have the same type in all alternatives
+
+error: aborting due to 15 previous errors
+
+Some errors have detailed explanations: E0308, E0408, E0416.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/basic-switch.rs b/src/test/ui/or-patterns/basic-switch.rs
new file mode 100644
index 000000000..674fbc3cc
--- /dev/null
+++ b/src/test/ui/or-patterns/basic-switch.rs
@@ -0,0 +1,31 @@
+// Test basic or-patterns when the target pattern type will be lowered to a
+// `Switch` (an `enum`).
+
+// run-pass
+
+#[derive(Debug)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(x: Option<Test>) -> bool {
+ match x {
+ // most simple case
+ Some(Test::Bar | Test::Qux) => true,
+ // wild case
+ Some(_) => false,
+ // empty case
+ None => false,
+ }
+}
+
+fn main() {
+ assert!(!test(Some(Test::Foo)));
+ assert!(test(Some(Test::Bar)));
+ assert!(!test(Some(Test::Baz)));
+ assert!(test(Some(Test::Qux)));
+ assert!(!test(None))
+}
diff --git a/src/test/ui/or-patterns/basic-switchint.rs b/src/test/ui/or-patterns/basic-switchint.rs
new file mode 100644
index 000000000..adb902caf
--- /dev/null
+++ b/src/test/ui/or-patterns/basic-switchint.rs
@@ -0,0 +1,52 @@
+// Test basic or-patterns when the target pattern type will be lowered to
+// a `SwitchInt`. This will happen when the target type is an integer.
+
+// run-pass
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug)]
+enum Foo {
+ One(usize),
+ Two(usize, usize),
+}
+
+fn test_foo(x: Foo) -> MatchArm {
+ match x {
+ // normal pattern.
+ Foo::One(0) | Foo::One(1) | Foo::One(2) => MatchArm::Arm(0),
+ // most simple or-pattern.
+ Foo::One(42 | 255) => MatchArm::Arm(1),
+ // multiple or-patterns for one structure.
+ Foo::Two(42 | 255, 1024 | 2048) => MatchArm::Arm(2),
+ // mix of pattern types in one or-pattern (range).
+ Foo::One(100 | 110..=120 | 210..=220) => MatchArm::Arm(3),
+ // multiple or-patterns with wild.
+ Foo::Two(0..=10 | 100..=110, 0 | _) => MatchArm::Arm(4),
+ // wild
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ // `Foo` tests.
+ assert_eq!(test_foo(Foo::One(0)), MatchArm::Arm(0));
+ assert_eq!(test_foo(Foo::One(42)), MatchArm::Arm(1));
+ assert_eq!(test_foo(Foo::One(43)), MatchArm::Wild);
+ assert_eq!(test_foo(Foo::One(255)), MatchArm::Arm(1));
+ assert_eq!(test_foo(Foo::One(256)), MatchArm::Wild);
+ assert_eq!(test_foo(Foo::Two(42, 1023)), MatchArm::Wild);
+ assert_eq!(test_foo(Foo::Two(255, 2048)), MatchArm::Arm(2));
+ assert_eq!(test_foo(Foo::One(100)), MatchArm::Arm(3));
+ assert_eq!(test_foo(Foo::One(115)), MatchArm::Arm(3));
+ assert_eq!(test_foo(Foo::One(105)), MatchArm::Wild);
+ assert_eq!(test_foo(Foo::One(215)), MatchArm::Arm(3));
+ assert_eq!(test_foo(Foo::One(121)), MatchArm::Wild);
+ assert_eq!(test_foo(Foo::Two(0, 42)), MatchArm::Arm(4));
+ assert_eq!(test_foo(Foo::Two(100, 0)), MatchArm::Arm(4));
+ assert_eq!(test_foo(Foo::Two(42, 0)), MatchArm::Wild);
+}
diff --git a/src/test/ui/or-patterns/bindings-runpass-1.rs b/src/test/ui/or-patterns/bindings-runpass-1.rs
new file mode 100644
index 000000000..3406d5197
--- /dev/null
+++ b/src/test/ui/or-patterns/bindings-runpass-1.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+fn two_bindings(x: &((bool, bool), u8)) -> u8 {
+ match x {
+ &((true, y) | (y, true), z @ (0 | 4)) => (y as u8) + z,
+ _ => 20,
+ }
+}
+
+fn main() {
+ assert_eq!(two_bindings(&((false, false), 0)), 20);
+ assert_eq!(two_bindings(&((false, true), 0)), 0);
+ assert_eq!(two_bindings(&((true, false), 0)), 0);
+ assert_eq!(two_bindings(&((true, true), 0)), 1);
+ assert_eq!(two_bindings(&((false, false), 4)), 20);
+ assert_eq!(two_bindings(&((false, true), 4)), 4);
+ assert_eq!(two_bindings(&((true, false), 4)), 4);
+ assert_eq!(two_bindings(&((true, true), 4)), 5);
+ assert_eq!(two_bindings(&((false, false), 3)), 20);
+ assert_eq!(two_bindings(&((false, true), 3)), 20);
+ assert_eq!(two_bindings(&((true, false), 3)), 20);
+ assert_eq!(two_bindings(&((true, true), 3)), 20);
+}
diff --git a/src/test/ui/or-patterns/bindings-runpass-2.rs b/src/test/ui/or-patterns/bindings-runpass-2.rs
new file mode 100644
index 000000000..5b9bb748c
--- /dev/null
+++ b/src/test/ui/or-patterns/bindings-runpass-2.rs
@@ -0,0 +1,30 @@
+// run-pass
+
+fn or_at(x: Result<u32, u32>) -> u32 {
+ match x {
+ Ok(x @ 4) | Err(x @ (6 | 8)) => x,
+ Ok(x @ 1 | x @ 2) => x,
+ Err(x @ (0..=10 | 30..=40)) if x % 2 == 0 => x + 100,
+ Err(x @ 0..=40) => x + 200,
+ _ => 500,
+ }
+}
+
+fn main() {
+ assert_eq!(or_at(Ok(1)), 1);
+ assert_eq!(or_at(Ok(2)), 2);
+ assert_eq!(or_at(Ok(3)), 500);
+ assert_eq!(or_at(Ok(4)), 4);
+ assert_eq!(or_at(Ok(5)), 500);
+ assert_eq!(or_at(Ok(6)), 500);
+ assert_eq!(or_at(Err(1)), 201);
+ assert_eq!(or_at(Err(2)), 102);
+ assert_eq!(or_at(Err(3)), 203);
+ assert_eq!(or_at(Err(4)), 104);
+ assert_eq!(or_at(Err(5)), 205);
+ assert_eq!(or_at(Err(6)), 6);
+ assert_eq!(or_at(Err(7)), 207);
+ assert_eq!(or_at(Err(8)), 8);
+ assert_eq!(or_at(Err(20)), 220);
+ assert_eq!(or_at(Err(50)), 500);
+}
diff --git a/src/test/ui/or-patterns/box-patterns.rs b/src/test/ui/or-patterns/box-patterns.rs
new file mode 100644
index 000000000..73051401c
--- /dev/null
+++ b/src/test/ui/or-patterns/box-patterns.rs
@@ -0,0 +1,36 @@
+// Test or-patterns with box-patterns
+
+// run-pass
+
+#![feature(box_patterns)]
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(x: Option<Box<Test>>) -> MatchArm {
+ match x {
+ Some(box Test::Foo | box Test::Bar) => MatchArm::Arm(0),
+ Some(box Test::Baz) => MatchArm::Arm(1),
+ Some(_) => MatchArm::Arm(2),
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ assert_eq!(test(Some(Box::new(Test::Foo))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(Test::Bar))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(Test::Baz))), MatchArm::Arm(1));
+ assert_eq!(test(Some(Box::new(Test::Qux))), MatchArm::Arm(2));
+ assert_eq!(test(None), MatchArm::Wild);
+}
diff --git a/src/test/ui/or-patterns/consistent-bindings.rs b/src/test/ui/or-patterns/consistent-bindings.rs
new file mode 100644
index 000000000..ecae1d8a2
--- /dev/null
+++ b/src/test/ui/or-patterns/consistent-bindings.rs
@@ -0,0 +1,39 @@
+// Check that or-patterns with consistent bindings across arms are allowed.
+
+// edition:2018
+
+// check-pass
+
+fn main() {
+ // One level:
+ let (Ok(a) | Err(a)) = Ok(0);
+ let (Ok(ref a) | Err(ref a)) = Ok(0);
+ let (Ok(ref mut a) | Err(ref mut a)) = Ok(0);
+
+ // Two levels:
+ enum Tri<S, T, U> {
+ V1(S),
+ V2(T),
+ V3(U),
+ }
+ use Tri::*;
+
+ let (Ok((V1(a) | V2(a) | V3(a), b)) | Err(Ok((a, b)) | Err((a, b)))): Result<_, Result<_, _>> =
+ Ok((V1(1), 1));
+
+ let (Ok((V1(a) | V2(a) | V3(a), ref b)) | Err(Ok((a, ref b)) | Err((a, ref b)))): Result<
+ _,
+ Result<_, _>,
+ > = Ok((V1(1), 1));
+
+ // Three levels:
+ let (
+ a,
+ Err((ref mut b, ref c, d))
+ | Ok((
+ Ok(V1((ref c, d)) | V2((d, ref c)) | V3((ref c, Ok((_, d)) | Err((d, _)))))
+ | Err((ref c, d)),
+ ref mut b,
+ )),
+ ): (_, Result<_, _>) = (1, Ok((Ok(V3((1, Ok::<_, (i32, i32)>((1, 1))))), 1)));
+}
diff --git a/src/test/ui/or-patterns/const-fn.rs b/src/test/ui/or-patterns/const-fn.rs
new file mode 100644
index 000000000..ca512ac71
--- /dev/null
+++ b/src/test/ui/or-patterns/const-fn.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+const fn foo((Ok(a) | Err(a)): Result<i32, i32>) {
+ let x = Ok(3);
+ let (Ok(y) | Err(y)) = x;
+}
+
+const X: () = {
+ let x = Ok(3);
+ let (Ok(y) | Err(y)) = x;
+};
+
+static Y: () = {
+ let x = Ok(3);
+ let (Ok(y) | Err(y)) = x;
+};
+
+static mut Z: () = {
+ let x = Ok(3);
+ let (Ok(y) | Err(y)) = x;
+};
+
+fn main() {
+ let _: [(); {
+ let x = Ok(3);
+ let (Ok(y) | Err(y)) = x;
+ 2
+ }];
+}
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 000000000..5999e04e0
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
@@ -0,0 +1,17 @@
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns were special-cased.
+fn main() {
+ match (0u8, 0u8) {
+ //~^ ERROR non-exhaustive patterns: `(2_u8..=u8::MAX, _)`
+ (0 | 1, 2 | 3) => {}
+ }
+ match ((0u8,),) {
+ //~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX))`
+ ((0 | 1,) | (2 | 3,),) => {}
+ }
+ match (Some(0u8),) {
+ //~^ ERROR non-exhaustive patterns: `(Some(2_u8..=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 000000000..9aa808e6b
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
@@ -0,0 +1,42 @@
+error[E0004]: non-exhaustive patterns: `(2_u8..=u8::MAX, _)` not covered
+ --> $DIR/exhaustiveness-non-exhaustive.rs:5:11
+ |
+LL | match (0u8, 0u8) {
+ | ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
+ |
+ = note: the matched value is of type `(u8, u8)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (0 | 1, 2 | 3) => {}
+LL + (2_u8..=u8::MAX, _) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
+ --> $DIR/exhaustiveness-non-exhaustive.rs:9:11
+ |
+LL | match ((0u8,),) {
+ | ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
+ |
+ = note: the matched value is of type `((u8,),)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ ((0 | 1,) | (2 | 3,),) => {}
+LL + ((4_u8..=u8::MAX)) => todo!()
+ |
+
+error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
+ --> $DIR/exhaustiveness-non-exhaustive.rs:13:11
+ |
+LL | match (Some(0u8),) {
+ | ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
+ |
+ = note: the matched value is of type `(Option<u8>,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (None | Some(0 | 1),) => {}
+LL + (Some(2_u8..=u8::MAX)) => todo!()
+ |
+
+error: aborting due to 3 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 000000000..e8c8a0e7b
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-pass.rs
@@ -0,0 +1,38 @@
+#![deny(unreachable_patterns)]
+
+// check-pass
+
+// We wrap patterns in a tuple because top-level or-patterns were special-cased.
+fn main() {
+ match (0,) {
+ (1 | 2,) => {}
+ _ => {}
+ }
+
+ match (0, 0) {
+ (1 | 2, 3 | 4) => {}
+ (1, 2) => {}
+ (3, 1) => {}
+ _ => {}
+ }
+ match (Some(0u8),) {
+ (None | Some(0 | 1),) => {}
+ (Some(2..=255),) => {}
+ }
+ match ((0,),) {
+ ((0 | 1,) | (2 | 3,),) => {}
+ ((_,),) => {}
+ }
+ match (&[0u8][..],) {
+ ([] | [0 | 1..=255] | [_, ..],) => {}
+ }
+
+ match ((0, 0),) {
+ ((0, 0) | (0, 1),) => {}
+ _ => {}
+ }
+ match ((0, 0),) {
+ ((0, 0) | (1, 0),) => {}
+ _ => {}
+ }
+}
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 000000000..8429799ca
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -0,0 +1,152 @@
+#![deny(unreachable_patterns)]
+
+// We wrap patterns in a tuple because top-level or-patterns were special-cased.
+fn main() {
+ 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 (true, true) {
+ (false | true, false | true) => (),
+ }
+ 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
+ _ => {}
+ }
+
+ match (0,) {
+ (1 | 1,) => {} //~ ERROR unreachable
+ _ => {}
+ }
+ match 0 {
+ (0 | 1) | 1 => {} //~ ERROR unreachable
+ _ => {}
+ }
+ match 0 {
+ // We get two errors because recursive or-pattern expansion means we don't notice the two
+ // errors span a whole pattern. This could be better but doesn't matter much
+ 0 | (0 | 0) => {}
+ //~^ ERROR unreachable
+ //~| ERROR unreachable
+ _ => {}
+ }
+ match None {
+ // There is only one error that correctly points to the whole subpattern
+ Some(0) |
+ Some( //~ ERROR unreachable
+ 0 | 0) => {}
+ _ => {}
+ }
+ match [0; 2] {
+ [0
+ | 0 //~ ERROR unreachable
+ , 0
+ | 0] => {} //~ ERROR unreachable
+ _ => {}
+ }
+ match &[][..] {
+ [0] => {}
+ [0, _] => {}
+ [0, _, _] => {}
+ [1, ..] => {}
+ [1 //~ ERROR unreachable
+ | 2, ..] => {}
+ _ => {}
+ }
+ match &[][..] {
+ [true] => {}
+ [true | false, ..] => {}
+ _ => {}
+ }
+ match &[][..] {
+ [false] => {}
+ [true, ..] => {}
+ [true //~ ERROR unreachable
+ | false, ..] => {}
+ _ => {}
+ }
+ match (true, None) {
+ (true, Some(_)) => {}
+ (false, Some(true)) => {}
+ (true | false, None | Some(true //~ ERROR unreachable
+ | false)) => {}
+ }
+ macro_rules! t_or_f {
+ () => {
+ (true //~ ERROR unreachable
+ | false)
+ };
+ }
+ match (true, None) {
+ (true, Some(_)) => {}
+ (false, Some(true)) => {}
+ (true | false, None | Some(t_or_f!())) => {}
+ }
+ match Some(0) {
+ Some(0) => {}
+ Some(0 //~ ERROR unreachable
+ | 1) => {}
+ _ => {}
+ }
+
+ // A subpattern that is only unreachable in one branch is overall reachable.
+ match (true, true) {
+ (true, true) => {}
+ (false | true, false | true) => {}
+ }
+ match (true, true) {
+ (true, true) => {}
+ (false, false) => {}
+ (false | true, false | true) => {}
+ }
+ // https://github.com/rust-lang/rust/issues/76836
+ match None {
+ Some(false) => {}
+ None | Some(true
+ | false) => {} //~ ERROR unreachable
+ }
+
+ // A subpattern that is unreachable in all branches is overall unreachable.
+ match (true, true) {
+ (false, true) => {}
+ (true, true) => {}
+ (false | true, false
+ | true) => {} //~ ERROR unreachable
+ }
+ match (true, true) {
+ (true, false) => {}
+ (true, true) => {}
+ (false
+ | true, //~ ERROR unreachable
+ false | true) => {}
+ }
+}
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 000000000..3f7d47dcb
--- /dev/null
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -0,0 +1,170 @@
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:7:9
+ |
+LL | (1,) => {}
+ | ^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:1:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:12:9
+ |
+LL | (2,) => {}
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:18:9
+ |
+LL | (1 | 2,) => {}
+ | ^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:23:9
+ |
+LL | (1, 3) => {}
+ | ^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
+ |
+LL | (1, 4) => {}
+ | ^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
+ |
+LL | (2, 4) => {}
+ | ^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
+ |
+LL | (2 | 1, 4) => {}
+ | ^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:28:9
+ |
+LL | (1, 4 | 5) => {}
+ | ^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:36:9
+ |
+LL | (Some(1),) => {}
+ | ^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
+ |
+LL | (None,) => {}
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
+ |
+LL | ((1..=4,),) => {}
+ | ^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:47:14
+ |
+LL | (1 | 1,) => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:51:19
+ |
+LL | (0 | 1) | 1 => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:57:14
+ |
+LL | 0 | (0 | 0) => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:57:18
+ |
+LL | 0 | (0 | 0) => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:65:13
+ |
+LL | / Some(
+LL | | 0 | 0) => {}
+ | |______________________^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:71:15
+ |
+LL | | 0
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:73:15
+ |
+LL | | 0] => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:81:10
+ |
+LL | [1
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:93:10
+ |
+LL | [true
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:100:36
+ |
+LL | (true | false, None | Some(true
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:105:14
+ |
+LL | (true
+ | ^^^^
+...
+LL | (true | false, None | Some(t_or_f!())) => {}
+ | --------- in this macro invocation
+ |
+ = note: this error originates in the macro `t_or_f` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:116:14
+ |
+LL | Some(0
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:135:19
+ |
+LL | | false) => {}
+ | ^^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:143:15
+ |
+LL | | true) => {}
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
+ |
+LL | | true,
+ | ^^^^
+
+error: aborting due to 26 previous errors
+
diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.fixed b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed
new file mode 100644
index 000000000..b9490aaf9
--- /dev/null
+++ b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed
@@ -0,0 +1,13 @@
+// Test the suggestion to wrap an or-pattern as a function parameter in parens.
+
+// run-rustfix
+
+#![allow(warnings)]
+
+fn main() {}
+
+enum E { A, B }
+use E::*;
+
+#[cfg(FALSE)]
+fn fun1((A | B): E) {} //~ ERROR top-level or-patterns are not allowed
diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.rs b/src/test/ui/or-patterns/fn-param-wrap-parens.rs
new file mode 100644
index 000000000..8e703d274
--- /dev/null
+++ b/src/test/ui/or-patterns/fn-param-wrap-parens.rs
@@ -0,0 +1,13 @@
+// Test the suggestion to wrap an or-pattern as a function parameter in parens.
+
+// run-rustfix
+
+#![allow(warnings)]
+
+fn main() {}
+
+enum E { A, B }
+use E::*;
+
+#[cfg(FALSE)]
+fn fun1(A | B: E) {} //~ ERROR top-level or-patterns are not allowed
diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.stderr b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr
new file mode 100644
index 000000000..732702841
--- /dev/null
+++ b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr
@@ -0,0 +1,8 @@
+error: top-level or-patterns are not allowed in function parameters
+ --> $DIR/fn-param-wrap-parens.rs:13:9
+ |
+LL | fn fun1(A | B: E) {}
+ | ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/or-patterns/for-loop.rs b/src/test/ui/or-patterns/for-loop.rs
new file mode 100644
index 000000000..11b61cb69
--- /dev/null
+++ b/src/test/ui/or-patterns/for-loop.rs
@@ -0,0 +1,16 @@
+// Check that or patterns are lowered correctly in `for` loops.
+// run-pass
+
+fn main() {
+ let v = vec![Ok(2), Err(3), Ok(5)];
+ let mut w = Vec::new();
+ for &(Ok(i) | Err(i)) in &v {
+ w.push(i);
+ }
+ let mut u = Vec::new();
+ for Ok(i) | Err(i) in v {
+ u.push(i);
+ }
+ assert_eq!(w, [2, 3, 5]);
+ assert_eq!(u, [2, 3, 5]);
+}
diff --git a/src/test/ui/or-patterns/if-let-while-let.rs b/src/test/ui/or-patterns/if-let-while-let.rs
new file mode 100644
index 000000000..92a1bb256
--- /dev/null
+++ b/src/test/ui/or-patterns/if-let-while-let.rs
@@ -0,0 +1,20 @@
+// Check that or patterns are lowered correctly in `if let` and `while let` expressions.
+// run-pass
+
+fn main() {
+ let mut opt = Some(3);
+ let mut w = Vec::new();
+ while let Some(ref mut val @ (3 | 4 | 6)) = opt {
+ w.push(*val);
+ *val += 1;
+ }
+ assert_eq!(w, [3, 4]);
+ if let &(None | Some(6 | 7)) = &opt {
+ unreachable!();
+ }
+ if let Some(x @ (4 | 5 | 6)) = opt {
+ assert_eq!(x, 5);
+ } else {
+ unreachable!();
+ }
+}
diff --git a/src/test/ui/or-patterns/inconsistent-modes.rs b/src/test/ui/or-patterns/inconsistent-modes.rs
new file mode 100644
index 000000000..a87a10ce8
--- /dev/null
+++ b/src/test/ui/or-patterns/inconsistent-modes.rs
@@ -0,0 +1,25 @@
+// This test ensures that or patterns require binding mode consistency across arms.
+
+#![allow(non_camel_case_types)]
+fn main() {
+ // One level:
+ let (Ok(a) | Err(ref a)): Result<&u8, u8> = Ok(&0);
+ //~^ ERROR variable `a` is bound inconsistently
+ let (Ok(ref mut a) | Err(a)): Result<u8, &mut u8> = Ok(0);
+ //~^ ERROR variable `a` is bound inconsistently
+ let (Ok(ref a) | Err(ref mut a)): Result<&u8, &mut u8> = Ok(&0);
+ //~^ ERROR variable `a` is bound inconsistently
+ //~| ERROR mismatched types
+ let (Ok((ref a, b)) | Err((ref mut a, ref b))) = Ok((0, &0));
+ //~^ ERROR variable `a` is bound inconsistently
+ //~| ERROR variable `b` is bound inconsistently
+ //~| ERROR mismatched types
+
+ // Two levels:
+ let (Ok(Ok(a) | Err(a)) | Err(ref a)) = Err(0);
+ //~^ ERROR variable `a` is bound inconsistently
+
+ // Three levels:
+ let (Ok([Ok((Ok(ref a) | Err(a),)) | Err(a)]) | Err(a)) = Err(&1);
+ //~^ ERROR variable `a` is bound inconsistently
+}
diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr
new file mode 100644
index 000000000..f6367ef82
--- /dev/null
+++ b/src/test/ui/or-patterns/inconsistent-modes.stderr
@@ -0,0 +1,80 @@
+error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/inconsistent-modes.rs:6:26
+ |
+LL | let (Ok(a) | Err(ref a)): Result<&u8, u8> = Ok(&0);
+ | - ^ bound in different ways
+ | |
+ | first binding
+
+error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/inconsistent-modes.rs:8:30
+ |
+LL | let (Ok(ref mut a) | Err(a)): Result<u8, &mut u8> = Ok(0);
+ | - ^ bound in different ways
+ | |
+ | first binding
+
+error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/inconsistent-modes.rs:10:34
+ |
+LL | let (Ok(ref a) | Err(ref mut a)): Result<&u8, &mut u8> = Ok(&0);
+ | - first binding ^ bound in different ways
+
+error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/inconsistent-modes.rs:13:40
+ |
+LL | let (Ok((ref a, b)) | Err((ref mut a, ref b))) = Ok((0, &0));
+ | - first binding ^ bound in different ways
+
+error[E0409]: variable `b` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/inconsistent-modes.rs:13:47
+ |
+LL | let (Ok((ref a, b)) | Err((ref mut a, ref b))) = Ok((0, &0));
+ | - first binding ^ bound in different ways
+
+error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/inconsistent-modes.rs:19:39
+ |
+LL | let (Ok(Ok(a) | Err(a)) | Err(ref a)) = Err(0);
+ | - ^ bound in different ways
+ | |
+ | first binding
+
+error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/inconsistent-modes.rs:23:34
+ |
+LL | let (Ok([Ok((Ok(ref a) | Err(a),)) | Err(a)]) | Err(a)) = Err(&1);
+ | - ^ bound in different ways
+ | |
+ | first binding
+
+error[E0308]: mismatched types
+ --> $DIR/inconsistent-modes.rs:10:26
+ |
+LL | let (Ok(ref a) | Err(ref mut a)): Result<&u8, &mut u8> = Ok(&0);
+ | ----- ^^^^^^^^^ -------------------- expected due to this
+ | | |
+ | | types differ in mutability
+ | first introduced with type `&&u8` here
+ |
+ = note: expected reference `&&u8`
+ found mutable reference `&mut &mut u8`
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/inconsistent-modes.rs:13:32
+ |
+LL | let (Ok((ref a, b)) | Err((ref mut a, ref b))) = Ok((0, &0));
+ | ----- ^^^^^^^^^ ----------- this expression has type `Result<({integer}, &{integer}), (_, _)>`
+ | | |
+ | | types differ in mutability
+ | first introduced with type `&{integer}` here
+ |
+ = note: expected reference `&{integer}`
+ found mutable reference `&mut _`
+ = note: a binding must have the same type in all alternatives
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0308, E0409.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs
new file mode 100644
index 000000000..181c77009
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs
@@ -0,0 +1,15 @@
+// In this regression test we check that a trailing `|` in an or-pattern just
+// before the `if` token of a `match` guard will receive parser recovery with
+// an appropriate error message.
+
+enum E { A, B }
+
+fn main() {
+ match E::A {
+ E::A |
+ E::B | //~ ERROR a trailing `|` is not allowed in an or-pattern
+ if true => {
+ let recovery_witness: bool = 0; //~ ERROR mismatched types
+ }
+ }
+}
diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr
new file mode 100644
index 000000000..9b827794f
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr
@@ -0,0 +1,19 @@
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/issue-64879-trailing-before-guard.rs:10:14
+ |
+LL | E::A |
+ | ---- while parsing this or-pattern starting here
+LL | E::B |
+ | ^ help: remove the `|`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-64879-trailing-before-guard.rs:12:42
+ |
+LL | let recovery_witness: bool = 0;
+ | ---- ^ expected `bool`, found integer
+ | |
+ | expected due to this
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs b/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs
new file mode 100644
index 000000000..73931def8
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs
@@ -0,0 +1,9 @@
+// Check that we don't ICE for irrefutable or-patterns in function parameters
+
+// check-pass
+
+fn foo((Some(_) | None): Option<u32>) {}
+
+fn main() {
+ foo(None);
+}
diff --git a/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs b/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs
new file mode 100644
index 000000000..7339a7e23
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+enum MyEnum {
+ FirstCase(u8),
+ OtherCase(u16),
+}
+
+fn my_fn(x @ (MyEnum::FirstCase(_) | MyEnum::OtherCase(_)): MyEnum) {}
+
+fn main() {
+ my_fn(MyEnum::FirstCase(0));
+}
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs
new file mode 100644
index 000000000..3538aad5d
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs
@@ -0,0 +1,7 @@
+fn main() {
+ let (0 | (1 | 2)) = 0; //~ ERROR refutable pattern in local binding
+ match 0 {
+ //~^ ERROR non-exhaustive patterns
+ 0 | (1 | 2) => {}
+ }
+}
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
new file mode 100644
index 000000000..95b22ac05
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
@@ -0,0 +1,31 @@
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+ --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:2:10
+ |
+LL | let (0 | (1 | 2)) = 0;
+ | ^^^^^^^^^^^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+ |
+ = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+ = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ = note: the matched value is of type `i32`
+help: you might want to use `if let` to ignore the variants that aren't matched
+ |
+LL | if let (0 | (1 | 2)) = 0 { todo!() }
+ | ++ ~~~~~~~~~~~
+
+error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+ --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11
+ |
+LL | match 0 {
+ | ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+ |
+ = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ 0 | (1 | 2) => {}
+LL + i32::MIN..=-1_i32 | 3_i32..=i32::MAX => todo!()
+ |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0004, E0005.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs
new file mode 100644
index 000000000..408ac24f3
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+fn main() {
+ let (0 | (1 | _)) = 0;
+ if let 0 | (1 | 2) = 0 {}
+ if let x @ 0 | x @ (1 | 2) = 0 {}
+}
diff --git a/src/test/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs b/src/test/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs
new file mode 100644
index 000000000..8a3c640b1
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+#![deny(unreachable_patterns)]
+
+fn main() {
+ match (3,42) {
+ (a,_) | (_,a) if a > 10 => {println!("{}", a)}
+ _ => ()
+ }
+
+ match Some((3,42)) {
+ Some((a, _)) | Some((_, a)) if a > 10 => {println!("{}", a)}
+ _ => ()
+
+ }
+
+ match Some((3,42)) {
+ Some((a, _) | (_, a)) if a > 10 => {println!("{}", a)}
+ _ => ()
+ }
+}
diff --git a/src/test/ui/or-patterns/let-pattern.rs b/src/test/ui/or-patterns/let-pattern.rs
new file mode 100644
index 000000000..97207e83e
--- /dev/null
+++ b/src/test/ui/or-patterns/let-pattern.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+fn or_pat_let(x: Result<u32, u32>) -> u32 {
+ let (Ok(y) | Err(y)) = x;
+ y
+}
+
+fn or_pat_arg((Ok(y) | Err(y)): Result<u32, u32>) -> u32 {
+ y
+}
+
+fn main() {
+ assert_eq!(or_pat_let(Ok(3)), 3);
+ assert_eq!(or_pat_let(Err(5)), 5);
+ assert_eq!(or_pat_arg(Ok(7)), 7);
+ assert_eq!(or_pat_arg(Err(9)), 9);
+}
diff --git a/src/test/ui/or-patterns/macro-pat.rs b/src/test/ui/or-patterns/macro-pat.rs
new file mode 100644
index 000000000..20d8f84c2
--- /dev/null
+++ b/src/test/ui/or-patterns/macro-pat.rs
@@ -0,0 +1,41 @@
+// run-pass
+// edition:2021
+
+use Foo::*;
+
+#[allow(dead_code)]
+#[derive(Eq, PartialEq, Debug)]
+enum Foo {
+ A(u64),
+ B(u64),
+ C,
+ D,
+}
+
+macro_rules! foo {
+ ($orpat:pat, $val:expr) => {
+ match $val {
+ x @ ($orpat) => x, // leading vert would not be allowed in $orpat
+ _ => B(0xDEADBEEFu64),
+ }
+ };
+}
+
+macro_rules! bar {
+ ($orpat:pat, $val:expr) => {
+ match $val {
+ $orpat => 42, // leading vert allowed here
+ _ => 0xDEADBEEFu64,
+ }
+ };
+}
+
+fn main() {
+ // Test or-pattern.
+ let y = foo!(A(_)|B(_), A(32));
+ assert_eq!(y, A(32));
+
+ // Leading vert in or-pattern.
+ let y = bar!(|C| D, C);
+ assert_eq!(y, 42u64);
+}
diff --git a/src/test/ui/or-patterns/mismatched-bindings-async-fn.rs b/src/test/ui/or-patterns/mismatched-bindings-async-fn.rs
new file mode 100644
index 000000000..d1cb73aaf
--- /dev/null
+++ b/src/test/ui/or-patterns/mismatched-bindings-async-fn.rs
@@ -0,0 +1,14 @@
+// Regression test for #71297
+// edition:2018
+
+async fn a((x | s): String) {}
+//~^ ERROR variable `x` is not bound in all patterns
+//~| ERROR variable `s` is not bound in all patterns
+
+async fn b() {
+ let (x | s) = String::new();
+ //~^ ERROR variable `x` is not bound in all patterns
+ //~| ERROR variable `s` is not bound in all patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/or-patterns/mismatched-bindings-async-fn.stderr b/src/test/ui/or-patterns/mismatched-bindings-async-fn.stderr
new file mode 100644
index 000000000..81602fffa
--- /dev/null
+++ b/src/test/ui/or-patterns/mismatched-bindings-async-fn.stderr
@@ -0,0 +1,35 @@
+error[E0408]: variable `s` is not bound in all patterns
+ --> $DIR/mismatched-bindings-async-fn.rs:4:13
+ |
+LL | async fn a((x | s): String) {}
+ | ^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `s`
+
+error[E0408]: variable `x` is not bound in all patterns
+ --> $DIR/mismatched-bindings-async-fn.rs:4:17
+ |
+LL | async fn a((x | s): String) {}
+ | - ^ pattern doesn't bind `x`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `s` is not bound in all patterns
+ --> $DIR/mismatched-bindings-async-fn.rs:9:10
+ |
+LL | let (x | s) = String::new();
+ | ^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `s`
+
+error[E0408]: variable `x` is not bound in all patterns
+ --> $DIR/mismatched-bindings-async-fn.rs:9:14
+ |
+LL | let (x | s) = String::new();
+ | - ^ pattern doesn't bind `x`
+ | |
+ | variable not in all patterns
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0408`.
diff --git a/src/test/ui/or-patterns/missing-bindings.rs b/src/test/ui/or-patterns/missing-bindings.rs
new file mode 100644
index 000000000..7c26012c0
--- /dev/null
+++ b/src/test/ui/or-patterns/missing-bindings.rs
@@ -0,0 +1,81 @@
+// This test ensures that or patterns do not allow missing bindings in any of the arms.
+
+// edition:2018
+
+#![allow(non_camel_case_types)]
+
+fn main() {}
+
+fn check_handling_of_paths() {
+ mod bar {
+ pub enum foo {
+ alpha,
+ beta,
+ charlie
+ }
+ }
+
+ use bar::foo::{alpha, charlie};
+ let (alpha | beta | charlie) = alpha; //~ ERROR variable `beta` is not bound in all patterns
+ match Some(alpha) {
+ Some(alpha | beta) => {} //~ ERROR variable `beta` is not bound in all patterns
+ }
+}
+
+fn check_misc_nesting() {
+ enum E<T> { A(T, T), B(T) }
+ use E::*;
+ enum Vars3<S, T, U> { V1(S), V2(T), V3(U) }
+ use Vars3::*;
+
+ // One level:
+ const X: E<u8> = B(0);
+ let (A(a, _) | _) = X; //~ ERROR variable `a` is not bound in all patterns
+ let (_ | B(a)) = X; //~ ERROR variable `a` is not bound in all patterns
+ let (A(..) | B(a)) = X; //~ ERROR variable `a` is not bound in all patterns
+ let (A(a, _) | B(_)) = X; //~ ERROR variable `a` is not bound in all patterns
+ let (A(_, a) | B(_)) = X; //~ ERROR variable `a` is not bound in all patterns
+ let (A(a, b) | B(a)) = X; //~ ERROR variable `b` is not bound in all patterns
+
+ // Two levels:
+ const Y: E<E<u8>> = B(B(0));
+ let (A(A(..) | B(_), _) | B(a)) = Y; //~ ERROR variable `a` is not bound in all patterns
+ let (A(A(..) | B(a), _) | B(A(a, _) | B(a))) = Y;
+ //~^ ERROR variable `a` is not bound in all patterns
+ let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ //~^ ERROR variable `a` is not bound in all patterns
+ //~| ERROR variable `a` is not bound in all patterns
+ //~| ERROR variable `b` is not bound in all patterns
+ //~| ERROR variable `b` is not bound in all patterns
+ //~| ERROR variable `c` is not bound in all patterns
+ //~| ERROR variable `c` is not bound in all patterns
+ //~| ERROR variable `d` is not bound in all patterns
+ //~| ERROR variable `e` is not bound in all patterns
+
+ // Three levels:
+ let (
+ V1(
+ //~^ ERROR variable `b` is not bound in all patterns
+ //~| ERROR variable `c` is not bound in all patterns
+ A(
+ Ok(a) | Err(_), //~ ERROR variable `a` is not bound in all patterns
+ _
+ ) |
+ B(Ok(a) | Err(a))
+ ) |
+ V2(
+ A(
+ A(_, a) | //~ ERROR variable `b` is not bound in all patterns
+ B(b), //~ ERROR variable `a` is not bound in all patterns
+ _
+ ) |
+ B(_)
+ //~^ ERROR variable `a` is not bound in all patterns
+ //~| ERROR variable `b` is not bound in all patterns
+ ) |
+ V3(c),
+ //~^ ERROR variable `a` is not bound in all patterns
+ )
+ : (Vars3<E<Result<u8, u8>>, E<E<u8>>, u8>,)
+ = (V3(0),);
+}
diff --git a/src/test/ui/or-patterns/missing-bindings.stderr b/src/test/ui/or-patterns/missing-bindings.stderr
new file mode 100644
index 000000000..8fafa275b
--- /dev/null
+++ b/src/test/ui/or-patterns/missing-bindings.stderr
@@ -0,0 +1,242 @@
+error[E0408]: variable `beta` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:19:10
+ |
+LL | let (alpha | beta | charlie) = alpha;
+ | ^^^^^ ---- ^^^^^^^ pattern doesn't bind `beta`
+ | | |
+ | | variable not in all patterns
+ | pattern doesn't bind `beta`
+
+error[E0408]: variable `beta` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:21:14
+ |
+LL | Some(alpha | beta) => {}
+ | ^^^^^ ---- variable not in all patterns
+ | |
+ | pattern doesn't bind `beta`
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:33:20
+ |
+LL | let (A(a, _) | _) = X;
+ | - ^ pattern doesn't bind `a`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:34:10
+ |
+LL | let (_ | B(a)) = X;
+ | ^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `a`
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:35:10
+ |
+LL | let (A(..) | B(a)) = X;
+ | ^^^^^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `a`
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:36:20
+ |
+LL | let (A(a, _) | B(_)) = X;
+ | - ^^^^ pattern doesn't bind `a`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:37:20
+ |
+LL | let (A(_, a) | B(_)) = X;
+ | - ^^^^ pattern doesn't bind `a`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `b` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:38:20
+ |
+LL | let (A(a, b) | B(a)) = X;
+ | - ^^^^ pattern doesn't bind `b`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:42:10
+ |
+LL | let (A(A(..) | B(_), _) | B(a)) = Y;
+ | ^^^^^^^^^^^^^^^^^^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `a`
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:43:12
+ |
+LL | let (A(A(..) | B(a), _) | B(A(a, _) | B(a))) = Y;
+ | ^^^^^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `a`
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:22
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | - ^^^^ pattern doesn't bind `a`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `b` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:22
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | - ^^^^ pattern doesn't bind `b`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `c` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:12
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | ^^^^^^^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `c`
+
+error[E0408]: variable `d` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:33
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | - ^^^^ pattern doesn't bind `d`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `e` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:10
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | ^^^^^^^^^^^^^^^^^^^^ - variable not in all patterns
+ | |
+ | pattern doesn't bind `e`
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:33
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | - ^^^^ pattern doesn't bind `a`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `b` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:33
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | - ^^^^ pattern doesn't bind `b`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `c` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:45:33
+ |
+LL | let (A(A(a, b) | B(c), d) | B(e)) = Y;
+ | - ^^^^ pattern doesn't bind `c`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:61:29
+ |
+LL | Ok(a) | Err(_),
+ | - ^^^^^^ pattern doesn't bind `a`
+ | |
+ | variable not in all patterns
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:69:21
+ |
+LL | A(_, a) |
+ | - variable not in all patterns
+LL | B(b),
+ | ^^^^ pattern doesn't bind `a`
+
+error[E0408]: variable `b` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:68:21
+ |
+LL | A(_, a) |
+ | ^^^^^^^ pattern doesn't bind `b`
+LL | B(b),
+ | - variable not in all patterns
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:72:17
+ |
+LL | A(_, a) |
+ | - variable not in all patterns
+...
+LL | B(_)
+ | ^^^^ pattern doesn't bind `a`
+
+error[E0408]: variable `b` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:72:17
+ |
+LL | B(b),
+ | - variable not in all patterns
+...
+LL | B(_)
+ | ^^^^ pattern doesn't bind `b`
+
+error[E0408]: variable `a` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:76:13
+ |
+LL | B(Ok(a) | Err(a))
+ | - variable not in all patterns
+...
+LL | A(_, a) |
+ | - variable not in all patterns
+...
+LL | V3(c),
+ | ^^^^^ pattern doesn't bind `a`
+
+error[E0408]: variable `b` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:57:13
+ |
+LL | / V1(
+LL | |
+LL | |
+LL | | A(
+... |
+LL | | B(Ok(a) | Err(a))
+LL | | ) |
+ | |_____________^ pattern doesn't bind `b`
+...
+LL | B(b),
+ | - variable not in all patterns
+...
+LL | V3(c),
+ | ^^^^^ pattern doesn't bind `b`
+
+error[E0408]: variable `c` is not bound in all patterns
+ --> $DIR/missing-bindings.rs:57:13
+ |
+LL | / V1(
+LL | |
+LL | |
+LL | | A(
+... |
+LL | | B(Ok(a) | Err(a))
+LL | | ) |
+ | |_____________^ pattern doesn't bind `c`
+LL | / V2(
+LL | | A(
+LL | | A(_, a) |
+LL | | B(b),
+... |
+LL | |
+LL | | ) |
+ | |_____________^ pattern doesn't bind `c`
+LL | V3(c),
+ | - variable not in all patterns
+
+error: aborting due to 26 previous errors
+
+For more information about this error, try `rustc --explain E0408`.
diff --git a/src/test/ui/or-patterns/mix-with-wild.rs b/src/test/ui/or-patterns/mix-with-wild.rs
new file mode 100644
index 000000000..d9911cda1
--- /dev/null
+++ b/src/test/ui/or-patterns/mix-with-wild.rs
@@ -0,0 +1,18 @@
+// Test that an or-pattern works with a wild pattern. This tests two things:
+//
+// 1) The Wild pattern should cause the pattern to always succeed.
+// 2) or-patterns should work with simplifyable patterns.
+
+// run-pass
+
+pub fn test(x: Option<usize>) -> bool {
+ match x {
+ Some(0 | _) => true,
+ _ => false,
+ }
+}
+
+fn main() {
+ assert!(test(Some(42)));
+ assert!(!test(None));
+}
diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs
new file mode 100644
index 000000000..5f2012533
--- /dev/null
+++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs
@@ -0,0 +1,44 @@
+//! Test for `||` in or-patterns
+
+fn main() {
+ let x = 3;
+
+ match x {
+ 1 | 2 || 3 => (), //~ ERROR unexpected token `||` in pattern
+ _ => (),
+ }
+
+ match x {
+ (1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern
+ _ => (),
+ }
+
+ match (x,) {
+ (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` in pattern
+ _ => (),
+ }
+
+ struct TS(u8);
+
+ match TS(x) {
+ TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` in pattern
+ _ => (),
+ }
+
+ struct NS { f: u8 }
+
+ match (NS { f: x }) {
+ NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` in pattern
+ _ => (),
+ }
+
+ match [x] {
+ [1 | 2 || 3] => (), //~ ERROR unexpected token `||` in pattern
+ _ => (),
+ }
+
+ match x {
+ || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` in pattern
+ _ => (),
+ }
+}
diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr
new file mode 100644
index 000000000..b0a82b367
--- /dev/null
+++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr
@@ -0,0 +1,56 @@
+error: unexpected token `||` in pattern
+ --> $DIR/multiple-pattern-typo.rs:7:15
+ |
+LL | 1 | 2 || 3 => (),
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: unexpected token `||` in pattern
+ --> $DIR/multiple-pattern-typo.rs:12:16
+ |
+LL | (1 | 2 || 3) => (),
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: unexpected token `||` in pattern
+ --> $DIR/multiple-pattern-typo.rs:17:16
+ |
+LL | (1 | 2 || 3,) => (),
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: unexpected token `||` in pattern
+ --> $DIR/multiple-pattern-typo.rs:24:18
+ |
+LL | TS(1 | 2 || 3) => (),
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: unexpected token `||` in pattern
+ --> $DIR/multiple-pattern-typo.rs:31:23
+ |
+LL | NS { f: 1 | 2 || 3 } => (),
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: unexpected token `||` in pattern
+ --> $DIR/multiple-pattern-typo.rs:36:16
+ |
+LL | [1 | 2 || 3] => (),
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: unexpected token `||` in pattern
+ --> $DIR/multiple-pattern-typo.rs:41:9
+ |
+LL | || 1 | 2 | 3 => (),
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/or-patterns/nested-undelimited-precedence.rs b/src/test/ui/or-patterns/nested-undelimited-precedence.rs
new file mode 100644
index 000000000..047836203
--- /dev/null
+++ b/src/test/ui/or-patterns/nested-undelimited-precedence.rs
@@ -0,0 +1,44 @@
+// This test tests the precedence of `|` (or-patterns) undelimited nested patterns. In particular,
+// we want to reserve the syntactic space of a pattern followed by a type annotation for possible
+// future type ascription, so we need to make sure that any time a pattern is followed by type
+// annotation (for now), the pattern is not a top-level or-pattern. However, there are also a few
+// types of patterns that allow undelimited subpatterns that could cause the same ambiguity.
+// Currently, those should be impossible due to precedence rule. This test enforces that.
+
+enum E {
+ A,
+ B,
+}
+
+fn foo() {
+ use E::*;
+
+ // ok
+ let b @ (A | B): E = A;
+
+ let b @ A | B: E = A; //~ERROR `b` is not bound in all patterns
+ //~^ ERROR top-level or-patterns are not allowed
+}
+
+enum F {
+ A(usize),
+ B(usize),
+}
+
+fn bar() {
+ use F::*;
+
+ // ok
+ let (A(x) | B(x)): F = A(3);
+
+ let &A(_) | B(_): F = A(3); //~ERROR mismatched types
+ //~^ ERROR top-level or-patterns are not allowed
+ let &&A(_) | B(_): F = A(3); //~ERROR mismatched types
+ //~^ ERROR top-level or-patterns are not allowed
+ let &mut A(_) | B(_): F = A(3); //~ERROR mismatched types
+ //~^ ERROR top-level or-patterns are not allowed
+ let &&mut A(_) | B(_): F = A(3); //~ERROR mismatched types
+ //~^ ERROR top-level or-patterns are not allowed
+}
+
+fn main() {}
diff --git a/src/test/ui/or-patterns/nested-undelimited-precedence.stderr b/src/test/ui/or-patterns/nested-undelimited-precedence.stderr
new file mode 100644
index 000000000..2e25d8b3e
--- /dev/null
+++ b/src/test/ui/or-patterns/nested-undelimited-precedence.stderr
@@ -0,0 +1,86 @@
+error: top-level or-patterns are not allowed in `let` bindings
+ --> $DIR/nested-undelimited-precedence.rs:19:9
+ |
+LL | let b @ A | B: E = A;
+ | ^^^^^^^^^ help: wrap the pattern in parentheses: `(b @ A | B)`
+
+error: top-level or-patterns are not allowed in `let` bindings
+ --> $DIR/nested-undelimited-precedence.rs:34:9
+ |
+LL | let &A(_) | B(_): F = A(3);
+ | ^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&A(_) | B(_))`
+
+error: top-level or-patterns are not allowed in `let` bindings
+ --> $DIR/nested-undelimited-precedence.rs:36:9
+ |
+LL | let &&A(_) | B(_): F = A(3);
+ | ^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&A(_) | B(_))`
+
+error: top-level or-patterns are not allowed in `let` bindings
+ --> $DIR/nested-undelimited-precedence.rs:38:9
+ |
+LL | let &mut A(_) | B(_): F = A(3);
+ | ^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&mut A(_) | B(_))`
+
+error: top-level or-patterns are not allowed in `let` bindings
+ --> $DIR/nested-undelimited-precedence.rs:40:9
+ |
+LL | let &&mut A(_) | B(_): F = A(3);
+ | ^^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&mut A(_) | B(_))`
+
+error[E0408]: variable `b` is not bound in all patterns
+ --> $DIR/nested-undelimited-precedence.rs:19:17
+ |
+LL | let b @ A | B: E = A;
+ | - ^ pattern doesn't bind `b`
+ | |
+ | variable not in all patterns
+
+error[E0308]: mismatched types
+ --> $DIR/nested-undelimited-precedence.rs:34:9
+ |
+LL | let &A(_) | B(_): F = A(3);
+ | ^^^^^ - expected due to this
+ | |
+ | expected enum `F`, found reference
+ |
+ = note: expected enum `F`
+ found reference `&_`
+
+error[E0308]: mismatched types
+ --> $DIR/nested-undelimited-precedence.rs:36:9
+ |
+LL | let &&A(_) | B(_): F = A(3);
+ | ^^^^^^ - expected due to this
+ | |
+ | expected enum `F`, found reference
+ |
+ = note: expected enum `F`
+ found reference `&_`
+
+error[E0308]: mismatched types
+ --> $DIR/nested-undelimited-precedence.rs:38:9
+ |
+LL | let &mut A(_) | B(_): F = A(3);
+ | ^^^^^^^^^ - expected due to this
+ | |
+ | expected enum `F`, found `&mut _`
+ |
+ = note: expected enum `F`
+ found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+ --> $DIR/nested-undelimited-precedence.rs:40:9
+ |
+LL | let &&mut A(_) | B(_): F = A(3);
+ | ^^^^^^^^^^ - expected due to this
+ | |
+ | expected enum `F`, found reference
+ |
+ = note: expected enum `F`
+ found reference `&_`
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0308, E0408.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs
new file mode 100644
index 000000000..fa470de7f
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs
@@ -0,0 +1,66 @@
+// Here we test type checking of bindings when combined with or-patterns.
+// Specifically, we ensure that introducing bindings of different types result in type errors.
+
+fn main() {
+ enum Blah {
+ A(isize, isize, usize),
+ B(isize, isize),
+ }
+
+ match Blah::A(1, 1, 2) {
+ Blah::A(_, x, y) | Blah::B(x, y) => {} //~ ERROR mismatched types
+ }
+
+ match Some(Blah::A(1, 1, 2)) {
+ Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} //~ ERROR mismatched types
+ }
+
+ match (0u8, 1u16) {
+ (x, y) | (y, x) => {} //~ ERROR mismatched types
+ //~^ ERROR mismatched types
+ }
+
+ match Some((0u8, Some((1u16, 2u32)))) {
+ Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ _ => {}
+ }
+
+ if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
+ //~^ ERROR mismatched types
+ }
+
+ if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
+ //~^ ERROR mismatched types
+ }
+
+ if let (x, y) | (y, x) = (0u8, 1u16) {
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ }
+
+ if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+ = Some((0u8, Some((1u16, 2u32))))
+ {}
+
+ let (Blah::A(_, x, y) | Blah::B(x, y)) = Blah::A(1, 1, 2);
+ //~^ ERROR mismatched types
+
+ let ((x, y) | (y, x)) = (0u8, 1u16);
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+
+ fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
+ //~^ ERROR mismatched types
+
+ fn f2(((x, y) | (y, x)): (u8, u16)) {}
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+}
diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr
new file mode 100644
index 000000000..00ce46c56
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr
@@ -0,0 +1,257 @@
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:11:39
+ |
+LL | match Blah::A(1, 1, 2) {
+ | ---------------- this expression has type `Blah`
+LL | Blah::A(_, x, y) | Blah::B(x, y) => {}
+ | - ^ expected `usize`, found `isize`
+ | |
+ | first introduced with type `usize` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:15:44
+ |
+LL | match Some(Blah::A(1, 1, 2)) {
+ | ---------------------- this expression has type `Option<Blah>`
+LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {}
+ | - ^ expected `usize`, found `isize`
+ | |
+ | first introduced with type `usize` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:19:19
+ |
+LL | match (0u8, 1u16) {
+ | ----------- this expression has type `(u8, u16)`
+LL | (x, y) | (y, x) => {}
+ | - ^ expected `u16`, found `u8`
+ | |
+ | first introduced with type `u16` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:19:22
+ |
+LL | match (0u8, 1u16) {
+ | ----------- this expression has type `(u8, u16)`
+LL | (x, y) | (y, x) => {}
+ | - ^ expected `u8`, found `u16`
+ | |
+ | first introduced with type `u8` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:24:41
+ |
+LL | match Some((0u8, Some((1u16, 2u32)))) {
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
+ | - ^ expected `u16`, found `u8`
+ | |
+ | first introduced with type `u16` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:24:50
+ |
+LL | match Some((0u8, Some((1u16, 2u32)))) {
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
+ | - ^ expected `u8`, found `u16`
+ | |
+ | first introduced with type `u8` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:24:59
+ |
+LL | match Some((0u8, Some((1u16, 2u32)))) {
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
+ | - ^ expected `u32`, found `u16`
+ | |
+ | first introduced with type `u32` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:24:62
+ |
+LL | match Some((0u8, Some((1u16, 2u32)))) {
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
+ | - first introduced with type `u8` here ^ expected `u8`, found `u32`
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:32:42
+ |
+LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
+ | - ^ ---------------- this expression has type `Blah`
+ | | |
+ | | expected `usize`, found `isize`
+ | first introduced with type `usize` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:36:47
+ |
+LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
+ | - ^ ---------------------- this expression has type `Option<Blah>`
+ | | |
+ | | expected `usize`, found `isize`
+ | first introduced with type `usize` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:40:22
+ |
+LL | if let (x, y) | (y, x) = (0u8, 1u16) {
+ | - ^ ----------- this expression has type `(u8, u16)`
+ | | |
+ | | expected `u16`, found `u8`
+ | first introduced with type `u16` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:40:25
+ |
+LL | if let (x, y) | (y, x) = (0u8, 1u16) {
+ | - ^ ----------- this expression has type `(u8, u16)`
+ | | |
+ | | expected `u8`, found `u16`
+ | first introduced with type `u8` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:45:44
+ |
+LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
+ | - ^ expected `u16`, found `u8`
+ | |
+ | first introduced with type `u16` here
+...
+LL | = Some((0u8, Some((1u16, 2u32))))
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:45:53
+ |
+LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
+ | - ^ expected `u8`, found `u16`
+ | |
+ | first introduced with type `u8` here
+...
+LL | = Some((0u8, Some((1u16, 2u32))))
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:45:62
+ |
+LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
+ | - ^ expected `u32`, found `u16`
+ | |
+ | first introduced with type `u32` here
+...
+LL | = Some((0u8, Some((1u16, 2u32))))
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:45:65
+ |
+LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
+ | - first introduced with type `u8` here ^ expected `u8`, found `u32`
+...
+LL | = Some((0u8, Some((1u16, 2u32))))
+ | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>`
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:53:40
+ |
+LL | let (Blah::A(_, x, y) | Blah::B(x, y)) = Blah::A(1, 1, 2);
+ | - ^ ---------------- this expression has type `Blah`
+ | | |
+ | | expected `usize`, found `isize`
+ | first introduced with type `usize` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:56:20
+ |
+LL | let ((x, y) | (y, x)) = (0u8, 1u16);
+ | - ^ ----------- this expression has type `(u8, u16)`
+ | | |
+ | | expected `u16`, found `u8`
+ | first introduced with type `u16` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:56:23
+ |
+LL | let ((x, y) | (y, x)) = (0u8, 1u16);
+ | - ^ ----------- this expression has type `(u8, u16)`
+ | | |
+ | | expected `u8`, found `u16`
+ | first introduced with type `u8` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:60:42
+ |
+LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
+ | - ^ ---- expected due to this
+ | | |
+ | | expected `usize`, found `isize`
+ | first introduced with type `usize` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:63:22
+ |
+LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
+ | - ^ --------- expected due to this
+ | | |
+ | | expected `u16`, found `u8`
+ | first introduced with type `u16` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error[E0308]: mismatched types
+ --> $DIR/or-patterns-binding-type-mismatch.rs:63:25
+ |
+LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
+ | - ^ --------- expected due to this
+ | | |
+ | | expected `u8`, found `u16`
+ | first introduced with type `u8` here
+ |
+ = note: a binding must have the same type in all alternatives
+
+error: aborting due to 22 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs b/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs
new file mode 100644
index 000000000..e56f9ffe2
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs
@@ -0,0 +1,131 @@
+// Test that or-patterns are pass-through with respect to default binding modes.
+
+// check-pass
+
+#![allow(irrefutable_let_patterns)]
+
+fn main() {
+ // A regression test for a mistake we made at one point:
+ match &1 {
+ e @ &(1..=2) | e @ &(3..=4) => {}
+ _ => {}
+ }
+
+ match &0 {
+ 0 | &1 => {}
+ _ => {}
+ }
+
+ type R<'a> = &'a Result<u8, u8>;
+
+ let res: R<'_> = &Ok(0);
+
+ match res {
+ // Alternatives propagate expected type / binding mode independently.
+ Ok(mut x) | &Err(mut x) => drop::<u8>(x),
+ }
+ match res {
+ &(Ok(x) | Err(x)) => drop::<u8>(x),
+ }
+ match res {
+ Ok(x) | Err(x) => drop::<&u8>(x),
+ }
+ if let Ok(mut x) | &Err(mut x) = res {
+ drop::<u8>(x);
+ }
+ if let &(Ok(x) | Err(x)) = res {
+ drop::<u8>(x);
+ }
+ let (Ok(mut x) | &Err(mut x)) = res;
+ drop::<u8>(x);
+ let &(Ok(x) | Err(x)) = res;
+ drop::<u8>(x);
+ let (Ok(x) | Err(x)) = res;
+ drop::<&u8>(x);
+ for Ok(mut x) | &Err(mut x) in std::iter::once(res) {
+ drop::<u8>(x);
+ }
+ for &(Ok(x) | Err(x)) in std::iter::once(res) {
+ drop::<u8>(x);
+ }
+ for Ok(x) | Err(x) in std::iter::once(res) {
+ drop::<&u8>(x);
+ }
+ fn f1((Ok(mut x) | &Err(mut x)): R<'_>) {
+ drop::<u8>(x);
+ }
+ fn f2(&(Ok(x) | Err(x)): R<'_>) {
+ drop::<u8>(x);
+ }
+ fn f3((Ok(x) | Err(x)): R<'_>) {
+ drop::<&u8>(x);
+ }
+
+ // Wrap inside another type (a product for a simplity with irrefutable contexts).
+ #[derive(Copy, Clone)]
+ struct Wrap<T>(T);
+ let wres = Wrap(res);
+
+ match wres {
+ Wrap(Ok(mut x) | &Err(mut x)) => drop::<u8>(x),
+ }
+ match wres {
+ Wrap(&(Ok(x) | Err(x))) => drop::<u8>(x),
+ }
+ match wres {
+ Wrap(Ok(x) | Err(x)) => drop::<&u8>(x),
+ }
+ if let Wrap(Ok(mut x) | &Err(mut x)) = wres {
+ drop::<u8>(x);
+ }
+ if let Wrap(&(Ok(x) | Err(x))) = wres {
+ drop::<u8>(x);
+ }
+ if let Wrap(Ok(x) | Err(x)) = wres {
+ drop::<&u8>(x);
+ }
+ let Wrap(Ok(mut x) | &Err(mut x)) = wres;
+ drop::<u8>(x);
+ let Wrap(&(Ok(x) | Err(x))) = wres;
+ drop::<u8>(x);
+ let Wrap(Ok(x) | Err(x)) = wres;
+ drop::<&u8>(x);
+ for Wrap(Ok(mut x) | &Err(mut x)) in std::iter::once(wres) {
+ drop::<u8>(x);
+ }
+ for Wrap(&(Ok(x) | Err(x))) in std::iter::once(wres) {
+ drop::<u8>(x);
+ }
+ for Wrap(Ok(x) | Err(x)) in std::iter::once(wres) {
+ drop::<&u8>(x);
+ }
+ fn fw1(Wrap(Ok(mut x) | &Err(mut x)): Wrap<R<'_>>) {
+ drop::<u8>(x);
+ }
+ fn fw2(Wrap(&(Ok(x) | Err(x))): Wrap<R<'_>>) {
+ drop::<u8>(x);
+ }
+ fn fw3(Wrap(Ok(x) | Err(x)): Wrap<R<'_>>) {
+ drop::<&u8>(x);
+ }
+
+ // Nest some more:
+
+ enum Tri<P> {
+ A(P),
+ B(P),
+ C(P),
+ }
+
+ let tri = &Tri::A(&Ok(0));
+ let (Tri::A(Ok(mut x) | Err(mut x))
+ | Tri::B(&Ok(mut x) | Err(mut x))
+ | &Tri::C(Ok(mut x) | Err(mut x))) = tri;
+ drop::<u8>(x);
+
+ match tri {
+ Tri::A(Ok(mut x) | Err(mut x))
+ | Tri::B(&Ok(mut x) | Err(mut x))
+ | &Tri::C(Ok(mut x) | Err(mut x)) => drop::<u8>(x),
+ }
+}
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
new file mode 100644
index 000000000..a624cbc89
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
@@ -0,0 +1,13 @@
+// Test that :pat doesn't accept top-level or-patterns in edition 2018.
+
+// edition:2018
+
+fn main() {}
+
+// Test the `pat` macro fragment parser:
+macro_rules! accept_pat {
+ ($p:pat) => {};
+}
+
+accept_pat!(p | q); //~ ERROR no rules expected the token `|`
+accept_pat!(|p| q); //~ ERROR no rules expected the token `|`
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
new file mode 100644
index 000000000..001c68a97
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
@@ -0,0 +1,20 @@
+error: no rules expected the token `|`
+ --> $DIR/or-patterns-syntactic-fail-2018.rs:12:15
+ |
+LL | macro_rules! accept_pat {
+ | ----------------------- when calling this macro
+...
+LL | accept_pat!(p | q);
+ | ^ no rules expected this token in macro call
+
+error: no rules expected the token `|`
+ --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13
+ |
+LL | macro_rules! accept_pat {
+ | ----------------------- when calling this macro
+...
+LL | accept_pat!(|p| q);
+ | ^ no rules expected this token in macro call
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
new file mode 100644
index 000000000..358e9d034
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
@@ -0,0 +1,30 @@
+// Test some cases where or-patterns may ostensibly be allowed but are in fact not.
+// This is not a semantic test. We only test parsing.
+
+fn main() {}
+
+enum E { A, B }
+use E::*;
+
+fn no_top_level_or_patterns() {
+ // We do *not* allow or-patterns at the top level of lambdas...
+ let _ = |A | B: E| (); //~ ERROR no implementation for `E | ()`
+ // -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`.
+
+ // ...and for now neither do we allow or-patterns at the top level of functions.
+ fn fun1(A | B: E) {}
+ //~^ ERROR top-level or-patterns are not allowed
+
+ fn fun2(| A | B: E) {}
+ //~^ ERROR top-level or-patterns are not allowed
+
+ // We don't allow top-level or-patterns before type annotation in let-statements because we
+ // want to reserve this syntactic space for possible future type ascription.
+ let A | B: E = A;
+ //~^ ERROR top-level or-patterns are not allowed
+
+ let | A | B: E = A;
+ //~^ ERROR top-level or-patterns are not allowed
+
+ let (A | B): E = A; // ok -- wrapped in parens
+}
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
new file mode 100644
index 000000000..920720a4f
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -0,0 +1,46 @@
+error: top-level or-patterns are not allowed in function parameters
+ --> $DIR/or-patterns-syntactic-fail.rs:15:13
+ |
+LL | fn fun1(A | B: E) {}
+ | ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+
+error: top-level or-patterns are not allowed in function parameters
+ --> $DIR/or-patterns-syntactic-fail.rs:18:13
+ |
+LL | fn fun2(| A | B: E) {}
+ | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+
+error: top-level or-patterns are not allowed in `let` bindings
+ --> $DIR/or-patterns-syntactic-fail.rs:23:9
+ |
+LL | let A | B: E = A;
+ | ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+
+error: top-level or-patterns are not allowed in `let` bindings
+ --> $DIR/or-patterns-syntactic-fail.rs:26:9
+ |
+LL | let | A | B: E = A;
+ | ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+
+error[E0369]: no implementation for `E | ()`
+ --> $DIR/or-patterns-syntactic-fail.rs:11:22
+ |
+LL | let _ = |A | B: E| ();
+ | ----^ -- ()
+ | |
+ | E
+ |
+note: an implementation of `BitOr<_>` might be missing for `E`
+ --> $DIR/or-patterns-syntactic-fail.rs:6:1
+ |
+LL | enum E { A, B }
+ | ^^^^^^ must implement `BitOr<_>`
+note: the following trait must be implemented
+ --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
+ |
+LL | pub trait BitOr<Rhs = Self> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs
new file mode 100644
index 000000000..c0d148d92
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs
@@ -0,0 +1,12 @@
+// Tests that :pat in macros in edition 2021 allows top-level or-patterns.
+
+// run-pass
+// edition:2021
+
+macro_rules! accept_pat {
+ ($p:pat) => {};
+}
+
+accept_pat!(p | q);
+
+fn main() {}
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs
new file mode 100644
index 000000000..6f9a631b0
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs
@@ -0,0 +1,76 @@
+// Here we test all the places `|` is *syntactically* allowed.
+// This is not a semantic test. We only test parsing.
+
+// check-pass
+
+fn main() {}
+
+// Test the `pat` macro fragment parser:
+macro_rules! accept_pat {
+ ($p:pat) => {}
+}
+
+accept_pat!((p | q));
+accept_pat!((p | q,));
+accept_pat!(TS(p | q));
+accept_pat!(NS { f: p | q });
+accept_pat!([p | q]);
+
+// Non-macro tests:
+
+#[cfg(FALSE)]
+fn or_patterns() {
+ // Top level of `let`:
+ let (| A | B);
+ let (A | B);
+ let (A | B): u8;
+ let (A | B) = 0;
+ let (A | B): u8 = 0;
+
+ // Top level of `for`:
+ for | A | B in 0 {}
+ for A | B in 0 {}
+
+ // Top level of `while`:
+ while let | A | B = 0 {}
+ while let A | B = 0 {}
+
+ // Top level of `if`:
+ if let | A | B = 0 {}
+ if let A | B = 0 {}
+
+ // Top level of `match` arms:
+ match 0 {
+ | A | B => {},
+ A | B => {},
+ }
+
+ // Functions:
+ fn fun((A | B): _) {}
+
+ // Lambdas:
+ let _ = |(A | B): u8| ();
+
+ // Parenthesis and tuple patterns:
+ let (A | B);
+ let (A | B,);
+
+ // Tuple struct patterns:
+ let A(B | C);
+ let E::V(B | C);
+
+ // Struct patterns:
+ let S { f1: B | C, f2 };
+ let E::V { f1: B | C, f2 };
+
+ // Slice patterns:
+ let [A | B, .. | ..];
+
+ // These bind as `(prefix p) | q` as opposed to `prefix (p | q)`:
+ let (box 0 | 1); // Unstable; we *can* change the precedence if we want.
+ let (&0 | 1);
+ let (&mut 0 | 1);
+ let (x @ 0 | 1);
+ let (ref x @ 0 | 1);
+ let (ref mut x @ 0 | 1);
+}
diff --git a/src/test/ui/or-patterns/remove-leading-vert.fixed b/src/test/ui/or-patterns/remove-leading-vert.fixed
new file mode 100644
index 000000000..b1cd0a944
--- /dev/null
+++ b/src/test/ui/or-patterns/remove-leading-vert.fixed
@@ -0,0 +1,48 @@
+// Test the suggestion to remove a leading, or trailing `|`.
+
+// run-rustfix
+
+#![allow(warnings)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn leading() {
+ fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed
+ fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter
+ let ( | A): E;
+ let ( | A): (E); //~ ERROR unexpected token `||` in pattern
+ let ( | A,): (E,);
+ let [ | A ]: [E; 1];
+ let [ | A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern
+ let TS( | A ): TS;
+ let TS( | A ): TS; //~ ERROR unexpected token `||` in pattern
+ let NS { f: | A }: NS;
+ let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern
+}
+
+#[cfg(FALSE)]
+fn trailing() {
+ let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let ( A | B ): E; //~ ERROR unexpected token `||` in pattern
+ //~^ ERROR a trailing `|` is not allowed in an or-pattern
+ match A {
+ A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+ A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+ A | B => {} //~ ERROR unexpected token `||` in pattern
+ //~^ ERROR a trailing `|` is not allowed in an or-pattern
+ | A | B => {}
+ //~^ ERROR a trailing `|` is not allowed in an or-pattern
+ }
+
+ // These test trailing-vert in `let` bindings, but they also test that we don't emit a
+ // duplicate suggestion that would confuse rustfix.
+
+ let a : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let a = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let a ; //~ ERROR a trailing `|` is not allowed in an or-pattern
+}
diff --git a/src/test/ui/or-patterns/remove-leading-vert.rs b/src/test/ui/or-patterns/remove-leading-vert.rs
new file mode 100644
index 000000000..dc12382aa
--- /dev/null
+++ b/src/test/ui/or-patterns/remove-leading-vert.rs
@@ -0,0 +1,48 @@
+// Test the suggestion to remove a leading, or trailing `|`.
+
+// run-rustfix
+
+#![allow(warnings)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn leading() {
+ fn fun1( | A: E) {} //~ ERROR top-level or-patterns are not allowed
+ fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter
+ let ( | A): E;
+ let ( || A): (E); //~ ERROR unexpected token `||` in pattern
+ let ( | A,): (E,);
+ let [ | A ]: [E; 1];
+ let [ || A ]: [E; 1]; //~ ERROR unexpected token `||` in pattern
+ let TS( | A ): TS;
+ let TS( || A ): TS; //~ ERROR unexpected token `||` in pattern
+ let NS { f: | A }: NS;
+ let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern
+}
+
+#[cfg(FALSE)]
+fn trailing() {
+ let ( A | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let (a |,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let ( A || B | ): E; //~ ERROR unexpected token `||` in pattern
+ //~^ ERROR a trailing `|` is not allowed in an or-pattern
+ match A {
+ A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+ A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+ A || B | => {} //~ ERROR unexpected token `||` in pattern
+ //~^ ERROR a trailing `|` is not allowed in an or-pattern
+ | A | B | => {}
+ //~^ ERROR a trailing `|` is not allowed in an or-pattern
+ }
+
+ // These test trailing-vert in `let` bindings, but they also test that we don't emit a
+ // duplicate suggestion that would confuse rustfix.
+
+ let a | : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let a | = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+ let a | ; //~ ERROR a trailing `|` is not allowed in an or-pattern
+}
diff --git a/src/test/ui/or-patterns/remove-leading-vert.stderr b/src/test/ui/or-patterns/remove-leading-vert.stderr
new file mode 100644
index 000000000..af51c67e1
--- /dev/null
+++ b/src/test/ui/or-patterns/remove-leading-vert.stderr
@@ -0,0 +1,162 @@
+error: top-level or-patterns are not allowed in function parameters
+ --> $DIR/remove-leading-vert.rs:11:14
+ |
+LL | fn fun1( | A: E) {}
+ | ^^^ help: remove the `|`: `A`
+
+error: unexpected `||` before function parameter
+ --> $DIR/remove-leading-vert.rs:12:14
+ |
+LL | fn fun2( || A: E) {}
+ | ^^ help: remove the `||`
+ |
+ = note: alternatives in or-patterns are separated with `|`, not `||`
+
+error: unexpected token `||` in pattern
+ --> $DIR/remove-leading-vert.rs:14:11
+ |
+LL | let ( || A): (E);
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+
+error: unexpected token `||` in pattern
+ --> $DIR/remove-leading-vert.rs:17:11
+ |
+LL | let [ || A ]: [E; 1];
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+
+error: unexpected token `||` in pattern
+ --> $DIR/remove-leading-vert.rs:19:13
+ |
+LL | let TS( || A ): TS;
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+
+error: unexpected token `||` in pattern
+ --> $DIR/remove-leading-vert.rs:21:17
+ |
+LL | let NS { f: || A }: NS;
+ | ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:26:13
+ |
+LL | let ( A | ): E;
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:27:12
+ |
+LL | let (a |,): (E,);
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:28:17
+ |
+LL | let ( A | B | ): E;
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:29:17
+ |
+LL | let [ A | B | ]: [E; 1];
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:30:18
+ |
+LL | let S { f: B | };
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: unexpected token `||` in pattern
+ --> $DIR/remove-leading-vert.rs:31:13
+ |
+LL | let ( A || B | ): E;
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:31:18
+ |
+LL | let ( A || B | ): E;
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:34:11
+ |
+LL | A | => {}
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:35:11
+ |
+LL | A || => {}
+ | - ^^ help: remove the `||`
+ | |
+ | while parsing this or-pattern starting here
+ |
+ = note: alternatives in or-patterns are separated with `|`, not `||`
+
+error: unexpected token `||` in pattern
+ --> $DIR/remove-leading-vert.rs:36:11
+ |
+LL | A || B | => {}
+ | - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:36:16
+ |
+LL | A || B | => {}
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:38:17
+ |
+LL | | A | B | => {}
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:45:11
+ |
+LL | let a | : u8 = 0;
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:46:11
+ |
+LL | let a | = 0;
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+ --> $DIR/remove-leading-vert.rs:47:11
+ |
+LL | let a | ;
+ | - ^ help: remove the `|`
+ | |
+ | while parsing this or-pattern starting here
+
+error: aborting due to 21 previous errors
+
diff --git a/src/test/ui/or-patterns/search-via-bindings.rs b/src/test/ui/or-patterns/search-via-bindings.rs
new file mode 100644
index 000000000..d98606ded
--- /dev/null
+++ b/src/test/ui/or-patterns/search-via-bindings.rs
@@ -0,0 +1,63 @@
+// Check that we expand multiple or-patterns from left to right.
+
+// run-pass
+
+fn search(target: (bool, bool, bool)) -> u32 {
+ let x = ((false, true), (false, true), (false, true));
+ let mut guard_count = 0;
+ match x {
+ ((a, _) | (_, a), (b @ _, _) | (_, b @ _), (c @ false, _) | (_, c @ true))
+ if {
+ guard_count += 1;
+ (a, b, c) == target
+ } =>
+ {
+ guard_count
+ }
+ _ => unreachable!(),
+ }
+}
+
+// Equivalent to the above code, but hopefully easier to understand.
+fn search_old_style(target: (bool, bool, bool)) -> u32 {
+ let x = ((false, true), (false, true), (false, true));
+ let mut guard_count = 0;
+ match x {
+ ((a, _), (b @ _, _), (c @ false, _))
+ | ((a, _), (b @ _, _), (_, c @ true))
+ | ((a, _), (_, b @ _), (c @ false, _))
+ | ((a, _), (_, b @ _), (_, c @ true))
+ | ((_, a), (b @ _, _), (c @ false, _))
+ | ((_, a), (b @ _, _), (_, c @ true))
+ | ((_, a), (_, b @ _), (c @ false, _))
+ | ((_, a), (_, b @ _), (_, c @ true))
+ if {
+ guard_count += 1;
+ (a, b, c) == target
+ } =>
+ {
+ guard_count
+ }
+ _ => unreachable!(),
+ }
+}
+
+fn main() {
+ assert_eq!(search((false, false, false)), 1);
+ assert_eq!(search((false, false, true)), 2);
+ assert_eq!(search((false, true, false)), 3);
+ assert_eq!(search((false, true, true)), 4);
+ assert_eq!(search((true, false, false)), 5);
+ assert_eq!(search((true, false, true)), 6);
+ assert_eq!(search((true, true, false)), 7);
+ assert_eq!(search((true, true, true)), 8);
+
+ assert_eq!(search_old_style((false, false, false)), 1);
+ assert_eq!(search_old_style((false, false, true)), 2);
+ assert_eq!(search_old_style((false, true, false)), 3);
+ assert_eq!(search_old_style((false, true, true)), 4);
+ assert_eq!(search_old_style((true, false, false)), 5);
+ assert_eq!(search_old_style((true, false, true)), 6);
+ assert_eq!(search_old_style((true, true, false)), 7);
+ assert_eq!(search_old_style((true, true, true)), 8);
+}
diff --git a/src/test/ui/or-patterns/slice-patterns.rs b/src/test/ui/or-patterns/slice-patterns.rs
new file mode 100644
index 000000000..ed5eace0b
--- /dev/null
+++ b/src/test/ui/or-patterns/slice-patterns.rs
@@ -0,0 +1,51 @@
+// Test or-patterns with slice-patterns
+
+// run-pass
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(foo: &[Option<Test>]) -> MatchArm {
+ match foo {
+ [.., Some(Test::Qux | Test::Foo)] => MatchArm::Arm(0),
+ [Some(Test::Foo), .., Some(Test::Baz | Test::Bar)] => MatchArm::Arm(1),
+ [.., Some(Test::Bar | Test::Baz), _] => MatchArm::Arm(2),
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ let foo = vec![
+ Some(Test::Foo),
+ Some(Test::Bar),
+ Some(Test::Baz),
+ Some(Test::Qux),
+ ];
+
+ // path 1a
+ assert_eq!(test(&foo), MatchArm::Arm(0));
+ // path 1b
+ assert_eq!(test(&[Some(Test::Bar), Some(Test::Foo)]), MatchArm::Arm(0));
+ // path 2a
+ assert_eq!(test(&foo[..3]), MatchArm::Arm(1));
+ // path 2b
+ assert_eq!(test(&[Some(Test::Foo), Some(Test::Foo), Some(Test::Bar)]), MatchArm::Arm(1));
+ // path 3a
+ assert_eq!(test(&foo[1..3]), MatchArm::Arm(2));
+ // path 3b
+ assert_eq!(test(&[Some(Test::Bar), Some(Test::Baz), Some(Test::Baz), Some(Test::Bar)]),
+ MatchArm::Arm(2));
+ // path 4
+ assert_eq!(test(&foo[4..]), MatchArm::Wild);
+}
diff --git a/src/test/ui/or-patterns/struct-like.rs b/src/test/ui/or-patterns/struct-like.rs
new file mode 100644
index 000000000..7de690d2d
--- /dev/null
+++ b/src/test/ui/or-patterns/struct-like.rs
@@ -0,0 +1,40 @@
+// run-pass
+
+#[derive(Debug)]
+enum Other {
+ One,
+ Two,
+ Three,
+}
+
+#[derive(Debug)]
+enum Test {
+ Foo { first: usize, second: usize },
+ Bar { other: Option<Other> },
+ Baz,
+}
+
+fn test(x: Option<Test>) -> bool {
+ match x {
+ Some(
+ Test::Foo { first: 1024 | 2048, second: 2048 | 4096 }
+ | Test::Bar { other: Some(Other::One | Other::Two) },
+ ) => true,
+ // wild case
+ Some(_) => false,
+ // empty case
+ None => false,
+ }
+}
+
+fn main() {
+ assert!(test(Some(Test::Foo { first: 1024, second: 4096 })));
+ assert!(!test(Some(Test::Foo { first: 2048, second: 8192 })));
+ assert!(!test(Some(Test::Foo { first: 42, second: 2048 })));
+ assert!(test(Some(Test::Bar { other: Some(Other::One) })));
+ assert!(test(Some(Test::Bar { other: Some(Other::Two) })));
+ assert!(!test(Some(Test::Bar { other: Some(Other::Three) })));
+ assert!(!test(Some(Test::Bar { other: None })));
+ assert!(!test(Some(Test::Baz)));
+ assert!(!test(None));
+}
diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs
new file mode 100644
index 000000000..b9bfb8638
--- /dev/null
+++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs
@@ -0,0 +1,9 @@
+// Test the parser for the "while parsing this or-pattern..." label here.
+
+fn main() {
+ match Some(42) {
+ Some(42) | .=. => {} //~ ERROR expected pattern, found `.`
+ //~^ while parsing this or-pattern starting here
+ //~| NOTE expected pattern
+ }
+}
diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr
new file mode 100644
index 000000000..7ad62ff99
--- /dev/null
+++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr
@@ -0,0 +1,10 @@
+error: expected pattern, found `.`
+ --> $DIR/while-parsing-this-or-pattern.rs:5:20
+ |
+LL | Some(42) | .=. => {}
+ | -------- ^ expected pattern
+ | |
+ | while parsing this or-pattern starting here
+
+error: aborting due to previous error
+