diff options
Diffstat (limited to 'tests/ui/rfcs/rfc-2294-if-let-guard')
29 files changed, 1027 insertions, 0 deletions
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.rs new file mode 100644 index 000000000..1f32e4af1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.rs @@ -0,0 +1,9 @@ +#![feature(if_let_guard)] + +fn main() { + match Some(None) { + Some(x) if let Some(y) = x => (x, y), + _ => y, //~ ERROR cannot find value `y` + } + y //~ ERROR cannot find value `y` +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.stderr new file mode 100644 index 000000000..2463b7f3e --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/bindings.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:6:14 + | +LL | _ => y, + | ^ not found in this scope + +error[E0425]: cannot find value `y` in this scope + --> $DIR/bindings.rs:8:5 + | +LL | y + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/const-expr.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/const-expr.rs new file mode 100644 index 000000000..5c42c0d8b --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/const-expr.rs @@ -0,0 +1,26 @@ +// Ensure if let guards can be used in constant expressions. +// build-pass + +#![feature(if_let_guard)] + +const fn match_if_let(x: Option<i32>, y: Option<i32>) -> i32 { + match x { + None if let Some(a @ 5) = y => a, + Some(z) if let (Some(_), 12) = (y, z) => 2, + _ => 3, + } +} + +const ASSERTS: usize = { + assert!(match_if_let(None, Some(5)) == 5); + assert!(match_if_let(Some(12), Some(3)) == 2); + assert!(match_if_let(None, Some(4)) == 3); + assert!(match_if_let(Some(11), Some(3)) == 3); + assert!(match_if_let(Some(12), None) == 3); + assert!(match_if_let(None, None) == 3); + 0 +}; + +fn main() { + let _: [(); ASSERTS]; +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.rs new file mode 100644 index 000000000..b4eb54139 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.rs @@ -0,0 +1,18 @@ +#![feature(if_let_guard)] +#![allow(irrefutable_let_patterns)] + +fn match_option(x: Option<u32>) { + match x { + //~^ ERROR non-exhaustive patterns: `None` not covered + Some(_) => {} + None if let y = x => {} + } +} + +fn main() { + let x = (); + match x { + //~^ ERROR non-exhaustive patterns: `()` not covered + y if let z = y => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr new file mode 100644 index 000000000..ddd08854f --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: `None` not covered + --> $DIR/exhaustive.rs:5:11 + | +LL | match x { + | ^ pattern `None` not covered + | +note: `Option<u32>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option<u32>` +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 if let y = x => {}, +LL + None => todo!() + | + +error[E0004]: non-exhaustive patterns: `()` not covered + --> $DIR/exhaustive.rs:14:11 + | +LL | match x { + | ^ pattern `()` not covered + | + = note: the matched value is of type `()` + = note: match arms with guards don't count towards exhaustivity +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 ~ y if let z = y => {}, +LL + () => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs new file mode 100644 index 000000000..b8c0eb3e6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -0,0 +1,74 @@ +// gate-test-if_let_guard + +use std::ops::Range; + +fn _if_let_guard() { + match () { + () if let 0 = 1 => {} + //~^ ERROR `if let` guards are experimental + + () if (let 0 = 1) => {} + //~^ ERROR expected expression, found `let` statement + + () if (((let 0 = 1))) => {} + //~^ ERROR expected expression, found `let` statement + + () if true && let 0 = 1 => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + + () if let 0 = 1 && true => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + + () if (let 0 = 1) && true => {} + //~^ ERROR expected expression, found `let` statement + + () if true && (let 0 = 1) => {} + //~^ ERROR expected expression, found `let` statement + + () if (let 0 = 1) && (let 0 = 1) => {} + //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + + () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + + + () if let Range { start: _, end: _ } = (true..true) && false => {} + //~^ ERROR `if let` guards are experimental + //~| ERROR `let` expressions in this position are unstable + + _ => {} + } +} + +fn _macros() { + macro_rules! use_expr { + ($e:expr) => { + match () { + () if $e => {} + _ => {} + } + } + } + use_expr!((let 0 = 1 && 0 == 0)); + //~^ ERROR expected expression, found `let` statement + use_expr!((let 0 = 1)); + //~^ ERROR expected expression, found `let` statement + match () { + #[cfg(FALSE)] + () if let 0 = 1 => {} + //~^ ERROR `if let` guards are experimental + _ => {} + } + use_expr!(let 0 = 1); + //~^ ERROR no rules expected the token `let` +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr new file mode 100644 index 000000000..62534b555 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -0,0 +1,256 @@ +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:13:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:13:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:24:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:24:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:27:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:27:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:30:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:30:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:30:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:30:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:34:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:34:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:34:55 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:34:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:34:68 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/feature-gate.rs:34:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:60:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:62:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: no rules expected the token `let` + --> $DIR/feature-gate.rs:70:15 + | +LL | macro_rules! use_expr { + | --------------------- when calling this macro +... +LL | use_expr!(let 0 = 1); + | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> $DIR/feature-gate.rs:53:10 + | +LL | ($e:expr) => { + | ^^^^^^^ + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:7:12 + | +LL | () if let 0 = 1 => {} + | ^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:16:12 + | +LL | () if true && let 0 = 1 => {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:20:12 + | +LL | () if let 0 = 1 && true => {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:34:12 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:43:12 + | +LL | () if let Range { start: _, end: _ } = (true..true) && false => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `if let` guards are experimental + --> $DIR/feature-gate.rs:66:12 + | +LL | () if let 0 = 1 => {} + | ^^^^^^^^^^^^ + | + = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information + = help: add `#![feature(if_let_guard)]` to the crate attributes to enable + = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:16:23 + | +LL | () if true && let 0 = 1 => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:20:15 + | +LL | () if let 0 = 1 && true => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:34:15 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:34:28 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/feature-gate.rs:43:15 + | +LL | () if let Range { start: _, end: _ } = (true..true) && false => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + +error: aborting due to 23 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-1.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-1.rs new file mode 100644 index 000000000..792225e65 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-1.rs @@ -0,0 +1,15 @@ +// References to by-move bindings in an if-let guard *cannot* be used after the guard. + +#![feature(if_let_guard)] + +fn main() { + let x: Option<Option<String>> = Some(Some(String::new())); + match x { + Some(mut y) if let Some(ref z) = y => { + //~^ ERROR: cannot move out of `x.0` because it is borrowed + let _z: &String = z; + let _y: Option<String> = y; + } + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-1.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-1.stderr new file mode 100644 index 000000000..741ae7c92 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-1.stderr @@ -0,0 +1,15 @@ +error[E0505]: cannot move out of `x.0` because it is borrowed + --> $DIR/guard-lifetime-1.rs:8:14 + | +LL | Some(mut y) if let Some(ref z) = y => { + | ^^^^^ + | | + | move out of `x.0` occurs here + | borrow of `x.0` occurs here +LL | +LL | let _z: &String = z; + | - borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-2.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-2.rs new file mode 100644 index 000000000..aa2154e3e --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-lifetime-2.rs @@ -0,0 +1,16 @@ +// References to by-mutable-ref bindings in an if-let guard *can* be used after the guard. + +// check-pass + +#![feature(if_let_guard)] + +fn main() { + let mut x: Option<Option<String>> = Some(Some(String::new())); + match x { + Some(ref mut y) if let Some(ref z) = *y => { + let _z: &String = z; + let _y: &mut Option<String> = y; + } + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-1.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-1.rs new file mode 100644 index 000000000..9353c9d92 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-1.rs @@ -0,0 +1,14 @@ +// Check mutable bindings cannot be mutated by an if-let guard. + +#![feature(if_let_guard)] + +fn main() { + let x: Option<Option<i32>> = Some(Some(6)); + match x { + Some(mut y) if let Some(ref mut z) = y => { + //~^ ERROR cannot borrow `y.0` as mutable, as it is immutable for the pattern guard + let _: &mut i32 = z; + } + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-1.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-1.stderr new file mode 100644 index 000000000..98285f5c3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-1.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `y.0` as mutable, as it is immutable for the pattern guard + --> $DIR/guard-mutability-1.rs:8:33 + | +LL | Some(mut y) if let Some(ref mut z) = y => { + | ^^^^^^^^^ cannot borrow as mutable + | + = note: variables bound in patterns are immutable until the end of the pattern guard + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.rs new file mode 100644 index 000000000..4efa02f57 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.rs @@ -0,0 +1,14 @@ +// Check mutable reference bindings cannot be mutated by an if-let guard. + +#![feature(if_let_guard)] + +fn main() { + let mut x: Option<Option<i32>> = Some(Some(6)); + match x { + Some(ref mut y) if let Some(ref mut z) = *y => { + //~^ ERROR cannot borrow `y.0` as mutable, as it is immutable for the pattern guard + let _: &mut i32 = z; + } + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.stderr new file mode 100644 index 000000000..31df8a922 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `y.0` as mutable, as it is immutable for the pattern guard + --> $DIR/guard-mutability-2.rs:8:37 + | +LL | Some(ref mut y) if let Some(ref mut z) = *y => { + | ^^^^^^^^^ cannot borrow as mutable + | + = note: variables bound in patterns are immutable until the end of the pattern guard + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs new file mode 100644 index 000000000..423a2cd53 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs @@ -0,0 +1,16 @@ +// Expression macros can't expand to a let match guard. + +#![feature(if_let_guard)] +#![feature(let_chains)] + +macro_rules! m { + ($e:expr) => { let Some(x) = $e } + //~^ ERROR expected expression, found `let` statement +} + +fn main() { + match () { + () if m!(Some(5)) => {} + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr new file mode 100644 index 000000000..b8065b9f5 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr @@ -0,0 +1,14 @@ +error: expected expression, found `let` statement + --> $DIR/macro-expanded.rs:7:20 + | +LL | ($e:expr) => { let Some(x) = $e } + | ^^^ +... +LL | () if m!(Some(5)) => {} + | ----------- in this macro invocation + | + = note: only supported directly in conditions of `if` and `while` expressions + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs new file mode 100644 index 000000000..5c333cd77 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs @@ -0,0 +1,97 @@ +#![feature(if_let_guard)] +#![feature(let_chains)] +#![allow(irrefutable_let_patterns)] + +fn same_pattern(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if let y = x && c => (), + (1, 2) if let z = x => (), //~ ERROR use of moved value: `x` + _ => (), + } +} + +fn same_pattern_ok(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if c && let y = x => (), + (1, 2) if let z = x => (), + _ => (), + } +} + +fn different_patterns(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, _) if let y = x && c => (), + (_, 2) if let z = x => (), //~ ERROR use of moved value: `x` + _ => (), + } +} + +fn different_patterns_ok(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, _) if c && let y = x => (), + (_, 2) if let z = x => (), + _ => (), + } +} + +fn or_pattern(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, _) | (_, 2) if let y = x && c => (), //~ ERROR use of moved value: `x` + _ => (), + } +} + +fn or_pattern_ok(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, _) | (_, 2) if c && let y = x => (), + _ => (), + } +} + +fn use_in_arm(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if let y = x && c => false, + _ => { *x == 1 }, //~ ERROR use of moved value: `x` + }; +} + +fn use_in_arm_ok(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if c && let y = x => false, + _ => { *x == 1 }, + }; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr new file mode 100644 index 000000000..087e54244 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr @@ -0,0 +1,65 @@ +error[E0382]: use of moved value: `x` + --> $DIR/move-guard-if-let-chain.rs:12:23 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (1, 2) if let y = x && c => (), + | - value moved here +LL | (1, 2) if let z = x => (), + | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | (1, 2) if let ref y = x && c => (), + | +++ + +error[E0382]: use of moved value: `x` + --> $DIR/move-guard-if-let-chain.rs:36:23 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (1, _) if let y = x && c => (), + | - value moved here +LL | (_, 2) if let z = x => (), + | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | (1, _) if let ref y = x && c => (), + | +++ + +error[E0382]: use of moved value: `x` + --> $DIR/move-guard-if-let-chain.rs:59:32 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (1, _) | (_, 2) if let y = x && c => (), + | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | (1, _) | (_, 2) if let ref y = x && c => (), + | +++ + +error[E0382]: use of moved value: `x` + --> $DIR/move-guard-if-let-chain.rs:82:16 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (1, 2) if let y = x && c => false, + | - value moved here +LL | _ => { *x == 1 }, + | ^^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | (1, 2) if let ref y = x && c => false, + | +++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let.rs new file mode 100644 index 000000000..071b86e2e --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let.rs @@ -0,0 +1,41 @@ +// Check that borrowck knows that moves in the pattern for if-let guards +// only happen when the pattern is matched. + +// build-pass + +#![feature(if_let_guard)] +#![allow(irrefutable_let_patterns)] + +fn same_pattern() { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if let y = x => (), + (1, 2) if let z = x => (), + _ => (), + } +} + +fn or_pattern() { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, _) | (_, 2) if let y = x => (), + _ => (), + } +} + +fn main() { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if let y = x => false, + _ => { *x == 1 }, + }; +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs new file mode 100644 index 000000000..f12824db9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs @@ -0,0 +1,25 @@ +// Parenthesised let "expressions" are not allowed in guards + +#![feature(if_let_guard)] +#![feature(let_chains)] + +#[cfg(FALSE)] +fn un_cfged() { + match () { + () if let 0 = 1 => {} + () if (let 0 = 1) => {} + //~^ ERROR expected expression, found `let` statement + () if (((let 0 = 1))) => {} + //~^ ERROR expected expression, found `let` statement + } +} + +fn main() { + match () { + () if let 0 = 1 => {} + () if (let 0 = 1) => {} + //~^ ERROR expected expression, found `let` statement + () if (((let 0 = 1))) => {} + //~^ ERROR expected expression, found `let` statement + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.stderr new file mode 100644 index 000000000..0c16d9c54 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.stderr @@ -0,0 +1,54 @@ +error: expected expression, found `let` statement + --> $DIR/parens.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/parens.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/parens.rs:12:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/parens.rs:12:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/parens.rs:20:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/parens.rs:20:16 + | +LL | () if (let 0 = 1) => {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/parens.rs:22:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/parens.rs:22:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs new file mode 100644 index 000000000..d91b3a358 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs @@ -0,0 +1,18 @@ +// Macros can be used for (parts of) the pattern and expression in an if let guard +// check-pass + +#![feature(if_let_guard)] +#![feature(let_chains)] + +macro_rules! m { + (pattern $i:ident) => { Some($i) }; + (expression $e:expr) => { $e }; +} + +fn main() { + match () { + () if let m!(pattern x) = m!(expression Some(4)) => {} + () if let [m!(pattern y)] = [Some(8 + m!(expression 4))] => {} + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/run-pass.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/run-pass.rs new file mode 100644 index 000000000..a303a0d1f --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/run-pass.rs @@ -0,0 +1,40 @@ +// run-pass + +#![feature(if_let_guard)] + +enum Foo { + Bar, + Baz, + Qux(u8), +} + +fn bar(x: bool) -> Foo { + if x { Foo::Baz } else { Foo::Bar } +} + +fn baz(x: u8) -> Foo { + if x % 2 == 0 { Foo::Bar } else { Foo::Baz } +} + +fn qux(x: u8) -> Foo { + Foo::Qux(x.rotate_left(1)) +} + +fn main() { + match Some((true, 3)) { + Some((x, _)) if let Foo::Bar = bar(x) => panic!(), + Some((_, x)) if let Foo::Baz = baz(x) => {}, + _ => panic!(), + } + match Some(42) { + Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84), + _ => panic!(), + } + + // issue #88015 + #[allow(irrefutable_let_patterns)] + match () { + () | () if let x = 42 => assert_eq!(x, 42), + _ => panic!() + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs new file mode 100644 index 000000000..dba292ef9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs @@ -0,0 +1,23 @@ +// Check shadowing in if let guards works as expected. +// check-pass + +#![feature(if_let_guard)] +#![feature(let_chains)] + +fn main() { + let x: Option<Option<i32>> = Some(Some(6)); + match x { + Some(x) if let Some(x) = x => { + let _: i32 = x; + } + _ => {} + } + + let y: Option<Option<Option<i32>>> = Some(Some(Some(-24))); + match y { + Some(y) if let Some(y) = y && let Some(y) = y => { + let _: i32 = y; + } + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rs new file mode 100644 index 000000000..ef7a772e6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(if_let_guard)] + +struct S; + +fn get<T>() -> Option<T> { + None +} + +fn main() { + match get() { + x if let Some(S) = x => {} + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs new file mode 100644 index 000000000..ad178dfa4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs @@ -0,0 +1,15 @@ +#![feature(if_let_guard)] + +fn ok() -> Result<Option<bool>, ()> { + Ok(Some(true)) +} + +fn main() { + match ok() { + Ok(x) if let Err(_) = x => {}, + //~^ ERROR mismatched types + Ok(x) if let 0 = x => {}, + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.stderr new file mode 100644 index 000000000..4ce97a68a --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/typeck.rs:9:22 + | +LL | Ok(x) if let Err(_) = x => {}, + | ^^^^^^ - this expression has type `Option<bool>` + | | + | expected `Option<bool>`, found `Result<_, _>` + | + = note: expected enum `Option<bool>` + found enum `Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/typeck.rs:11:22 + | +LL | Ok(x) if let 0 = x => {}, + | ^ - this expression has type `Option<bool>` + | | + | expected `Option<bool>`, found integer + | + = note: expected enum `Option<bool>` + found type `{integer}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs new file mode 100644 index 000000000..3ad1a50c6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs @@ -0,0 +1,21 @@ +#![feature(if_let_guard)] + +#[deny(irrefutable_let_patterns)] +fn irrefutable_let_guard() { + match Some(()) { + Some(x) if let () = x => {} + //~^ ERROR irrefutable `if let` guard + _ => {} + } +} + +#[deny(unreachable_patterns)] +fn unreachable_pattern() { + match Some(()) { + x if let None | None = x => {} + //~^ ERROR unreachable pattern + _ => {} + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr new file mode 100644 index 000000000..75f22ac8d --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr @@ -0,0 +1,28 @@ +error: irrefutable `if let` guard pattern + --> $DIR/warns.rs:6:24 + | +LL | Some(x) if let () = x => {} + | ^^ + | + = note: this pattern will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm +note: the lint level is defined here + --> $DIR/warns.rs:3:8 + | +LL | #[deny(irrefutable_let_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/warns.rs:15:25 + | +LL | x if let None | None = x => {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/warns.rs:12:8 + | +LL | #[deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + |