diff options
Diffstat (limited to 'tests/ui/or-patterns')
61 files changed, 2978 insertions, 0 deletions
diff --git a/tests/ui/or-patterns/already-bound-name.rs b/tests/ui/or-patterns/already-bound-name.rs new file mode 100644 index 000000000..65c25293d --- /dev/null +++ b/tests/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/tests/ui/or-patterns/already-bound-name.stderr b/tests/ui/or-patterns/already-bound-name.stderr new file mode 100644 index 000000000..368782c1e --- /dev/null +++ b/tests/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/tests/ui/or-patterns/basic-switch.rs b/tests/ui/or-patterns/basic-switch.rs new file mode 100644 index 000000000..674fbc3cc --- /dev/null +++ b/tests/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/tests/ui/or-patterns/basic-switchint.rs b/tests/ui/or-patterns/basic-switchint.rs new file mode 100644 index 000000000..adb902caf --- /dev/null +++ b/tests/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/tests/ui/or-patterns/bindings-runpass-1.rs b/tests/ui/or-patterns/bindings-runpass-1.rs new file mode 100644 index 000000000..3406d5197 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/bindings-runpass-2.rs b/tests/ui/or-patterns/bindings-runpass-2.rs new file mode 100644 index 000000000..5b9bb748c --- /dev/null +++ b/tests/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/tests/ui/or-patterns/box-patterns.rs b/tests/ui/or-patterns/box-patterns.rs new file mode 100644 index 000000000..73051401c --- /dev/null +++ b/tests/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/tests/ui/or-patterns/consistent-bindings.rs b/tests/ui/or-patterns/consistent-bindings.rs new file mode 100644 index 000000000..ecae1d8a2 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/const-fn.rs b/tests/ui/or-patterns/const-fn.rs new file mode 100644 index 000000000..ca512ac71 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.rs new file mode 100644 index 000000000..5999e04e0 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr new file mode 100644 index 000000000..9aa808e6b --- /dev/null +++ b/tests/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/tests/ui/or-patterns/exhaustiveness-pass.rs b/tests/ui/or-patterns/exhaustiveness-pass.rs new file mode 100644 index 000000000..e8c8a0e7b --- /dev/null +++ b/tests/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/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs new file mode 100644 index 000000000..8429799ca --- /dev/null +++ b/tests/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/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr new file mode 100644 index 000000000..3f7d47dcb --- /dev/null +++ b/tests/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/tests/ui/or-patterns/fn-param-wrap-parens.fixed b/tests/ui/or-patterns/fn-param-wrap-parens.fixed new file mode 100644 index 000000000..b9490aaf9 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/fn-param-wrap-parens.rs b/tests/ui/or-patterns/fn-param-wrap-parens.rs new file mode 100644 index 000000000..8e703d274 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/fn-param-wrap-parens.stderr b/tests/ui/or-patterns/fn-param-wrap-parens.stderr new file mode 100644 index 000000000..732702841 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/for-loop.rs b/tests/ui/or-patterns/for-loop.rs new file mode 100644 index 000000000..11b61cb69 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/if-let-while-let.rs b/tests/ui/or-patterns/if-let-while-let.rs new file mode 100644 index 000000000..92a1bb256 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/inconsistent-modes.rs b/tests/ui/or-patterns/inconsistent-modes.rs new file mode 100644 index 000000000..a87a10ce8 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/inconsistent-modes.stderr b/tests/ui/or-patterns/inconsistent-modes.stderr new file mode 100644 index 000000000..f6367ef82 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/inner-or-pat.or3.stderr b/tests/ui/or-patterns/inner-or-pat.or3.stderr new file mode 100644 index 000000000..2236a38c3 --- /dev/null +++ b/tests/ui/or-patterns/inner-or-pat.or3.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/inner-or-pat.rs:38:54 + | +LL | match x { + | - this expression has type `&str` +LL | x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) | + | ^^ expected `str`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/or-patterns/inner-or-pat.or4.stderr b/tests/ui/or-patterns/inner-or-pat.or4.stderr new file mode 100644 index 000000000..058873ff5 --- /dev/null +++ b/tests/ui/or-patterns/inner-or-pat.or4.stderr @@ -0,0 +1,11 @@ +error[E0408]: variable `x` is not bound in all patterns + --> $DIR/inner-or-pat.rs:53:37 + | +LL | (x @ "red" | (x @ "blue" | "red")) => { + | - ^^^^^ pattern doesn't bind `x` + | | + | variable not in all patterns + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0408`. diff --git a/tests/ui/or-patterns/inner-or-pat.rs b/tests/ui/or-patterns/inner-or-pat.rs new file mode 100644 index 000000000..f4cf4b0c1 --- /dev/null +++ b/tests/ui/or-patterns/inner-or-pat.rs @@ -0,0 +1,73 @@ +// revisions: or1 or2 or3 or4 or5 +// [or1] run-pass +// [or2] run-pass +// [or5] run-pass + +#![allow(unreachable_patterns)] +#![allow(unused_variables)] +#![allow(unused_parens)] +#![allow(dead_code)] + + + +fn foo() { + let x = "foo"; + match x { + x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) | + x @ ("black" | "pink") | + x @ ("red" | "blue") => { + } + _ => (), + } +} + +fn bar() { + let x = "foo"; + match x { + x @ ("foo" | "bar") | + (x @ "red" | (x @ "blue" | x @ "red")) => { + } + _ => (), + } +} + +#[cfg(or3)] +fn zot() { + let x = "foo"; + match x { + x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) | + //[or3]~^ ERROR mismatched types + x @ ("black" | "pink") | + x @ ("red" | "blue") => { + } + _ => (), + } +} + + +#[cfg(or4)] +fn hey() { + let x = "foo"; + match x { + x @ ("foo" | "bar") | + (x @ "red" | (x @ "blue" | "red")) => { + //[or4]~^ variable `x` is not bound in all patterns + } + _ => (), + } +} + +fn don() { + enum Foo { + A, + B, + C, + } + + match Foo::A { + | _foo @ (Foo::A | Foo::B) => {} + Foo::C => {} + }; +} + +fn main(){} diff --git a/tests/ui/or-patterns/issue-64879-trailing-before-guard.rs b/tests/ui/or-patterns/issue-64879-trailing-before-guard.rs new file mode 100644 index 000000000..181c77009 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr new file mode 100644 index 000000000..9b827794f --- /dev/null +++ b/tests/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/tests/ui/or-patterns/issue-67514-irrefutable-param.rs b/tests/ui/or-patterns/issue-67514-irrefutable-param.rs new file mode 100644 index 000000000..73931def8 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs b/tests/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs new file mode 100644 index 000000000..7339a7e23 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs new file mode 100644 index 000000000..3538aad5d --- /dev/null +++ b/tests/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/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr new file mode 100644 index 000000000..4adcf4fee --- /dev/null +++ b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -0,0 +1,31 @@ +error[E0005]: refutable pattern in local binding + --> $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/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs new file mode 100644 index 000000000..408ac24f3 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs b/tests/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs new file mode 100644 index 000000000..8a3c640b1 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/let-pattern.rs b/tests/ui/or-patterns/let-pattern.rs new file mode 100644 index 000000000..97207e83e --- /dev/null +++ b/tests/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/tests/ui/or-patterns/macro-pat.rs b/tests/ui/or-patterns/macro-pat.rs new file mode 100644 index 000000000..20d8f84c2 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/mismatched-bindings-async-fn.rs b/tests/ui/or-patterns/mismatched-bindings-async-fn.rs new file mode 100644 index 000000000..d1cb73aaf --- /dev/null +++ b/tests/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/tests/ui/or-patterns/mismatched-bindings-async-fn.stderr b/tests/ui/or-patterns/mismatched-bindings-async-fn.stderr new file mode 100644 index 000000000..81602fffa --- /dev/null +++ b/tests/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/tests/ui/or-patterns/missing-bindings.rs b/tests/ui/or-patterns/missing-bindings.rs new file mode 100644 index 000000000..7c26012c0 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/missing-bindings.stderr b/tests/ui/or-patterns/missing-bindings.stderr new file mode 100644 index 000000000..8fafa275b --- /dev/null +++ b/tests/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/tests/ui/or-patterns/mix-with-wild.rs b/tests/ui/or-patterns/mix-with-wild.rs new file mode 100644 index 000000000..d9911cda1 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/multiple-pattern-typo.rs b/tests/ui/or-patterns/multiple-pattern-typo.rs new file mode 100644 index 000000000..5f2012533 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/multiple-pattern-typo.stderr b/tests/ui/or-patterns/multiple-pattern-typo.stderr new file mode 100644 index 000000000..b0a82b367 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/nested-undelimited-precedence.rs b/tests/ui/or-patterns/nested-undelimited-precedence.rs new file mode 100644 index 000000000..047836203 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/nested-undelimited-precedence.stderr b/tests/ui/or-patterns/nested-undelimited-precedence.stderr new file mode 100644 index 000000000..2e25d8b3e --- /dev/null +++ b/tests/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/tests/ui/or-patterns/or-patterns-binding-type-mismatch.rs b/tests/ui/or-patterns/or-patterns-binding-type-mismatch.rs new file mode 100644 index 000000000..fa470de7f --- /dev/null +++ b/tests/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/tests/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/tests/ui/or-patterns/or-patterns-binding-type-mismatch.stderr new file mode 100644 index 000000000..00ce46c56 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/or-patterns-default-binding-modes.rs b/tests/ui/or-patterns/or-patterns-default-binding-modes.rs new file mode 100644 index 000000000..e56f9ffe2 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs new file mode 100644 index 000000000..a624cbc89 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr new file mode 100644 index 000000000..acc2099bb --- /dev/null +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -0,0 +1,32 @@ +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 + | +note: while trying to match meta-variable `$p:pat` + --> $DIR/or-patterns-syntactic-fail-2018.rs:9:6 + | +LL | ($p:pat) => {}; + | ^^^^^^ + +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 + | +note: while trying to match meta-variable `$p:pat` + --> $DIR/or-patterns-syntactic-fail-2018.rs:9:6 + | +LL | ($p:pat) => {}; + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail.rs new file mode 100644 index 000000000..358e9d034 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr new file mode 100644 index 000000000..10d42b7e3 --- /dev/null +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -0,0 +1,43 @@ +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 trait `BitOr` must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/or-patterns/or-patterns-syntactic-pass-2021.rs b/tests/ui/or-patterns/or-patterns-syntactic-pass-2021.rs new file mode 100644 index 000000000..c0d148d92 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/or-patterns-syntactic-pass.rs b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs new file mode 100644 index 000000000..92750bec8 --- /dev/null +++ b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -0,0 +1,78 @@ +// 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. + //~^ WARN box pattern syntax is experimental + //~| WARN unstable syntax + 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/tests/ui/or-patterns/or-patterns-syntactic-pass.stderr b/tests/ui/or-patterns/or-patterns-syntactic-pass.stderr new file mode 100644 index 000000000..c43fe192a --- /dev/null +++ b/tests/ui/or-patterns/or-patterns-syntactic-pass.stderr @@ -0,0 +1,13 @@ +warning: box pattern syntax is experimental + --> $DIR/or-patterns-syntactic-pass.rs:70:10 + | +LL | let (box 0 | 1); // Unstable; we *can* change the precedence if we want. + | ^^^^^ + | + = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: 1 warning emitted + diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed new file mode 100644 index 000000000..b1cd0a944 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/remove-leading-vert.rs b/tests/ui/or-patterns/remove-leading-vert.rs new file mode 100644 index 000000000..dc12382aa --- /dev/null +++ b/tests/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/tests/ui/or-patterns/remove-leading-vert.stderr b/tests/ui/or-patterns/remove-leading-vert.stderr new file mode 100644 index 000000000..af51c67e1 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/search-via-bindings.rs b/tests/ui/or-patterns/search-via-bindings.rs new file mode 100644 index 000000000..d98606ded --- /dev/null +++ b/tests/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/tests/ui/or-patterns/slice-patterns.rs b/tests/ui/or-patterns/slice-patterns.rs new file mode 100644 index 000000000..ed5eace0b --- /dev/null +++ b/tests/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/tests/ui/or-patterns/struct-like.rs b/tests/ui/or-patterns/struct-like.rs new file mode 100644 index 000000000..7de690d2d --- /dev/null +++ b/tests/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/tests/ui/or-patterns/while-parsing-this-or-pattern.rs b/tests/ui/or-patterns/while-parsing-this-or-pattern.rs new file mode 100644 index 000000000..b9bfb8638 --- /dev/null +++ b/tests/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/tests/ui/or-patterns/while-parsing-this-or-pattern.stderr b/tests/ui/or-patterns/while-parsing-this-or-pattern.stderr new file mode 100644 index 000000000..7ad62ff99 --- /dev/null +++ b/tests/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 + |