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_infer::infer::InferCtxt;
|
||||||
use rustc_middle::hir::place::ProjectionKind;
|
use rustc_middle::hir::place::ProjectionKind;
|
||||||
use rustc_middle::mir::FakeReadCause;
|
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 rustc_target::abi::VariantIdx;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
@ -845,5 +845,20 @@ fn delegate_consume<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_multivariant_adt(ty: Ty<'tcx>) -> bool {
|
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