about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/mir-opt/exponential-or.rs76
-rw-r--r--src/test/ui/borrowck/or-patterns.rs64
-rw-r--r--src/test/ui/borrowck/or-patterns.stderr141
-rw-r--r--src/test/ui/or-patterns/bindings-runpass-1.rs25
-rw-r--r--src/test/ui/or-patterns/bindings-runpass-2.rs32
-rw-r--r--src/test/ui/or-patterns/for-loop.rs18
-rw-r--r--src/test/ui/or-patterns/if-let-while-let.rs22
-rw-r--r--src/test/ui/or-patterns/issue-67514-irrefutable-param.rs11
-rw-r--r--src/test/ui/or-patterns/let-pattern.rs19
-rw-r--r--src/test/ui/or-patterns/search-via-bindings.rs66
10 files changed, 474 insertions, 0 deletions
diff --git a/src/test/mir-opt/exponential-or.rs b/src/test/mir-opt/exponential-or.rs
new file mode 100644
index 00000000000..4c23582e1f8
--- /dev/null
+++ b/src/test/mir-opt/exponential-or.rs
@@ -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
diff --git a/src/test/ui/borrowck/or-patterns.rs b/src/test/ui/borrowck/or-patterns.rs
new file mode 100644
index 00000000000..5b31e2d76a0
--- /dev/null
+++ b/src/test/ui/borrowck/or-patterns.rs
@@ -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() {}
diff --git a/src/test/ui/borrowck/or-patterns.stderr b/src/test/ui/borrowck/or-patterns.stderr
new file mode 100644
index 00000000000..d3f3544426a
--- /dev/null
+++ b/src/test/ui/borrowck/or-patterns.stderr
@@ -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`.
diff --git a/src/test/ui/or-patterns/bindings-runpass-1.rs b/src/test/ui/or-patterns/bindings-runpass-1.rs
new file mode 100644
index 00000000000..0087167af7e
--- /dev/null
+++ b/src/test/ui/or-patterns/bindings-runpass-1.rs
@@ -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);
+}
diff --git a/src/test/ui/or-patterns/bindings-runpass-2.rs b/src/test/ui/or-patterns/bindings-runpass-2.rs
new file mode 100644
index 00000000000..0e1eb7b2e03
--- /dev/null
+++ b/src/test/ui/or-patterns/bindings-runpass-2.rs
@@ -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);
+}
diff --git a/src/test/ui/or-patterns/for-loop.rs b/src/test/ui/or-patterns/for-loop.rs
new file mode 100644
index 00000000000..b79af6c402e
--- /dev/null
+++ b/src/test/ui/or-patterns/for-loop.rs
@@ -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]);
+}
diff --git a/src/test/ui/or-patterns/if-let-while-let.rs b/src/test/ui/or-patterns/if-let-while-let.rs
new file mode 100644
index 00000000000..9256360b29d
--- /dev/null
+++ b/src/test/ui/or-patterns/if-let-while-let.rs
@@ -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!();
+    }
+}
diff --git a/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs b/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs
new file mode 100644
index 00000000000..0c2ae44e546
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs
@@ -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);
+}
diff --git a/src/test/ui/or-patterns/let-pattern.rs b/src/test/ui/or-patterns/let-pattern.rs
new file mode 100644
index 00000000000..07e37412ce8
--- /dev/null
+++ b/src/test/ui/or-patterns/let-pattern.rs
@@ -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);
+}
diff --git a/src/test/ui/or-patterns/search-via-bindings.rs b/src/test/ui/or-patterns/search-via-bindings.rs
new file mode 100644
index 00000000000..eb127b881cd
--- /dev/null
+++ b/src/test/ui/or-patterns/search-via-bindings.rs
@@ -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);
+}