Handle match with non axhaustive variants in closures
This commit is contained in:
parent
926f069950
commit
20de556a26
4 changed files with 131 additions and 2 deletions
|
@ -15,7 +15,7 @@ use rustc_index::vec::Idx;
|
|||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::hir::place::ProjectionKind;
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty::{self, adjustment, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use std::iter;
|
||||
|
||||
|
@ -845,5 +845,20 @@ fn delegate_consume<'a, 'tcx>(
|
|||
}
|
||||
|
||||
fn is_multivariant_adt(ty: Ty<'tcx>) -> bool {
|
||||
if let ty::Adt(def, _) = ty.kind() { def.variants.len() > 1 } else { false }
|
||||
if let ty::Adt(def, _) = ty.kind() {
|
||||
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
|
||||
// to assume that more cases will be added to the variant in the future. This mean
|
||||
// that we should handle non-exhaustive SingleVariant the same way we would handle
|
||||
// a MultiVariant.
|
||||
// If the variant is not local it must be defined in another crate.
|
||||
let is_non_exhaustive = match def.adt_kind() {
|
||||
AdtKind::Struct | AdtKind::Union => {
|
||||
def.non_enum_variant().is_field_list_non_exhaustive()
|
||||
}
|
||||
AdtKind::Enum => def.is_variant_list_non_exhaustive(),
|
||||
};
|
||||
def.variants.len() > 1 || (!def.did.is_local() && is_non_exhaustive)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
|
@ -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();
|
||||
}
|
|
@ -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`.
|
Loading…
Add table
Add a link
Reference in a new issue