-
Notifications
You must be signed in to change notification settings - Fork 12.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #88280 - sexxi-goose:non-exhaustive, r=nikomatsakis
Handle match statements with non exhaustive variants in closures This PR ensures that the behavior for match statements with non exhaustive variants is the same inside and outside closures. If we have a non-exhaustive SingleVariant which is defined in a different crate, then we should handle the case the same way we would handle a MultiVariant: borrow the match discriminant. Closes rust-lang/project-rfc-2229#59 r? `@nikomatsakis`
- Loading branch information
Showing
17 changed files
with
185 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/test/ui/closures/2229_closure_analysis/match/auxiliary/match_non_exhaustive_lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#[non_exhaustive] | ||
pub enum E1 {} | ||
|
||
#[non_exhaustive] | ||
pub enum E2 { A, B } | ||
|
||
#[non_exhaustive] | ||
pub enum E3 { C } | ||
|
||
pub enum E4 { D } |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
37 changes: 37 additions & 0 deletions
37
src/test/ui/closures/2229_closure_analysis/match/match-edge-cases_2.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// edition:2021 | ||
|
||
enum SingleVariant { | ||
A | ||
} | ||
|
||
struct TestStruct { | ||
x: i32, | ||
y: i32, | ||
z: i32, | ||
} | ||
|
||
fn edge_case_if() { | ||
let sv = SingleVariant::A; | ||
let condition = true; | ||
// sv should not be captured as it is a SingleVariant | ||
let _a = || { | ||
match sv { | ||
SingleVariant::A if condition => (), | ||
_ => () | ||
} | ||
}; | ||
let mut mut_sv = sv; | ||
_a(); | ||
|
||
// ts should be captured | ||
let ts = TestStruct { x: 1, y: 1, z: 1 }; | ||
let _b = || { match ts { | ||
TestStruct{ x: 1, .. } => (), | ||
_ => () | ||
}}; | ||
let mut mut_ts = ts; | ||
//~^ ERROR: cannot move out of `ts` because it is borrowed | ||
_b(); | ||
} | ||
|
||
fn main() {} |
17 changes: 17 additions & 0 deletions
17
src/test/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
error[E0505]: cannot move out of `ts` because it is borrowed | ||
--> $DIR/match-edge-cases_2.rs:32:22 | ||
| | ||
LL | let _b = || { match ts { | ||
| -- -- borrow occurs due to use in closure | ||
| | | ||
| borrow of `ts` occurs here | ||
... | ||
LL | let mut mut_ts = ts; | ||
| ^^ move out of `ts` occurs here | ||
LL | | ||
LL | _b(); | ||
| -- borrow later used here | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0505`. |
54 changes: 54 additions & 0 deletions
54
src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// edition:2021 | ||
|
||
// aux-build:match_non_exhaustive_lib.rs | ||
|
||
/* The error message for non-exhaustive matches on non-local enums | ||
* marked as non-exhaustive should mention the fact that the enum | ||
* is marked as non-exhaustive (issue #85227). | ||
*/ | ||
|
||
// Ignore non_exhaustive in the same crate | ||
#[non_exhaustive] | ||
enum L1 { A, B } | ||
enum L2 { C } | ||
|
||
extern crate match_non_exhaustive_lib; | ||
use match_non_exhaustive_lib::{E1, E2, E3, E4}; | ||
|
||
fn foo() -> (L1, L2) {todo!()} | ||
fn bar() -> (E1, E2, E3, E4) {todo!()} | ||
|
||
fn main() { | ||
let (l1, l2) = foo(); | ||
// No error for enums defined in this crate | ||
let _a = || { match l1 { L1::A => (), L1::B => () } }; | ||
// (except if the match is already non-exhaustive) | ||
let _b = || { match l1 { L1::A => () } }; | ||
//~^ ERROR: non-exhaustive patterns: `B` not covered [E0004] | ||
|
||
// l2 should not be captured as it is a non-exhaustive SingleVariant | ||
// defined in this crate | ||
let _c = || { match l2 { L2::C => (), _ => () } }; | ||
let mut mut_l2 = l2; | ||
_c(); | ||
|
||
// E1 is not visibly uninhabited from here | ||
let (e1, e2, e3, e4) = bar(); | ||
let _d = || { match e1 {} }; | ||
//~^ ERROR: non-exhaustive patterns: type `E1` is non-empty [E0004] | ||
let _e = || { match e2 { E2::A => (), E2::B => () } }; | ||
//~^ ERROR: non-exhaustive patterns: `_` not covered [E0004] | ||
let _f = || { match e2 { E2::A => (), E2::B => (), _ => () } }; | ||
|
||
// e3 should be captured as it is a non-exhaustive SingleVariant | ||
// defined in another crate | ||
let _g = || { match e3 { E3::C => (), _ => () } }; | ||
let mut mut_e3 = e3; | ||
//~^ ERROR: cannot move out of `e3` because it is borrowed | ||
_g(); | ||
|
||
// e4 should not be captured as it is a SingleVariant | ||
let _h = || { match e4 { E4::D => (), _ => () } }; | ||
let mut mut_e4 = e4; | ||
_h(); | ||
} |
50 changes: 50 additions & 0 deletions
50
src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
error[E0004]: non-exhaustive patterns: `B` not covered | ||
--> $DIR/non-exhaustive-match.rs:26:25 | ||
| | ||
LL | enum L1 { A, B } | ||
| ---------------- | ||
| | | | ||
| | not covered | ||
| `L1` defined here | ||
... | ||
LL | let _b = || { match l1 { L1::A => () } }; | ||
| ^^ pattern `B` not covered | ||
| | ||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms | ||
= note: the matched value is of type `L1` | ||
|
||
error[E0004]: non-exhaustive patterns: type `E1` is non-empty | ||
--> $DIR/non-exhaustive-match.rs:37:25 | ||
| | ||
LL | let _d = || { match e1 {} }; | ||
| ^^ | ||
| | ||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms | ||
= note: the matched value is of type `E1`, which is marked as non-exhaustive | ||
|
||
error[E0004]: non-exhaustive patterns: `_` not covered | ||
--> $DIR/non-exhaustive-match.rs:39:25 | ||
| | ||
LL | let _e = || { match e2 { E2::A => (), E2::B => () } }; | ||
| ^^ pattern `_` not covered | ||
| | ||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms | ||
= note: the matched value is of type `E2`, which is marked as non-exhaustive | ||
|
||
error[E0505]: cannot move out of `e3` because it is borrowed | ||
--> $DIR/non-exhaustive-match.rs:46:22 | ||
| | ||
LL | let _g = || { match e3 { E3::C => (), _ => () } }; | ||
| -- -- borrow occurs due to use in closure | ||
| | | ||
| borrow of `e3` occurs here | ||
LL | let mut mut_e3 = e3; | ||
| ^^ move out of `e3` occurs here | ||
LL | | ||
LL | _g(); | ||
| -- borrow later used here | ||
|
||
error: aborting due to 4 previous errors | ||
|
||
Some errors have detailed explanations: E0004, E0505. | ||
For more information about an error, try `rustc --explain E0004`. |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.