mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-17 01:13:11 +00:00
Auto merge of #79670 - Nadrieril:uninhabited-query, r=estebank
Turn type inhabitedness into a query to fix `exhaustive_patterns` perf We measured in https://github.com/rust-lang/rust/pull/79394 that enabling the [`exhaustive_patterns` feature](https://github.com/rust-lang/rust/issues/51085) causes significant perf degradation. It was conjectured that the culprit is type inhabitedness checking, and [I hypothesized](https://github.com/rust-lang/rust/pull/79394#issuecomment-733861149) that turning this computation into a query would solve most of the problem. This PR turns `tcx.is_ty_uninhabited_from` into a query, and I measured a 25% perf gain on the benchmark that stress-tests `exhaustiveness_patterns`. This more than compensates for the 30% perf hit I measured [when creating it](https://github.com/rust-lang/rustc-perf/pull/801). We'll have to measure enabling the feature again, but I suspect this fixes the perf regression entirely. I'd like a perf run on this PR obviously. I made small atomic commits to help reviewing. The first one is just me discovering the "revisions" feature of the testing framework. I believe there's a push to move things out of `rustc_middle` because it's huge. I guess `inhabitedness/mod.rs` could be moved out, but it's quite small. `DefIdForest` might be movable somewhere too. I don't know what the policy is for that. Ping `@camelid` since you were interested in following along `@rustbot` modify labels: +A-exhaustiveness-checking
This commit is contained in:
commit
058a710165
@ -1319,6 +1319,15 @@ rustc_queries! {
|
||||
eval_always
|
||||
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
|
||||
}
|
||||
|
||||
/// Computes the set of modules from which this type is visibly uninhabited.
|
||||
/// To check whether a type is uninhabited at all (not just from a given module), you could
|
||||
/// check whether the forest is empty.
|
||||
query type_uninhabited_from(
|
||||
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
|
||||
) -> ty::inhabitedness::DefIdForest {
|
||||
desc { "computing the inhabitedness of `{:?}`", key }
|
||||
}
|
||||
}
|
||||
|
||||
Other {
|
||||
|
@ -3,6 +3,9 @@ use crate::ty::{DefId, DefIdTree};
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use smallvec::SmallVec;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use DefIdForest::*;
|
||||
|
||||
/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
|
||||
/// if a `DefId` representing a module is contained in the forest then all
|
||||
@ -11,45 +14,77 @@ use std::mem;
|
||||
///
|
||||
/// This is used to represent a set of modules in which a type is visibly
|
||||
/// uninhabited.
|
||||
#[derive(Clone)]
|
||||
pub struct DefIdForest {
|
||||
/// The minimal set of `DefId`s required to represent the whole set.
|
||||
/// If A and B are DefIds in the `DefIdForest`, and A is a descendant
|
||||
/// of B, then only B will be in `root_ids`.
|
||||
/// We use a `SmallVec` here because (for its use for caching inhabitedness)
|
||||
/// it's rare that this will contain even two IDs.
|
||||
root_ids: SmallVec<[DefId; 1]>,
|
||||
///
|
||||
/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
|
||||
/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
|
||||
/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
|
||||
#[derive(Clone, HashStable)]
|
||||
pub enum DefIdForest {
|
||||
Empty,
|
||||
Single(DefId),
|
||||
/// This variant is very rare.
|
||||
/// Invariant: >1 elements
|
||||
/// We use `Arc` because this is used in the output of a query.
|
||||
Multiple(Arc<[DefId]>),
|
||||
}
|
||||
|
||||
/// Tests whether a slice of roots contains a given DefId.
|
||||
#[inline]
|
||||
fn slice_contains(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
|
||||
slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
|
||||
}
|
||||
|
||||
impl<'tcx> DefIdForest {
|
||||
/// Creates an empty forest.
|
||||
pub fn empty() -> DefIdForest {
|
||||
DefIdForest { root_ids: SmallVec::new() }
|
||||
DefIdForest::Empty
|
||||
}
|
||||
|
||||
/// Creates a forest consisting of a single tree representing the entire
|
||||
/// crate.
|
||||
#[inline]
|
||||
pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
|
||||
let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID);
|
||||
DefIdForest::from_id(crate_id.to_def_id())
|
||||
DefIdForest::from_id(tcx.hir().local_def_id(CRATE_HIR_ID).to_def_id())
|
||||
}
|
||||
|
||||
/// Creates a forest containing a `DefId` and all its descendants.
|
||||
pub fn from_id(id: DefId) -> DefIdForest {
|
||||
let mut root_ids = SmallVec::new();
|
||||
root_ids.push(id);
|
||||
DefIdForest { root_ids }
|
||||
DefIdForest::Single(id)
|
||||
}
|
||||
|
||||
fn as_slice(&self) -> &[DefId] {
|
||||
match self {
|
||||
Empty => &[],
|
||||
Single(id) => std::slice::from_ref(id),
|
||||
Multiple(root_ids) => root_ids,
|
||||
}
|
||||
}
|
||||
|
||||
// Only allocates in the rare `Multiple` case.
|
||||
fn from_slice(root_ids: &[DefId]) -> DefIdForest {
|
||||
match root_ids {
|
||||
[] => Empty,
|
||||
[id] => Single(*id),
|
||||
_ => DefIdForest::Multiple(root_ids.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests whether the forest is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.root_ids.is_empty()
|
||||
match self {
|
||||
Empty => true,
|
||||
Single(..) | Multiple(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over the set of roots.
|
||||
fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
|
||||
self.as_slice().iter().copied()
|
||||
}
|
||||
|
||||
/// Tests whether the forest contains a given DefId.
|
||||
pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
|
||||
self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
|
||||
slice_contains(tcx, self.as_slice(), id)
|
||||
}
|
||||
|
||||
/// Calculate the intersection of a collection of forests.
|
||||
@ -58,35 +93,28 @@ impl<'tcx> DefIdForest {
|
||||
I: IntoIterator<Item = DefIdForest>,
|
||||
{
|
||||
let mut iter = iter.into_iter();
|
||||
let mut ret = if let Some(first) = iter.next() {
|
||||
first
|
||||
let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
|
||||
SmallVec::from_slice(first.as_slice())
|
||||
} else {
|
||||
return DefIdForest::full(tcx);
|
||||
};
|
||||
|
||||
let mut next_ret = SmallVec::new();
|
||||
let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
|
||||
let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
|
||||
for next_forest in iter {
|
||||
// No need to continue if the intersection is already empty.
|
||||
if ret.is_empty() {
|
||||
break;
|
||||
if ret.is_empty() || next_forest.is_empty() {
|
||||
return DefIdForest::empty();
|
||||
}
|
||||
|
||||
for id in ret.root_ids.drain(..) {
|
||||
if next_forest.contains(tcx, id) {
|
||||
next_ret.push(id);
|
||||
} else {
|
||||
old_ret.push(id);
|
||||
}
|
||||
}
|
||||
ret.root_ids.extend(old_ret.drain(..));
|
||||
// We keep the elements in `ret` that are also in `next_forest`.
|
||||
next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
|
||||
// We keep the elements in `next_forest` that are also in `ret`.
|
||||
next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
|
||||
|
||||
next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));
|
||||
|
||||
mem::swap(&mut next_ret, &mut ret.root_ids);
|
||||
next_ret.drain(..);
|
||||
mem::swap(&mut next_ret, &mut ret);
|
||||
next_ret.clear();
|
||||
}
|
||||
ret
|
||||
DefIdForest::from_slice(&ret)
|
||||
}
|
||||
|
||||
/// Calculate the union of a collection of forests.
|
||||
@ -94,20 +122,26 @@ impl<'tcx> DefIdForest {
|
||||
where
|
||||
I: IntoIterator<Item = DefIdForest>,
|
||||
{
|
||||
let mut ret = DefIdForest::empty();
|
||||
let mut next_ret = SmallVec::new();
|
||||
let mut ret: SmallVec<[_; 1]> = SmallVec::new();
|
||||
let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
|
||||
for next_forest in iter {
|
||||
next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id)));
|
||||
// Union with the empty set is a no-op.
|
||||
if next_forest.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for id in next_forest.root_ids {
|
||||
if !next_ret.contains(&id) {
|
||||
// We add everything in `ret` that is not in `next_forest`.
|
||||
next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
|
||||
// We add everything in `next_forest` that we haven't added yet.
|
||||
for id in next_forest.iter() {
|
||||
if !slice_contains(tcx, &next_ret, id) {
|
||||
next_ret.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
mem::swap(&mut next_ret, &mut ret.root_ids);
|
||||
next_ret.drain(..);
|
||||
mem::swap(&mut next_ret, &mut ret);
|
||||
next_ret.clear();
|
||||
}
|
||||
ret
|
||||
DefIdForest::from_slice(&ret)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ use crate::ty::TyKind::*;
|
||||
use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
|
||||
use crate::ty::{AdtKind, Visibility};
|
||||
use crate::ty::{DefId, SubstsRef};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
|
||||
mod def_id_forest;
|
||||
|
||||
@ -187,34 +186,46 @@ impl<'tcx> FieldDef {
|
||||
|
||||
impl<'tcx> TyS<'tcx> {
|
||||
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
|
||||
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
|
||||
match *self.kind() {
|
||||
Adt(def, substs) => {
|
||||
ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env))
|
||||
}
|
||||
|
||||
Never => DefIdForest::full(tcx),
|
||||
|
||||
Tuple(ref tys) => DefIdForest::union(
|
||||
tcx,
|
||||
tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
|
||||
),
|
||||
|
||||
Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
|
||||
Some(0) | None => DefIdForest::empty(),
|
||||
// If the array is definitely non-empty, it's uninhabited if
|
||||
// the type of its elements is uninhabited.
|
||||
Some(1..) => ty.uninhabited_from(tcx, param_env),
|
||||
},
|
||||
|
||||
// References to uninitialised memory are valid for any type, including
|
||||
// uninhabited types, in unsafe code, so we treat all references as
|
||||
// inhabited.
|
||||
// The precise semantics of inhabitedness with respect to references is currently
|
||||
// undecided.
|
||||
Ref(..) => DefIdForest::empty(),
|
||||
|
||||
_ => DefIdForest::empty(),
|
||||
}
|
||||
fn uninhabited_from(
|
||||
&'tcx self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> DefIdForest {
|
||||
tcx.type_uninhabited_from(param_env.and(self))
|
||||
}
|
||||
}
|
||||
|
||||
// Query provider for `type_uninhabited_from`.
|
||||
pub(crate) fn type_uninhabited_from<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> DefIdForest {
|
||||
let ty = key.value;
|
||||
let param_env = key.param_env;
|
||||
match *ty.kind() {
|
||||
Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
|
||||
|
||||
Never => DefIdForest::full(tcx),
|
||||
|
||||
Tuple(ref tys) => DefIdForest::union(
|
||||
tcx,
|
||||
tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
|
||||
),
|
||||
|
||||
Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
|
||||
Some(0) | None => DefIdForest::empty(),
|
||||
// If the array is definitely non-empty, it's uninhabited if
|
||||
// the type of its elements is uninhabited.
|
||||
Some(1..) => ty.uninhabited_from(tcx, param_env),
|
||||
},
|
||||
|
||||
// References to uninitialised memory are valid for any type, including
|
||||
// uninhabited types, in unsafe code, so we treat all references as
|
||||
// inhabited.
|
||||
// The precise semantics of inhabitedness with respect to references is currently
|
||||
// undecided.
|
||||
Ref(..) => DefIdForest::empty(),
|
||||
|
||||
_ => DefIdForest::empty(),
|
||||
}
|
||||
}
|
||||
|
@ -3155,6 +3155,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||
*providers = ty::query::Providers {
|
||||
trait_impls_of: trait_def::trait_impls_of_provider,
|
||||
all_local_trait_impls: trait_def::all_local_trait_impls,
|
||||
type_uninhabited_from: inhabitedness::type_uninhabited_from,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
@ -1,2 +1,10 @@
|
||||
#![crate_type = "rlib"]
|
||||
pub enum EmptyForeignEnum {}
|
||||
|
||||
pub struct VisiblyUninhabitedForeignStruct {
|
||||
pub field: EmptyForeignEnum,
|
||||
}
|
||||
|
||||
pub struct SecretlyUninhabitedForeignStruct {
|
||||
_priv: EmptyForeignEnum,
|
||||
}
|
||||
|
@ -1,94 +1,94 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:52:9
|
||||
--> $DIR/empty-match.rs:37:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:5:9
|
||||
--> $DIR/empty-match.rs:8:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:55:9
|
||||
--> $DIR/empty-match.rs:40:9
|
||||
|
|
||||
LL | _ if false => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:62:9
|
||||
--> $DIR/empty-match.rs:47:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:65:9
|
||||
--> $DIR/empty-match.rs:50:9
|
||||
|
|
||||
LL | _ if false => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:72:9
|
||||
--> $DIR/empty-match.rs:57:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:75:9
|
||||
--> $DIR/empty-match.rs:60:9
|
||||
|
|
||||
LL | _ if false => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:82:9
|
||||
|
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:86:9
|
||||
|
|
||||
LL | Some(_) => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `u8` is non-empty
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:89:18
|
||||
--> $DIR/empty-match.rs:78:20
|
||||
|
|
||||
LL | match_empty!(0u8);
|
||||
| ^^^
|
||||
LL | match_no_arms!(0u8);
|
||||
| ^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `u8`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:91:18
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
|
||||
--> $DIR/empty-match.rs:79:20
|
||||
|
|
||||
LL | struct NonEmptyStruct(bool);
|
||||
| ---------------------------- `NonEmptyStruct` defined here
|
||||
LL | struct NonEmptyStruct1;
|
||||
| ----------------------- `NonEmptyStruct1` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyStruct(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
LL | match_no_arms!(NonEmptyStruct1);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyStruct`
|
||||
= note: the matched value is of type `NonEmptyStruct1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
|
||||
--> $DIR/empty-match.rs:80:20
|
||||
|
|
||||
LL | struct NonEmptyStruct2(bool);
|
||||
| ----------------------------- `NonEmptyStruct2` defined here
|
||||
...
|
||||
LL | match_no_arms!(NonEmptyStruct2(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyStruct2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:93:18
|
||||
--> $DIR/empty-match.rs:81:20
|
||||
|
|
||||
LL | / union NonEmptyUnion1 {
|
||||
LL | | foo: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion1` defined here
|
||||
...
|
||||
LL | match_empty!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyUnion1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:95:18
|
||||
--> $DIR/empty-match.rs:82:20
|
||||
|
|
||||
LL | / union NonEmptyUnion2 {
|
||||
LL | | foo: (),
|
||||
@ -96,101 +96,107 @@ LL | | bar: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion2` defined here
|
||||
...
|
||||
LL | match_empty!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyUnion2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:97:18
|
||||
--> $DIR/empty-match.rs:83:20
|
||||
|
|
||||
LL | / enum NonEmptyEnum1 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum1` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
||||
LL | match_no_arms!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:99:18
|
||||
--> $DIR/empty-match.rs:84:20
|
||||
|
|
||||
LL | / enum NonEmptyEnum2 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | Bar,
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum2` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
|
||||
LL | match_no_arms!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:101:18
|
||||
--> $DIR/empty-match.rs:85:20
|
||||
|
|
||||
LL | / enum NonEmptyEnum5 {
|
||||
LL | | V1, V2, V3, V4, V5,
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum5` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
|
||||
LL | match_no_arms!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:104:18
|
||||
--> $DIR/empty-match.rs:87:24
|
||||
|
|
||||
LL | match_false!(0u8);
|
||||
| ^^^ pattern `_` not covered
|
||||
LL | match_guarded_arm!(0u8);
|
||||
| ^^^ 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 `u8`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:106:18
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
|
||||
--> $DIR/empty-match.rs:88:24
|
||||
|
|
||||
LL | struct NonEmptyStruct(bool);
|
||||
| ---------------------------- `NonEmptyStruct` defined here
|
||||
LL | struct NonEmptyStruct1;
|
||||
| ----------------------- `NonEmptyStruct1` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyStruct(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
|
||||
LL | match_guarded_arm!(NonEmptyStruct1);
|
||||
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` 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 `NonEmptyStruct`
|
||||
= note: the matched value is of type `NonEmptyStruct1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
|
||||
--> $DIR/empty-match.rs:89:24
|
||||
|
|
||||
LL | struct NonEmptyStruct2(bool);
|
||||
| ----------------------------- `NonEmptyStruct2` defined here
|
||||
...
|
||||
LL | match_guarded_arm!(NonEmptyStruct2(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` 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 `NonEmptyStruct2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:108:18
|
||||
--> $DIR/empty-match.rs:90:24
|
||||
|
|
||||
LL | / union NonEmptyUnion1 {
|
||||
LL | | foo: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion1` defined here
|
||||
...
|
||||
LL | match_false!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
|
||||
LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` 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 `NonEmptyUnion1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:110:18
|
||||
--> $DIR/empty-match.rs:91:24
|
||||
|
|
||||
LL | / union NonEmptyUnion2 {
|
||||
LL | | foo: (),
|
||||
@ -198,60 +204,54 @@ LL | | bar: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion2` defined here
|
||||
...
|
||||
LL | match_false!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
|
||||
LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` 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 `NonEmptyUnion2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:112:18
|
||||
--> $DIR/empty-match.rs:92:24
|
||||
|
|
||||
LL | / enum NonEmptyEnum1 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum1` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
||||
LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:114:18
|
||||
--> $DIR/empty-match.rs:93:24
|
||||
|
|
||||
LL | / enum NonEmptyEnum2 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | Bar,
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum2` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
|
||||
LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
|
||||
--> $DIR/match-empty-exhaustive_patterns.rs:116:18
|
||||
--> $DIR/empty-match.rs:94:24
|
||||
|
|
||||
LL | / enum NonEmptyEnum5 {
|
||||
LL | | V1, V2, V3, V4, V5,
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum5` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
|
||||
LL | match_guarded_arm!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`
|
@ -1,82 +1,94 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty.rs:51:9
|
||||
--> $DIR/empty-match.rs:37:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/match-empty.rs:4:9
|
||||
--> $DIR/empty-match.rs:8:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty.rs:54:9
|
||||
--> $DIR/empty-match.rs:40:9
|
||||
|
|
||||
LL | _ if false => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty.rs:61:9
|
||||
--> $DIR/empty-match.rs:47:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty.rs:64:9
|
||||
--> $DIR/empty-match.rs:50:9
|
||||
|
|
||||
LL | _ if false => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty.rs:71:9
|
||||
--> $DIR/empty-match.rs:57:9
|
||||
|
|
||||
LL | _ => {},
|
||||
| ^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/match-empty.rs:74:9
|
||||
--> $DIR/empty-match.rs:60:9
|
||||
|
|
||||
LL | _ if false => {},
|
||||
| ^
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `u8` is non-empty
|
||||
--> $DIR/match-empty.rs:89:18
|
||||
--> $DIR/empty-match.rs:78:20
|
||||
|
|
||||
LL | match_empty!(0u8);
|
||||
| ^^^
|
||||
LL | match_no_arms!(0u8);
|
||||
| ^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `u8`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
|
||||
--> $DIR/match-empty.rs:91:18
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
|
||||
--> $DIR/empty-match.rs:79:20
|
||||
|
|
||||
LL | struct NonEmptyStruct(bool);
|
||||
| ---------------------------- `NonEmptyStruct` defined here
|
||||
LL | struct NonEmptyStruct1;
|
||||
| ----------------------- `NonEmptyStruct1` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyStruct(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
LL | match_no_arms!(NonEmptyStruct1);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyStruct`
|
||||
= note: the matched value is of type `NonEmptyStruct1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
|
||||
--> $DIR/empty-match.rs:80:20
|
||||
|
|
||||
LL | struct NonEmptyStruct2(bool);
|
||||
| ----------------------------- `NonEmptyStruct2` defined here
|
||||
...
|
||||
LL | match_no_arms!(NonEmptyStruct2(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyStruct2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
|
||||
--> $DIR/match-empty.rs:93:18
|
||||
--> $DIR/empty-match.rs:81:20
|
||||
|
|
||||
LL | / union NonEmptyUnion1 {
|
||||
LL | | foo: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion1` defined here
|
||||
...
|
||||
LL | match_empty!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyUnion1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
|
||||
--> $DIR/match-empty.rs:95:18
|
||||
--> $DIR/empty-match.rs:82:20
|
||||
|
|
||||
LL | / union NonEmptyUnion2 {
|
||||
LL | | foo: (),
|
||||
@ -84,101 +96,107 @@ LL | | bar: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion2` defined here
|
||||
...
|
||||
LL | match_empty!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||
= note: the matched value is of type `NonEmptyUnion2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
|
||||
--> $DIR/match-empty.rs:97:18
|
||||
--> $DIR/empty-match.rs:83:20
|
||||
|
|
||||
LL | / enum NonEmptyEnum1 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum1` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
||||
LL | match_no_arms!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
|
||||
--> $DIR/match-empty.rs:99:18
|
||||
--> $DIR/empty-match.rs:84:20
|
||||
|
|
||||
LL | / enum NonEmptyEnum2 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | Bar,
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum2` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
|
||||
LL | match_no_arms!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
|
||||
--> $DIR/match-empty.rs:101:18
|
||||
--> $DIR/empty-match.rs:85:20
|
||||
|
|
||||
LL | / enum NonEmptyEnum5 {
|
||||
LL | | V1, V2, V3, V4, V5,
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum5` defined here
|
||||
...
|
||||
LL | match_empty!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
|
||||
LL | match_no_arms!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/match-empty.rs:104:18
|
||||
--> $DIR/empty-match.rs:87:24
|
||||
|
|
||||
LL | match_false!(0u8);
|
||||
| ^^^ pattern `_` not covered
|
||||
LL | match_guarded_arm!(0u8);
|
||||
| ^^^ 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 `u8`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
|
||||
--> $DIR/match-empty.rs:106:18
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
|
||||
--> $DIR/empty-match.rs:88:24
|
||||
|
|
||||
LL | struct NonEmptyStruct(bool);
|
||||
| ---------------------------- `NonEmptyStruct` defined here
|
||||
LL | struct NonEmptyStruct1;
|
||||
| ----------------------- `NonEmptyStruct1` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyStruct(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
|
||||
LL | match_guarded_arm!(NonEmptyStruct1);
|
||||
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` 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 `NonEmptyStruct`
|
||||
= note: the matched value is of type `NonEmptyStruct1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
|
||||
--> $DIR/empty-match.rs:89:24
|
||||
|
|
||||
LL | struct NonEmptyStruct2(bool);
|
||||
| ----------------------------- `NonEmptyStruct2` defined here
|
||||
...
|
||||
LL | match_guarded_arm!(NonEmptyStruct2(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` 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 `NonEmptyStruct2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
|
||||
--> $DIR/match-empty.rs:108:18
|
||||
--> $DIR/empty-match.rs:90:24
|
||||
|
|
||||
LL | / union NonEmptyUnion1 {
|
||||
LL | | foo: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion1` defined here
|
||||
...
|
||||
LL | match_false!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
|
||||
LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` 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 `NonEmptyUnion1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
|
||||
--> $DIR/match-empty.rs:110:18
|
||||
--> $DIR/empty-match.rs:91:24
|
||||
|
|
||||
LL | / union NonEmptyUnion2 {
|
||||
LL | | foo: (),
|
||||
@ -186,64 +204,58 @@ LL | | bar: (),
|
||||
LL | | }
|
||||
| |_- `NonEmptyUnion2` defined here
|
||||
...
|
||||
LL | match_false!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
|
||||
LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` 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 `NonEmptyUnion2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
|
||||
--> $DIR/match-empty.rs:112:18
|
||||
--> $DIR/empty-match.rs:92:24
|
||||
|
|
||||
LL | / enum NonEmptyEnum1 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum1` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
||||
LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
|
||||
--> $DIR/match-empty.rs:114:18
|
||||
--> $DIR/empty-match.rs:93:24
|
||||
|
|
||||
LL | / enum NonEmptyEnum2 {
|
||||
LL | | Foo(bool),
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | Bar,
|
||||
| | --- not covered
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum2` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
|
||||
LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
|
||||
--> $DIR/match-empty.rs:116:18
|
||||
--> $DIR/empty-match.rs:94:24
|
||||
|
|
||||
LL | / enum NonEmptyEnum5 {
|
||||
LL | | V1, V2, V3, V4, V5,
|
||||
LL | | }
|
||||
| |_- `NonEmptyEnum5` defined here
|
||||
...
|
||||
LL | match_false!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
|
||||
LL | match_guarded_arm!(NonEmptyEnum5::V1);
|
||||
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
error: aborting due to 22 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
95
src/test/ui/pattern/usefulness/empty-match.rs
Normal file
95
src/test/ui/pattern/usefulness/empty-match.rs
Normal file
@ -0,0 +1,95 @@
|
||||
// aux-build:empty.rs
|
||||
// revisions: normal exhaustive_patterns
|
||||
//
|
||||
// This tests a match with no arms on various types.
|
||||
#![feature(never_type)]
|
||||
#![feature(never_type_fallback)]
|
||||
#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
extern crate empty;
|
||||
|
||||
enum EmptyEnum {}
|
||||
|
||||
struct NonEmptyStruct1;
|
||||
struct NonEmptyStruct2(bool);
|
||||
union NonEmptyUnion1 {
|
||||
foo: (),
|
||||
}
|
||||
union NonEmptyUnion2 {
|
||||
foo: (),
|
||||
bar: (),
|
||||
}
|
||||
enum NonEmptyEnum1 {
|
||||
Foo(bool),
|
||||
}
|
||||
enum NonEmptyEnum2 {
|
||||
Foo(bool),
|
||||
Bar,
|
||||
}
|
||||
enum NonEmptyEnum5 {
|
||||
V1, V2, V3, V4, V5,
|
||||
}
|
||||
|
||||
fn empty_enum(x: EmptyEnum) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn never(x: !) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! match_no_arms {
|
||||
($e:expr) => {
|
||||
match $e {}
|
||||
};
|
||||
}
|
||||
macro_rules! match_guarded_arm {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
_ if false => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
|
||||
match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty
|
||||
match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty
|
||||
match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty
|
||||
match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty
|
||||
match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
|
||||
match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
|
||||
match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
|
||||
|
||||
match_guarded_arm!(0u8); //~ ERROR `_` not covered
|
||||
match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered
|
||||
match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered
|
||||
match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered
|
||||
match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered
|
||||
match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
|
||||
match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
|
||||
match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#![feature(exclusive_range_pattern)]
|
||||
|
||||
macro_rules! m {
|
||||
($s:expr, $($t:tt)+) => {
|
||||
match $s { $($t)+ => {} }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match 0usize {
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
0 ..= usize::MAX => {}
|
||||
}
|
||||
|
||||
match 0isize {
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
isize::MIN ..= isize::MAX => {}
|
||||
}
|
||||
|
||||
m!(0usize, 0..=usize::MAX);
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
m!(0usize, 0..5 | 5..=usize::MAX);
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
m!(0usize, 0..usize::MAX | usize::MAX);
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
|
||||
m!(0isize, isize::MIN..=isize::MAX);
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
m!(0isize, isize::MIN..5 | 5..=isize::MAX);
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
m!(0isize, isize::MIN..isize::MAX | isize::MAX);
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
m!((0isize, true), (isize::MIN..5, true)
|
||||
| (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
|
||||
//~^^ ERROR non-exhaustive patterns
|
||||
|
||||
match 0isize {
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
isize::MIN ..= -1 => {}
|
||||
0 => {}
|
||||
1 ..= isize::MAX => {}
|
||||
}
|
||||
|
||||
match 7usize {}
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
|
||||
--> $DIR/pointer-sized-int-allow.rs:36:11
|
||||
--> $DIR/pointer-sized-int.rs:48:11
|
||||
|
|
||||
LL | match 7usize {}
|
||||
| ^^^^^^
|
@ -1,5 +1,5 @@
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:10:11
|
||||
--> $DIR/pointer-sized-int.rs:12:11
|
||||
|
|
||||
LL | match 0usize {
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -10,7 +10,7 @@ LL | match 0usize {
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:15:11
|
||||
--> $DIR/pointer-sized-int.rs:17:11
|
||||
|
|
||||
LL | match 0isize {
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -21,7 +21,7 @@ LL | match 0isize {
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:20:8
|
||||
--> $DIR/pointer-sized-int.rs:22:8
|
||||
|
|
||||
LL | m!(0usize, 0..=usize::MAX);
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -32,7 +32,7 @@ LL | m!(0usize, 0..=usize::MAX);
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:22:8
|
||||
--> $DIR/pointer-sized-int.rs:24:8
|
||||
|
|
||||
LL | m!(0usize, 0..5 | 5..=usize::MAX);
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -43,7 +43,7 @@ LL | m!(0usize, 0..5 | 5..=usize::MAX);
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:24:8
|
||||
--> $DIR/pointer-sized-int.rs:26:8
|
||||
|
|
||||
LL | m!(0usize, 0..usize::MAX | usize::MAX);
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -54,7 +54,7 @@ LL | m!(0usize, 0..usize::MAX | usize::MAX);
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:26:8
|
||||
--> $DIR/pointer-sized-int.rs:28:8
|
||||
|
|
||||
LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
|
||||
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||
@ -63,7 +63,7 @@ LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::
|
||||
= note: the matched value is of type `(usize, bool)`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:29:8
|
||||
--> $DIR/pointer-sized-int.rs:31:8
|
||||
|
|
||||
LL | m!(0isize, isize::MIN..=isize::MAX);
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -74,7 +74,7 @@ LL | m!(0isize, isize::MIN..=isize::MAX);
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:31:8
|
||||
--> $DIR/pointer-sized-int.rs:33:8
|
||||
|
|
||||
LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -85,7 +85,7 @@ LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:33:8
|
||||
--> $DIR/pointer-sized-int.rs:35:8
|
||||
|
|
||||
LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -96,7 +96,7 @@ LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:35:8
|
||||
--> $DIR/pointer-sized-int.rs:37:8
|
||||
|
|
||||
LL | m!((0isize, true), (isize::MIN..5, true)
|
||||
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||
@ -105,7 +105,7 @@ LL | m!((0isize, true), (isize::MIN..5, true)
|
||||
= note: the matched value is of type `(isize, bool)`
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/pointer-sized-int-deny.rs:39:11
|
||||
--> $DIR/pointer-sized-int.rs:41:11
|
||||
|
|
||||
LL | match 0isize {
|
||||
| ^^^^^^ pattern `_` not covered
|
||||
@ -116,7 +116,7 @@ LL | match 0isize {
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
|
||||
--> $DIR/pointer-sized-int-deny.rs:46:11
|
||||
--> $DIR/pointer-sized-int.rs:48:11
|
||||
|
|
||||
LL | match 7usize {}
|
||||
| ^^^^^^
|
@ -1,5 +1,6 @@
|
||||
#![feature(precise_pointer_size_matching)]
|
||||
// revisions: allow deny
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![cfg_attr(allow, feature(precise_pointer_size_matching))]
|
||||
|
||||
macro_rules! m {
|
||||
($s:expr, $($t:tt)+) => {
|
||||
@ -9,25 +10,36 @@ macro_rules! m {
|
||||
|
||||
fn main() {
|
||||
match 0usize {
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
0 ..= usize::MAX => {}
|
||||
}
|
||||
|
||||
match 0isize {
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
isize::MIN ..= isize::MAX => {}
|
||||
}
|
||||
|
||||
m!(0usize, 0..=usize::MAX);
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
m!(0usize, 0..5 | 5..=usize::MAX);
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
m!(0usize, 0..usize::MAX | usize::MAX);
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
|
||||
m!(0isize, isize::MIN..=isize::MAX);
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
m!(0isize, isize::MIN..5 | 5..=isize::MAX);
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
m!(0isize, isize::MIN..isize::MAX | isize::MAX);
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
m!((0isize, true), (isize::MIN..5, true)
|
||||
| (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
|
||||
//[deny]~^^ ERROR non-exhaustive patterns
|
||||
|
||||
match 0isize {
|
||||
//[deny]~^ ERROR non-exhaustive patterns
|
||||
isize::MIN ..= -1 => {}
|
||||
0 => {}
|
||||
1 ..= isize::MAX => {}
|
@ -1,118 +0,0 @@
|
||||
// aux-build:empty.rs
|
||||
#![feature(never_type)]
|
||||
#![feature(never_type_fallback)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
extern crate empty;
|
||||
|
||||
enum EmptyEnum {}
|
||||
|
||||
struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
|
||||
union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
|
||||
foo: (),
|
||||
}
|
||||
union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
|
||||
foo: (),
|
||||
bar: (),
|
||||
}
|
||||
enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
|
||||
Foo(bool),
|
||||
//~^ not covered
|
||||
//~| not covered
|
||||
}
|
||||
enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
|
||||
Foo(bool),
|
||||
//~^ not covered
|
||||
//~| not covered
|
||||
Bar,
|
||||
//~^ not covered
|
||||
//~| not covered
|
||||
}
|
||||
enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
|
||||
V1, V2, V3, V4, V5,
|
||||
}
|
||||
|
||||
macro_rules! match_empty {
|
||||
($e:expr) => {
|
||||
match $e {}
|
||||
};
|
||||
}
|
||||
macro_rules! match_false {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
_ if false => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn empty_enum(x: EmptyEnum) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn never(x: !) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match None::<!> {
|
||||
None => {}
|
||||
Some(_) => {} //~ ERROR unreachable pattern
|
||||
}
|
||||
match None::<EmptyEnum> {
|
||||
None => {}
|
||||
Some(_) => {} //~ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match_empty!(0u8);
|
||||
//~^ ERROR type `u8` is non-empty
|
||||
match_empty!(NonEmptyStruct(true));
|
||||
//~^ ERROR type `NonEmptyStruct` is non-empty
|
||||
match_empty!((NonEmptyUnion1 { foo: () }));
|
||||
//~^ ERROR type `NonEmptyUnion1` is non-empty
|
||||
match_empty!((NonEmptyUnion2 { foo: () }));
|
||||
//~^ ERROR type `NonEmptyUnion2` is non-empty
|
||||
match_empty!(NonEmptyEnum1::Foo(true));
|
||||
//~^ ERROR `Foo(_)` not covered
|
||||
match_empty!(NonEmptyEnum2::Foo(true));
|
||||
//~^ ERROR `Foo(_)` and `Bar` not covered
|
||||
match_empty!(NonEmptyEnum5::V1);
|
||||
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
|
||||
|
||||
match_false!(0u8);
|
||||
//~^ ERROR `_` not covered
|
||||
match_false!(NonEmptyStruct(true));
|
||||
//~^ ERROR `NonEmptyStruct(_)` not covered
|
||||
match_false!((NonEmptyUnion1 { foo: () }));
|
||||
//~^ ERROR `NonEmptyUnion1 { .. }` not covered
|
||||
match_false!((NonEmptyUnion2 { foo: () }));
|
||||
//~^ ERROR `NonEmptyUnion2 { .. }` not covered
|
||||
match_false!(NonEmptyEnum1::Foo(true));
|
||||
//~^ ERROR `Foo(_)` not covered
|
||||
match_false!(NonEmptyEnum2::Foo(true));
|
||||
//~^ ERROR `Foo(_)` and `Bar` not covered
|
||||
match_false!(NonEmptyEnum5::V1);
|
||||
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
// aux-build:empty.rs
|
||||
#![feature(never_type)]
|
||||
#![feature(never_type_fallback)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
extern crate empty;
|
||||
|
||||
enum EmptyEnum {}
|
||||
|
||||
struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
|
||||
union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
|
||||
foo: (),
|
||||
}
|
||||
union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
|
||||
foo: (),
|
||||
bar: (),
|
||||
}
|
||||
enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
|
||||
Foo(bool),
|
||||
//~^ not covered
|
||||
//~| not covered
|
||||
}
|
||||
enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
|
||||
Foo(bool),
|
||||
//~^ not covered
|
||||
//~| not covered
|
||||
Bar,
|
||||
//~^ not covered
|
||||
//~| not covered
|
||||
}
|
||||
enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
|
||||
V1, V2, V3, V4, V5,
|
||||
}
|
||||
|
||||
macro_rules! match_empty {
|
||||
($e:expr) => {
|
||||
match $e {}
|
||||
};
|
||||
}
|
||||
macro_rules! match_false {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
_ if false => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn empty_enum(x: EmptyEnum) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn never(x: !) {
|
||||
match x {} // ok
|
||||
match x {
|
||||
_ => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
match x {
|
||||
_ if false => {}, //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable.
|
||||
match None::<!> {
|
||||
None => {}
|
||||
Some(_) => {}
|
||||
}
|
||||
match None::<EmptyEnum> {
|
||||
None => {}
|
||||
Some(_) => {}
|
||||
}
|
||||
|
||||
match_empty!(0u8);
|
||||
//~^ ERROR type `u8` is non-empty
|
||||
match_empty!(NonEmptyStruct(true));
|
||||
//~^ ERROR type `NonEmptyStruct` is non-empty
|
||||
match_empty!((NonEmptyUnion1 { foo: () }));
|
||||
//~^ ERROR type `NonEmptyUnion1` is non-empty
|
||||
match_empty!((NonEmptyUnion2 { foo: () }));
|
||||
//~^ ERROR type `NonEmptyUnion2` is non-empty
|
||||
match_empty!(NonEmptyEnum1::Foo(true));
|
||||
//~^ ERROR `Foo(_)` not covered
|
||||
match_empty!(NonEmptyEnum2::Foo(true));
|
||||
//~^ ERROR `Foo(_)` and `Bar` not covered
|
||||
match_empty!(NonEmptyEnum5::V1);
|
||||
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
|
||||
|
||||
match_false!(0u8);
|
||||
//~^ ERROR `_` not covered
|
||||
match_false!(NonEmptyStruct(true));
|
||||
//~^ ERROR `NonEmptyStruct(_)` not covered
|
||||
match_false!((NonEmptyUnion1 { foo: () }));
|
||||
//~^ ERROR `NonEmptyUnion1 { .. }` not covered
|
||||
match_false!((NonEmptyUnion2 { foo: () }));
|
||||
//~^ ERROR `NonEmptyUnion2 { .. }` not covered
|
||||
match_false!(NonEmptyEnum1::Foo(true));
|
||||
//~^ ERROR `Foo(_)` not covered
|
||||
match_false!(NonEmptyEnum2::Foo(true));
|
||||
//~^ ERROR `Foo(_)` and `Bar` not covered
|
||||
match_false!(NonEmptyEnum5::V1);
|
||||
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
|
||||
}
|
143
src/test/ui/pattern/usefulness/uninhabited.rs
Normal file
143
src/test/ui/pattern/usefulness/uninhabited.rs
Normal file
@ -0,0 +1,143 @@
|
||||
// check-pass
|
||||
// aux-build:empty.rs
|
||||
//
|
||||
// This tests plays with matching and uninhabited types. This also serves as a test for the
|
||||
// `tcx.is_ty_uninhabited_from()` function.
|
||||
#![feature(never_type)]
|
||||
#![feature(never_type_fallback)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
macro_rules! assert_empty {
|
||||
($ty:ty) => {
|
||||
const _: () = {
|
||||
fn assert_empty(x: $ty) {
|
||||
match x {}
|
||||
match Some(x) {
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
macro_rules! assert_non_empty {
|
||||
($ty:ty) => {
|
||||
const _: () = {
|
||||
fn assert_non_empty(x: $ty) {
|
||||
match x {
|
||||
_ => {}
|
||||
}
|
||||
match Some(x) {
|
||||
None => {}
|
||||
Some(_) => {}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
extern crate empty;
|
||||
assert_empty!(empty::EmptyForeignEnum);
|
||||
assert_empty!(empty::VisiblyUninhabitedForeignStruct);
|
||||
assert_non_empty!(empty::SecretlyUninhabitedForeignStruct);
|
||||
|
||||
enum Void {}
|
||||
assert_empty!(Void);
|
||||
|
||||
enum Enum2 {
|
||||
Foo(Void),
|
||||
Bar(!),
|
||||
}
|
||||
assert_empty!(Enum2);
|
||||
|
||||
enum Enum3 {
|
||||
Foo(Void),
|
||||
Bar {
|
||||
x: u64,
|
||||
y: !,
|
||||
},
|
||||
}
|
||||
assert_empty!(Enum3);
|
||||
|
||||
enum Enum4 {
|
||||
Foo(u64),
|
||||
Bar(!),
|
||||
}
|
||||
assert_non_empty!(Enum4);
|
||||
|
||||
struct Struct1(empty::EmptyForeignEnum);
|
||||
assert_empty!(Struct1);
|
||||
|
||||
struct Struct2 {
|
||||
x: u64,
|
||||
y: !,
|
||||
}
|
||||
assert_empty!(Struct2);
|
||||
|
||||
union Union {
|
||||
foo: !,
|
||||
}
|
||||
assert_non_empty!(Union);
|
||||
|
||||
assert_empty!((!, String));
|
||||
|
||||
assert_non_empty!(&'static !);
|
||||
assert_non_empty!(&'static Struct1);
|
||||
assert_non_empty!(&'static &'static &'static !);
|
||||
|
||||
assert_empty!([!; 1]);
|
||||
assert_empty!([Void; 2]);
|
||||
assert_non_empty!([!; 0]);
|
||||
assert_non_empty!(&'static [!]);
|
||||
|
||||
mod visibility {
|
||||
/// This struct can only be seen to be inhabited in modules `b`, `c` or `d`, because otherwise
|
||||
/// the uninhabitedness of both `SecretlyUninhabited` structs is hidden.
|
||||
struct SometimesEmptyStruct {
|
||||
x: a::b::SecretlyUninhabited,
|
||||
y: c::AlsoSecretlyUninhabited,
|
||||
}
|
||||
|
||||
/// This enum can only be seen to be inhabited in module `d`.
|
||||
enum SometimesEmptyEnum {
|
||||
X(c::AlsoSecretlyUninhabited),
|
||||
Y(c::d::VerySecretlyUninhabited),
|
||||
}
|
||||
|
||||
mod a {
|
||||
use super::*;
|
||||
pub mod b {
|
||||
use super::*;
|
||||
pub struct SecretlyUninhabited {
|
||||
_priv: !,
|
||||
}
|
||||
assert_empty!(SometimesEmptyStruct);
|
||||
}
|
||||
|
||||
assert_non_empty!(SometimesEmptyStruct);
|
||||
assert_non_empty!(SometimesEmptyEnum);
|
||||
}
|
||||
|
||||
mod c {
|
||||
use super::*;
|
||||
pub struct AlsoSecretlyUninhabited {
|
||||
_priv: ::Struct1,
|
||||
}
|
||||
assert_empty!(SometimesEmptyStruct);
|
||||
assert_non_empty!(SometimesEmptyEnum);
|
||||
|
||||
pub mod d {
|
||||
use super::*;
|
||||
pub struct VerySecretlyUninhabited {
|
||||
_priv: !,
|
||||
}
|
||||
assert_empty!(SometimesEmptyStruct);
|
||||
assert_empty!(SometimesEmptyEnum);
|
||||
}
|
||||
}
|
||||
|
||||
assert_non_empty!(SometimesEmptyStruct);
|
||||
assert_non_empty!(SometimesEmptyEnum);
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user