List missing constructors in an almost empty match

Actually empty matches are still handled by a different code path
This commit is contained in:
Nadrieril 2019-12-03 16:15:25 +00:00
parent 5a3b7d2055
commit e444346b12
7 changed files with 115 additions and 77 deletions

View File

@ -770,6 +770,10 @@ impl<'tcx> Constructor<'tcx> {
// Returns the set of constructors covered by `self` but not by
// anything in `other_ctors`.
fn subtract_ctors(&self, other_ctors: &Vec<Constructor<'tcx>>) -> Vec<Constructor<'tcx>> {
if other_ctors.is_empty() {
return vec![self.clone()];
}
match self {
// Those constructors can only match themselves.
Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
@ -1614,6 +1618,7 @@ pub fn is_useful<'p, 'tcx>(
v: &PatStack<'p, 'tcx>,
witness_preference: WitnessPreference,
hir_id: HirId,
is_top_level: bool,
) -> Usefulness<'tcx, 'p> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:#?}, {:#?})", matrix, v);
@ -1641,7 +1646,7 @@ pub fn is_useful<'p, 'tcx>(
let mut unreachable_pats = Vec::new();
let mut any_is_useful = false;
for v in vs {
let res = is_useful(cx, &matrix, &v, witness_preference, hir_id);
let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
match res {
Useful(pats) => {
any_is_useful = true;
@ -1741,7 +1746,7 @@ pub fn is_useful<'p, 'tcx>(
} else {
let matrix = matrix.specialize_wildcard();
let v = v.to_tail();
let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id);
let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
// In this case, there's at least one "free"
// constructor that is only matched against by
@ -1770,7 +1775,9 @@ pub fn is_useful<'p, 'tcx>(
// `(<direction-1>, <direction-2>, true)` - we are
// satisfied with `(_, _, true)`. In this case,
// `used_ctors` is empty.
if missing_ctors.all_ctors_are_missing() {
// The exception is: if we are at the top-level, for example in an empty match, we
// prefer reporting the list of constructors instead of just `_`.
if missing_ctors.all_ctors_are_missing() && !is_top_level {
// All constructors are unused. Add a wild pattern
// rather than each individual constructor.
usefulness.apply_wildcard(pcx.ty)
@ -1802,7 +1809,7 @@ fn is_useful_specialized<'p, 'tcx>(
cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false))
.map(|u| u.apply_constructor(cx, &ctor, lty))
.unwrap_or(NotUseful)
}

View File

@ -388,7 +388,7 @@ fn check_arms<'p, 'tcx>(
for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
let v = PatStack::from_pattern(pat);
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
NotUseful => {
match source {
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
@ -476,7 +476,8 @@ fn check_not_useful<'p, 'tcx>(
hir_id: HirId,
) -> Result<(), Vec<super::Pat<'tcx>>> {
let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
match is_useful(cx, matrix, &PatStack::from_pattern(wild_pattern), ConstructWitness, hir_id) {
let v = PatStack::from_pattern(wild_pattern);
match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) {
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
UsefulWithWitness(pats) => Err(if pats.is_empty() {
bug!("Exhaustiveness check returned no witnesses")

View File

@ -3,20 +3,26 @@
#![deny(unreachable_patterns)]
enum Foo {}
struct NonEmptyStruct(bool);
union NonEmptyUnion1 {
struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
foo: (),
}
union NonEmptyUnion2 {
union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
foo: (),
bar: (),
}
enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
Foo(bool), //~ variant not covered
Foo(bool),
//~^ variant not covered
//~| not covered
}
enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
Foo(bool), //~ variant not covered
Bar, //~ variant not covered
Foo(bool),
//~^ variant not covered
//~| not covered
Bar,
//~^ variant not covered
//~| not covered
}
enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
V1, V2, V3, V4, V5,
@ -71,17 +77,17 @@ fn main() {
//~^ ERROR multiple patterns of type `NonEmptyEnum5` are not handled
match_false!(0u8);
//~^ ERROR `_` not covered
//~^ ERROR `0u8..=std::u8::MAX` not covered
match_false!(NonEmptyStruct(true));
//~^ ERROR `_` not covered
//~^ ERROR `NonEmptyStruct(_)` not covered
match_false!((NonEmptyUnion1 { foo: () }));
//~^ ERROR `_` not covered
//~^ ERROR `NonEmptyUnion1 { .. }` not covered
match_false!((NonEmptyUnion2 { foo: () }));
//~^ ERROR `_` not covered
//~^ ERROR `NonEmptyUnion2 { .. }` not covered
match_false!(NonEmptyEnum1::Foo(true));
//~^ ERROR `_` not covered
//~^ ERROR `Foo(_)` not covered
match_false!(NonEmptyEnum2::Foo(true));
//~^ ERROR `_` not covered
//~^ ERROR `Foo(_)` and `Bar` not covered
match_false!(NonEmptyEnum5::V1);
//~^ ERROR `_` not covered
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
}

View File

@ -103,26 +103,26 @@ LL | match_empty!(NonEmptyEnum5::V1);
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `0u8..=std::u8::MAX` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:73:18
|
LL | match_false!(0u8);
| ^^^ pattern `_` not covered
| ^^^ pattern `0u8..=std::u8::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:75:18
|
LL | struct NonEmptyStruct(bool);
| ---------------------------- `NonEmptyStruct` defined here
...
LL | match_false!(NonEmptyStruct(true));
| ^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:77:18
|
LL | / union NonEmptyUnion1 {
@ -131,11 +131,11 @@ LL | | }
| |_- `NonEmptyUnion1` defined here
...
LL | match_false!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:79:18
|
LL | / union NonEmptyUnion2 {
@ -145,38 +145,41 @@ LL | | }
| |_- `NonEmptyUnion2` defined here
...
LL | match_false!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:81:18
|
LL | / enum NonEmptyEnum1 {
LL | | Foo(bool),
| | --- not covered
LL | | }
| |_- `NonEmptyEnum1` defined here
...
LL | match_false!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:83:18
|
LL | / enum NonEmptyEnum2 {
LL | | Foo(bool),
| | --- not covered
LL | | Bar,
| | --- not covered
LL | | }
| |_- `NonEmptyEnum2` defined here
...
LL | match_false!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/match-empty-exhaustive_patterns.rs:85:18
|
LL | / enum NonEmptyEnum5 {
@ -185,7 +188,7 @@ LL | | }
| |_- `NonEmptyEnum5` defined here
...
LL | match_false!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^ 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

View File

@ -2,20 +2,26 @@
#![deny(unreachable_patterns)]
enum Foo {}
struct NonEmptyStruct(bool);
union NonEmptyUnion1 {
struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
foo: (),
}
union NonEmptyUnion2 {
union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
foo: (),
bar: (),
}
enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
Foo(bool), //~ variant not covered
Foo(bool),
//~^ variant not covered
//~| not covered
}
enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
Foo(bool), //~ variant not covered
Bar, //~ variant not covered
Foo(bool),
//~^ variant not covered
//~| not covered
Bar,
//~^ variant not covered
//~| not covered
}
enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
V1, V2, V3, V4, V5,
@ -70,17 +76,17 @@ fn main() {
//~^ ERROR multiple patterns of type `NonEmptyEnum5` are not handled
match_false!(0u8);
//~^ ERROR `_` not covered
//~^ ERROR `0u8..=std::u8::MAX` not covered
match_false!(NonEmptyStruct(true));
//~^ ERROR `_` not covered
//~^ ERROR `NonEmptyStruct(_)` not covered
match_false!((NonEmptyUnion1 { foo: () }));
//~^ ERROR `_` not covered
//~^ ERROR `NonEmptyUnion1 { .. }` not covered
match_false!((NonEmptyUnion2 { foo: () }));
//~^ ERROR `_` not covered
//~^ ERROR `NonEmptyUnion2 { .. }` not covered
match_false!(NonEmptyEnum1::Foo(true));
//~^ ERROR `_` not covered
//~^ ERROR `Foo(_)` not covered
match_false!(NonEmptyEnum2::Foo(true));
//~^ ERROR `_` not covered
//~^ ERROR `Foo(_)` and `Bar` not covered
match_false!(NonEmptyEnum5::V1);
//~^ ERROR `_` not covered
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
}

View File

@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:39:18
--> $DIR/match-empty.rs:45:18
|
LL | enum Foo {}
| ----------- `Foo` defined here
@ -10,7 +10,7 @@ LL | match_false!(x); // Not detected as unreachable nor exhaustive.
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: type `u8` is non-empty
--> $DIR/match-empty.rs:57:18
--> $DIR/match-empty.rs:63:18
|
LL | match_empty!(0u8);
| ^^^
@ -18,7 +18,7 @@ LL | match_empty!(0u8);
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
--> $DIR/match-empty.rs:59:18
--> $DIR/match-empty.rs:65:18
|
LL | match_empty!(NonEmptyStruct(true));
| ^^^^^^^^^^^^^^^^^^^^
@ -26,7 +26,7 @@ LL | match_empty!(NonEmptyStruct(true));
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
--> $DIR/match-empty.rs:61:18
--> $DIR/match-empty.rs:67:18
|
LL | match_empty!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -34,7 +34,7 @@ LL | match_empty!((NonEmptyUnion1 { foo: () }));
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
--> $DIR/match-empty.rs:63:18
--> $DIR/match-empty.rs:69:18
|
LL | match_empty!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -42,11 +42,13 @@ LL | match_empty!((NonEmptyUnion2 { foo: () }));
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: pattern `Foo` of type `NonEmptyEnum1` is not handled
--> $DIR/match-empty.rs:65:18
--> $DIR/match-empty.rs:71:18
|
LL | / enum NonEmptyEnum1 {
LL | | Foo(bool),
| | --- variant not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum1` defined here
...
@ -56,13 +58,17 @@ LL | match_empty!(NonEmptyEnum1::Foo(true));
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: multiple patterns of type `NonEmptyEnum2` are not handled
--> $DIR/match-empty.rs:67:18
--> $DIR/match-empty.rs:73:18
|
LL | / enum NonEmptyEnum2 {
LL | | Foo(bool),
| | --- variant not covered
LL | |
LL | |
LL | | Bar,
| | --- variant not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum2` defined here
...
@ -72,7 +78,7 @@ LL | match_empty!(NonEmptyEnum2::Foo(true));
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: multiple patterns of type `NonEmptyEnum5` are not handled
--> $DIR/match-empty.rs:69:18
--> $DIR/match-empty.rs:75:18
|
LL | / enum NonEmptyEnum5 {
LL | | V1, V2, V3, V4, V5,
@ -84,27 +90,27 @@ LL | match_empty!(NonEmptyEnum5::V1);
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:72:18
error[E0004]: non-exhaustive patterns: `0u8..=std::u8::MAX` not covered
--> $DIR/match-empty.rs:78:18
|
LL | match_false!(0u8);
| ^^^ pattern `_` not covered
| ^^^ pattern `0u8..=std::u8::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:74:18
error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
--> $DIR/match-empty.rs:80:18
|
LL | struct NonEmptyStruct(bool);
| ---------------------------- `NonEmptyStruct` defined here
...
LL | match_false!(NonEmptyStruct(true));
| ^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:76:18
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/match-empty.rs:82:18
|
LL | / union NonEmptyUnion1 {
LL | | foo: (),
@ -112,12 +118,12 @@ LL | | }
| |_- `NonEmptyUnion1` defined here
...
LL | match_false!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:78:18
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/match-empty.rs:84:18
|
LL | / union NonEmptyUnion2 {
LL | | foo: (),
@ -126,39 +132,48 @@ LL | | }
| |_- `NonEmptyUnion2` defined here
...
LL | match_false!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:80:18
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/match-empty.rs:86:18
|
LL | / enum NonEmptyEnum1 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum1` defined here
...
LL | match_false!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:82:18
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/match-empty.rs:88:18
|
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));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:84:18
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/match-empty.rs:90:18
|
LL | / enum NonEmptyEnum5 {
LL | | V1, V2, V3, V4, V5,
@ -166,7 +181,7 @@ LL | | }
| |_- `NonEmptyEnum5` defined here
...
LL | match_false!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ pattern `_` not covered
| ^^^^^^^^^^^^^^^^^ 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

View File

@ -6,11 +6,11 @@ LL | match 0 { 1 => () }
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `std::i32::MIN..=std::i32::MAX` not covered
--> $DIR/match-non-exhaustive.rs:3:11
|
LL | match 0 { 0 if false => () }
| ^ pattern `_` not covered
| ^ pattern `std::i32::MIN..=std::i32::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms