Add more tests for or-patterns

This commit is contained in:
Matthew Jasper 2019-12-27 18:11:20 +00:00
parent 0b1ff27cd8
commit c7e6f88926
10 changed files with 474 additions and 0 deletions

View File

@ -0,0 +1,76 @@
// Test that simple or-patterns don't get expanded to exponentially large CFGs
// ignore-tidy-linelength
#![feature(or_patterns)]
fn match_tuple(x: (u32, bool, Option<i32>, u32)) -> u32 {
match x {
(y @ (1 | 4), true | false, Some(1 | 8) | None, z @ (6..=9 | 13..=16)) => y ^ z,
_ => 0,
}
}
fn main() {}
// END RUST SOURCE
// START rustc.match_tuple.SimplifyCfg-initial.after.mir
// scope 1 {
// debug y => _7;
// debug z => _8;
// }
// bb0: {
// FakeRead(ForMatchedPlace, _1);
// switchInt((_1.0: u32)) -> [1u32: bb2, 4u32: bb2, otherwise: bb1];
// }
// bb1: {
// _0 = const 0u32;
// goto -> bb10;
// }
// bb2: {
// _2 = discriminant((_1.2: std::option::Option<i32>));
// switchInt(move _2) -> [0isize: bb4, 1isize: bb3, otherwise: bb1];
// }
// bb3: {
// switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1i32: bb4, 8i32: bb4, otherwise: bb1];
// }
// bb4: {
// _5 = Le(const 6u32, (_1.3: u32));
// switchInt(move _5) -> [false: bb6, otherwise: bb5];
// }
// bb5: {
// _6 = Le((_1.3: u32), const 9u32);
// switchInt(move _6) -> [false: bb6, otherwise: bb8];
// }
// bb6: {
// _3 = Le(const 13u32, (_1.3: u32));
// switchInt(move _3) -> [false: bb1, otherwise: bb7];
// }
// bb7: {
// _4 = Le((_1.3: u32), const 16u32);
// switchInt(move _4) -> [false: bb1, otherwise: bb8];
// }
// bb8: {
// falseEdges -> [real: bb9, imaginary: bb1];
// }
// bb9: {
// StorageLive(_7);
// _7 = (_1.0: u32);
// StorageLive(_8);
// _8 = (_1.3: u32);
// StorageLive(_9);
// _9 = _7;
// StorageLive(_10);
// _10 = _8;
// _0 = BitXor(move _9, move _10);
// StorageDead(_10);
// StorageDead(_9);
// StorageDead(_8);
// StorageDead(_7);
// goto -> bb10;
// }
// bb10: {
// return;
// }
// END rustc.match_tuple.SimplifyCfg-initial.after.mir

View File

@ -0,0 +1,64 @@
// Test that borrow check considers all choices in an or pattern, even the
// unreachable ones.
#![feature(or_patterns)]
fn or_pattern_moves_all(x: ((String, String),)) {
match x {
((y, _) | (_, y),) => (),
}
&x.0 .0;
//~^ ERROR borrow of moved value
&x.0 .1;
//~^ ERROR borrow of moved value
}
fn or_pattern_borrows_all(mut x: ((String, String),)) {
let r = match x {
((ref y, _) | (_, ref y),) => y,
};
&mut x.0 .0;
//~^ ERROR cannot borrow
&mut x.0 .1;
//~^ ERROR cannot borrow
drop(r);
}
fn or_pattern_borrows_all_mut(mut x: ((String, String),)) {
let r = match x {
((ref mut y, _) | (_, ref mut y),) => y,
};
&x.0 .0;
//~^ ERROR cannot borrow
&x.0 .1;
//~^ ERROR cannot borrow
drop(r);
}
fn let_or_pattern_moves_all(x: ((String, String),)) {
let ((y, _) | (_, y),) = x;
&x.0 .0;
//~^ ERROR borrow of moved value
&x.0 .1;
//~^ ERROR borrow of moved value
}
fn let_or_pattern_borrows_all(mut x: ((String, String),)) {
let ((ref r, _) | (_, ref r),) = x;
&mut x.0 .0;
//~^ ERROR cannot borrow
&mut x.0 .1;
//~^ ERROR cannot borrow
drop(r);
}
fn let_or_pattern_borrows_all_mut(mut x: ((String, String),)) {
let ((ref mut r, _) | (_, ref mut r),) = x;
&x.0 .0;
//~^ ERROR cannot borrow
&x.0 .1;
//~^ ERROR cannot borrow
drop(r);
}
fn main() {}

View File

@ -0,0 +1,141 @@
error[E0382]: borrow of moved value: `x.0.0`
--> $DIR/or-patterns.rs:10:5
|
LL | ((y, _) | (_, y),) => (),
| - value moved here
LL | }
LL | &x.0 .0;
| ^^^^^^^ value borrowed here after move
|
= note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x.0.1`
--> $DIR/or-patterns.rs:12:5
|
LL | ((y, _) | (_, y),) => (),
| - value moved here
...
LL | &x.0 .1;
| ^^^^^^^ value borrowed here after move
|
= note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait
error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
--> $DIR/or-patterns.rs:20:5
|
LL | ((ref y, _) | (_, ref y),) => y,
| ----- immutable borrow occurs here
LL | };
LL | &mut x.0 .0;
| ^^^^^^^^^^^ mutable borrow occurs here
...
LL | drop(r);
| - immutable borrow later used here
error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable
--> $DIR/or-patterns.rs:22:5
|
LL | ((ref y, _) | (_, ref y),) => y,
| ----- immutable borrow occurs here
...
LL | &mut x.0 .1;
| ^^^^^^^^^^^ mutable borrow occurs here
LL |
LL | drop(r);
| - immutable borrow later used here
error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable
--> $DIR/or-patterns.rs:31:5
|
LL | ((ref mut y, _) | (_, ref mut y),) => y,
| --------- mutable borrow occurs here
LL | };
LL | &x.0 .0;
| ^^^^^^^ immutable borrow occurs here
...
LL | drop(r);
| - mutable borrow later used here
error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable
--> $DIR/or-patterns.rs:33:5
|
LL | ((ref mut y, _) | (_, ref mut y),) => y,
| --------- mutable borrow occurs here
...
LL | &x.0 .1;
| ^^^^^^^ immutable borrow occurs here
LL |
LL | drop(r);
| - mutable borrow later used here
error[E0382]: borrow of moved value: `x.0.0`
--> $DIR/or-patterns.rs:40:5
|
LL | let ((y, _) | (_, y),) = x;
| - value moved here
LL | &x.0 .0;
| ^^^^^^^ value borrowed here after move
|
= note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x.0.1`
--> $DIR/or-patterns.rs:42:5
|
LL | let ((y, _) | (_, y),) = x;
| - value moved here
...
LL | &x.0 .1;
| ^^^^^^^ value borrowed here after move
|
= note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait
error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
--> $DIR/or-patterns.rs:48:5
|
LL | let ((ref r, _) | (_, ref r),) = x;
| ----- immutable borrow occurs here
LL | &mut x.0 .0;
| ^^^^^^^^^^^ mutable borrow occurs here
...
LL | drop(r);
| - immutable borrow later used here
error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable
--> $DIR/or-patterns.rs:50:5
|
LL | let ((ref r, _) | (_, ref r),) = x;
| ----- immutable borrow occurs here
...
LL | &mut x.0 .1;
| ^^^^^^^^^^^ mutable borrow occurs here
LL |
LL | drop(r);
| - immutable borrow later used here
error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable
--> $DIR/or-patterns.rs:57:5
|
LL | let ((ref mut r, _) | (_, ref mut r),) = x;
| --------- mutable borrow occurs here
LL | &x.0 .0;
| ^^^^^^^ immutable borrow occurs here
...
LL | drop(r);
| - mutable borrow later used here
error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable
--> $DIR/or-patterns.rs:59:5
|
LL | let ((ref mut r, _) | (_, ref mut r),) = x;
| --------- mutable borrow occurs here
...
LL | &x.0 .1;
| ^^^^^^^ immutable borrow occurs here
LL |
LL | drop(r);
| - mutable borrow later used here
error: aborting due to 12 previous errors
Some errors have detailed explanations: E0382, E0502.
For more information about an error, try `rustc --explain E0382`.

View File

@ -0,0 +1,25 @@
// run-pass
#![feature(or_patterns)]
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);
}

View File

@ -0,0 +1,32 @@
// run-pass
#![feature(or_patterns)]
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);
}

View File

@ -0,0 +1,18 @@
// Check that or patterns are lowered correctly in `for` loops.
// run-pass
#![feature(or_patterns)]
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]);
}

View File

@ -0,0 +1,22 @@
// Check that or patterns are lowered correctly in `if let` and `while let` expressions.
// run-pass
#![feature(or_patterns)]
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!();
}
}

View File

@ -0,0 +1,11 @@
// Check that we don't ICE for irrefutable or-patterns in function parameters
// check-pass
#![feature(or_patterns)]
fn foo((Some(_) | None): Option<u32>) {}
fn main() {
foo(None);
}

View File

@ -0,0 +1,19 @@
#![feature(or_patterns)]
// 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);
}

View File

@ -0,0 +1,66 @@
// Check that we expand multiple or-patterns from left to right.
// run-pass
#![feature(or_patterns)]
#![allow(unreachable_patterns)] // FIXME(or-patterns) this shouldn't trigger
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);
}