Add more if let guard tests

This commit is contained in:
Matthew Jasper 2023-09-18 15:18:51 +00:00
parent 078eb1120a
commit b49140295c
11 changed files with 297 additions and 4 deletions

View File

@ -1,12 +1,15 @@
// build-pass
// edition:2018
#![feature(if_let_guard)]
static A: [i32; 5] = [1, 2, 3, 4, 5];
async fn fun() {
let u = A[async { 1 }.await];
match A {
i if async { true }.await => (),
i if let Some(1) = async { Some(1) }.await => (),
_ => (),
}
}
@ -18,6 +21,7 @@ fn main() {
async {
match A {
i if async { true }.await => (),
i if let Some(2) = async { Some(2) }.await => (),
_ => (),
}
};

View File

@ -5,6 +5,8 @@
// [drop_tracking] compile-flags: -Zdrop-tracking
// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
#![feature(if_let_guard)]
static mut A: [i32; 5] = [1, 2, 3, 4, 5];
fn is_send_sync<T: Send + Sync>(_: T) {}
@ -14,6 +16,7 @@ async fn fun() {
unsafe {
match A {
i if async { true }.await => (),
i if let Some(1) = async { Some(1) }.await => (),
_ => (),
}
}
@ -27,6 +30,7 @@ fn main() {
unsafe {
match A {
i if async { true }.await => (),
i if let Some(2) = async { Some(2) }.await => (),
_ => (),
}
}

View File

@ -1,6 +1,8 @@
// check-pass
// edition:2018
#![feature(if_let_guard)]
fn main() {}
struct StructA {}
@ -22,3 +24,10 @@ async fn ice() {
_ => {}
}
}
async fn if_let() {
match Some(StructB {}) {
Some(struct_b) if let true = get_struct_a_async().await.fn_taking_struct_b(&struct_b) => {}
_ => {}
}
}

View File

@ -1,4 +1,7 @@
// run-pass
#![feature(if_let_guard)]
enum Foo {
A,
B,
@ -13,6 +16,7 @@ fn main() {
match *foo {
| A => println!("A"),
| B | C if 1 < 2 => println!("BC!"),
| D if let 1 = 1 => println!("D!"),
| _ => {},
}
}

View File

@ -2,6 +2,7 @@
// needs-unwind
#![feature(generators, generator_trait)]
#![feature(if_let_guard)]
#![allow(unused_assignments)]
#![allow(unused_variables)]
@ -332,6 +333,16 @@ fn move_ref_pattern(a: &Allocator) {
let (ref _a, ref mut _b, _c, mut _d) = tup;
}
fn if_let_guard(a: &Allocator, c: bool, d: i32) {
let foo = if c { Some(a.alloc()) } else { None };
match d == 0 {
false if let Some(a) = foo => { let b = a; }
true if let true = { drop(foo.unwrap_or_else(|| a.alloc())); d == 1 } => {}
_ => {}
}
}
fn panic_after_return(a: &Allocator) -> Ptr<'_> {
// Panic in the drop of `p` or `q` can leak
let exceptions = vec![8, 9];
@ -497,6 +508,13 @@ fn main() {
run_test(|a| move_ref_pattern(a));
run_test(|a| if_let_guard(a, true, 0));
run_test(|a| if_let_guard(a, true, 1));
run_test(|a| if_let_guard(a, true, 2));
run_test(|a| if_let_guard(a, false, 0));
run_test(|a| if_let_guard(a, false, 1));
run_test(|a| if_let_guard(a, false, 2));
run_test(|a| {
panic_after_return(a);
});

View File

@ -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];
}

View File

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

View File

@ -0,0 +1,67 @@
error[E0382]: use of moved value: `x`
--> $DIR/move-guard-if-let-chain.rs:12:27
|
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:27
|
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:36
|
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
| |
| value moved here
|
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`.

View File

@ -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 },
};
}

View File

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

View File

@ -2,25 +2,32 @@
#![allow(unused_must_use)]
#![allow(dead_code)]
#![allow(path_statements)]
#![allow(unreachable_code)]
#![allow(unused_variables)]
#![feature(if_let_guard)]
fn id(x: bool) -> bool { x }
fn id(x: bool) -> bool {
x
}
fn call_id() {
let c = panic!();
id(c);
}
fn call_id_2() { id(true) && id(return); }
fn call_id_2() {
id(true) && id(return);
}
fn call_id_3() { id(return) && id(return); }
fn call_id_3() {
id(return) && id(return);
}
fn ret_guard() {
match 2 {
x if (return) => { x; }
x if let true = return => { x; }
_ => {}
}
}