Rollup merge of #115172 - matthewjasper:if-let-guard-tests, r=cjgillot

Add more tests for if_let_guard

Adds tests for borrow checking, name shadowing and interaction with macros.

cc #51114
This commit is contained in:
Weihang Lo 2023-08-24 22:54:00 +01:00 committed by GitHub
commit 0c1f9c8c4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 298 additions and 0 deletions

View File

@ -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 => {}
}
}

View File

@ -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`.

View File

@ -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;
}
_ => {}
}
}

View File

@ -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 previous error
For more information about this error, try `rustc --explain E0505`.

View File

@ -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;
}
_ => {}
}
}

View File

@ -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;
}
_ => {}
}
}

View File

@ -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 previous error
For more information about this error, try `rustc --explain E0596`.

View File

@ -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;
}
_ => {}
}
}

View File

@ -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 previous error
For more information about this error, try `rustc --explain E0596`.

View File

@ -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)) => {}
_ => {}
}
}

View File

@ -0,0 +1,13 @@
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: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error

View File

@ -0,0 +1,27 @@
// 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
//~| ERROR `let` expressions are not supported here
() if (((let 0 = 1))) => {}
//~^ ERROR expected expression, found `let` statement
//~| ERROR `let` expressions are not supported here
}
}

View File

@ -0,0 +1,52 @@
error: expected expression, found `let` statement
--> $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))) => {}
| ^^^
error: expected expression, found `let` statement
--> $DIR/parens.rs:20:16
|
LL | () if (let 0 = 1) => {}
| ^^^
error: expected expression, found `let` statement
--> $DIR/parens.rs:23:18
|
LL | () if (((let 0 = 1))) => {}
| ^^^
error: `let` expressions are not supported here
--> $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: `let` expressions are not supported here
--> $DIR/parens.rs:23: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:23:18
|
LL | () if (((let 0 = 1))) => {}
| ^^^^^^^^^
error: aborting due to 6 previous errors

View File

@ -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))] => {}
_ => {}
}
}

View File

@ -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;
}
_ => {}
}
}