Skip to content

Commit

Permalink
Rollup merge of rust-lang#106005 - LeSeulArtichaut:if-let-guard-borro…
Browse files Browse the repository at this point in the history
…wck-test, r=Nilstrieb

Test the borrowck behavior of if-let guards

Add some tests to make sure that if-let guards behave the same as if guards with respect to borrow-checking. Most of them are a naive adaptation, replacing an `if` guard with `if let Some(())`.
This includes regression tests for notable issues that arose for if guards (rust-lang#24535, rust-lang#27282, rust-lang#29723, rust-lang#31287) as suggested in rust-lang#51114 (comment).

cc `@pnkfelix` are there any other tests that you would want to see?
cc tracking issue rust-lang#51114
  • Loading branch information
matthiaskrgr authored Jan 3, 2023
2 parents da07053 + 56aaf74 commit 6e94012
Show file tree
Hide file tree
Showing 27 changed files with 645 additions and 62 deletions.
9 changes: 9 additions & 0 deletions src/test/ui/borrowck/borrowck-drop-from-guard.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![feature(if_let_guard)]

fn foo(_:String) {}

fn main()
Expand All @@ -8,4 +10,11 @@ fn main()
Some(_) => {}
None => { foo(my_str); } //~ ERROR [E0382]
}

let my_str = "hello".to_owned();
match Some(42) {
Some(_) if let Some(()) = { drop(my_str); None } => {}
Some(_) => {}
None => { foo(my_str); } //~ ERROR [E0382]
}
}
21 changes: 19 additions & 2 deletions src/test/ui/borrowck/borrowck-drop-from-guard.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0382]: use of moved value: `my_str`
--> $DIR/borrowck-drop-from-guard.rs:9:23
--> $DIR/borrowck-drop-from-guard.rs:11:23
|
LL | let my_str = "hello".to_owned();
| ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
Expand All @@ -15,6 +15,23 @@ help: consider cloning the value if the performance cost is acceptable
LL | Some(_) if { drop(my_str.clone()); false } => {}
| ++++++++

error: aborting due to previous error
error[E0382]: use of moved value: `my_str`
--> $DIR/borrowck-drop-from-guard.rs:18:23
|
LL | let my_str = "hello".to_owned();
| ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
LL | match Some(42) {
LL | Some(_) if let Some(()) = { drop(my_str); None } => {}
| ------ value moved here
LL | Some(_) => {}
LL | None => { foo(my_str); }
| ^^^^^^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
| ++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0382`.
19 changes: 16 additions & 3 deletions src/test/ui/borrowck/borrowck-mutate-in-guard.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#![feature(if_let_guard)]

enum Enum<'a> {
A(&'a isize),
B(bool),
}

fn foo() -> isize {
fn if_guard() -> isize {
let mut n = 42;
let mut x = Enum::A(&mut n);
match x {
Expand All @@ -16,6 +18,17 @@ fn foo() -> isize {
}
}

fn main() {
foo();
fn if_let_guard() -> isize {
let mut n = 42;
let mut x = Enum::A(&mut n);
match x {
Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
//~^ ERROR cannot assign `x` in match guard
Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
//~^ ERROR cannot mutably borrow `x` in match guard
Enum::A(p) => *p,
Enum::B(_) => 2,
}
}

fn main() {}
23 changes: 20 additions & 3 deletions src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
error[E0510]: cannot assign `x` in match guard
--> $DIR/borrowck-mutate-in-guard.rs:10:25
--> $DIR/borrowck-mutate-in-guard.rs:12:25
|
LL | match x {
| - value is immutable in match guard
LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
| ^^^^^^^^^^^^^^^^^^ cannot assign

error[E0510]: cannot mutably borrow `x` in match guard
--> $DIR/borrowck-mutate-in-guard.rs:12:33
--> $DIR/borrowck-mutate-in-guard.rs:14:33
|
LL | match x {
| - value is immutable in match guard
...
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
| ^^^^^^ cannot mutably borrow

error: aborting due to 2 previous errors
error[E0510]: cannot assign `x` in match guard
--> $DIR/borrowck-mutate-in-guard.rs:25:40
|
LL | match x {
| - value is immutable in match guard
LL | Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
| ^^^^^^^^^^^^^^^^^^ cannot assign

error[E0510]: cannot mutably borrow `x` in match guard
--> $DIR/borrowck-mutate-in-guard.rs:27:48
|
LL | match x {
| - value is immutable in match guard
...
LL | Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
| ^^^^^^ cannot mutably borrow

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0510`.
9 changes: 8 additions & 1 deletion src/test/ui/borrowck/issue-31287-drop-in-guard.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
#![feature(if_let_guard)]

fn main() {
let a = Some("...".to_owned());
let b = match a {
Some(_) if { drop(a); false } => None,
x => x, //~ ERROR use of moved value: `a`
};
println!("{:?}", b);

let a = Some("...".to_owned());
let b = match a {
Some(_) if let Some(()) = { drop(a); None } => None,
x => x, //~ ERROR use of moved value: `a`
};
}
20 changes: 18 additions & 2 deletions src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0382]: use of moved value: `a`
--> $DIR/issue-31287-drop-in-guard.rs:5:9
--> $DIR/issue-31287-drop-in-guard.rs:7:9
|
LL | let a = Some("...".to_owned());
| - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
Expand All @@ -14,6 +14,22 @@ help: consider cloning the value if the performance cost is acceptable
LL | Some(_) if { drop(a.clone()); false } => None,
| ++++++++

error: aborting due to previous error
error[E0382]: use of moved value: `a`
--> $DIR/issue-31287-drop-in-guard.rs:13:9
|
LL | let a = Some("...".to_owned());
| - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
LL | let b = match a {
LL | Some(_) if let Some(()) = { drop(a); None } => None,
| - value moved here
LL | x => x,
| ^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | Some(_) if let Some(()) = { drop(a.clone()); None } => None,
| ++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0382`.
8 changes: 8 additions & 0 deletions src/test/ui/issues/issue-29723.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// test for https://github.com/rust-lang/rust/issues/29723

#![feature(if_let_guard)]

fn main() {
let s = String::new();
let _s = match 0 {
Expand All @@ -11,4 +13,10 @@ fn main() {
//~^ ERROR use of moved value: `s`
}
};

let s = String::new();
let _s = match 0 {
0 if let Some(()) = { drop(s); None } => String::from("oops"),
_ => s //~ ERROR use of moved value: `s`
};
}
20 changes: 18 additions & 2 deletions src/test/ui/issues/issue-29723.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0382]: use of moved value: `s`
--> $DIR/issue-29723.rs:10:13
--> $DIR/issue-29723.rs:12:13
|
LL | let s = String::new();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
Expand All @@ -15,6 +15,22 @@ help: consider cloning the value if the performance cost is acceptable
LL | 0 if { drop(s.clone()); false } => String::from("oops"),
| ++++++++

error: aborting due to previous error
error[E0382]: use of moved value: `s`
--> $DIR/issue-29723.rs:20:14
|
LL | let s = String::new();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
LL | let _s = match 0 {
LL | 0 if let Some(()) = { drop(s); None } => String::from("oops"),
| - value moved here
LL | _ => s
| ^ value used here after move
|
help: consider cloning the value if the performance cost is acceptable
|
LL | 0 if let Some(()) = { drop(s.clone()); None } => String::from("oops"),
| ++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0382`.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// See further discussion on rust-lang/rust#24535,
// rust-lang/rfcs#1006, and rust-lang/rfcs#107

#![feature(if_let_guard)]

fn main() {
rust_issue_24535();
rfcs_issue_1006_1();
Expand All @@ -23,6 +25,12 @@ fn rust_issue_24535() {
3 if compare(&a, &mut 3) => (),
_ => panic!("nope"),
}

match a {
0 => panic!("nope"),
3 if let true = compare(&a, &mut 3) => (),
_ => panic!("nope"),
}
}

fn rfcs_issue_1006_1() {
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// reaches the panic code when executed, despite the compiler warning
// about that match arm being unreachable.

#![feature(if_let_guard)]

fn main() {
let b = &mut true;
match b {
Expand All @@ -17,4 +19,16 @@ fn main() {
&mut true => { println!("You might think we should get here"); },
_ => panic!("surely we could never get here, since rustc warns it is unreachable."),
}

let b = &mut true;
match b {
//~^ ERROR use of moved value: `b` [E0382]
&mut false => {}
_ if let Some(()) = {
(|| { let bar = b; *bar = false; })();
None
} => {}
&mut true => {}
_ => {}
}
}
17 changes: 15 additions & 2 deletions src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0382]: use of moved value: `b`
--> $DIR/issue-27282-move-match-input-into-guard.rs:12:5
--> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
|
LL | let b = &mut true;
| - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
Expand All @@ -11,6 +11,19 @@ LL | _ if { (|| { let bar = b; *bar = false; })();
| |
| value moved into closure here

error: aborting due to previous error
error[E0382]: use of moved value: `b`
--> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
|
LL | let b = &mut true;
| - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
LL | match b {
| ^^^^^^^ value used here after move
...
LL | (|| { let bar = b; *bar = false; })();
| -- - variable moved due to use in closure
| |
| value moved into closure here

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0382`.
10 changes: 10 additions & 0 deletions src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// mutable borrows in match guards by hiding the mutable borrow in a
// guard behind a move (of the ref mut pattern id) within a closure.

#![feature(if_let_guard)]

fn main() {
match Some(&4) {
None => {},
Expand All @@ -10,4 +12,12 @@ fn main() {
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
Some(s) => std::process::exit(*s),
}

match Some(&4) {
None => {},
ref mut foo
if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
Some(s) => std::process::exit(*s),
}
}
14 changes: 12 additions & 2 deletions src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
|
LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
Expand All @@ -8,6 +8,16 @@ LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard

error: aborting due to previous error
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
|
LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| move out of `foo` occurs here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0507`.
13 changes: 13 additions & 0 deletions src/test/ui/nll/issue-27282-mutation-in-guard.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![feature(if_let_guard)]

fn main() {
match Some(&4) {
None => {},
Expand All @@ -10,4 +12,15 @@ fn main() {
Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
_ => println!("Here is some supposedly unreachable code."),
}

match Some(&4) {
None => {},
ref mut foo
if let Some(()) = {
(|| { let bar = foo; bar.take() })();
//~^ ERROR cannot move out of `foo` in pattern guard
None
} => {},
Some(_) => {},
}
}
14 changes: 12 additions & 2 deletions src/test/ui/nll/issue-27282-mutation-in-guard.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-mutation-in-guard.rs:6:18
--> $DIR/issue-27282-mutation-in-guard.rs:8:18
|
LL | (|| { let bar = foo; bar.take() })();
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
Expand All @@ -8,6 +8,16 @@ LL | (|| { let bar = foo; bar.take() })();
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard

error: aborting due to previous error
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-mutation-in-guard.rs:20:18
|
LL | (|| { let bar = foo; bar.take() })();
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| move out of `foo` occurs here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0507`.
Loading

0 comments on commit 6e94012

Please sign in to comment.