Keep all witnesses of non-exhaustiveness
This commit is contained in:
parent
d7a6365b77
commit
2d71a0b9b9
9 changed files with 51 additions and 39 deletions
|
@ -713,13 +713,9 @@ impl<'tcx> Usefulness<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_useful(&self) -> bool {
|
|
||||||
!matches!(*self, NotUseful)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When trying several branches and each returns a `Usefulness`, we need to combine the
|
/// When trying several branches and each returns a `Usefulness`, we need to combine the
|
||||||
/// results together.
|
/// results together.
|
||||||
fn merge(usefulnesses: impl Iterator<Item = (Self, Span)>) -> Self {
|
fn merge_or_patterns(usefulnesses: impl Iterator<Item = (Self, Span)>) -> Self {
|
||||||
// If we have detected some unreachable sub-branches, we only want to keep them when they
|
// If we have detected some unreachable sub-branches, we only want to keep them when they
|
||||||
// were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable
|
// were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable
|
||||||
// in the second branch of the first or-pattern, but not otherwise. Therefore we don't want
|
// in the second branch of the first or-pattern, but not otherwise. Therefore we don't want
|
||||||
|
@ -789,6 +785,27 @@ impl<'tcx> Usefulness<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When trying several branches and each returns a `Usefulness`, we need to combine the
|
||||||
|
/// results together.
|
||||||
|
fn merge_split_constructors(usefulnesses: impl Iterator<Item = Self>) -> Self {
|
||||||
|
// Witnesses of usefulness, if any.
|
||||||
|
let mut witnesses = Vec::new();
|
||||||
|
|
||||||
|
for u in usefulnesses {
|
||||||
|
match u {
|
||||||
|
Useful(..) => {
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
NotUseful => {}
|
||||||
|
UsefulWithWitness(wits) => {
|
||||||
|
witnesses.extend(wits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !witnesses.is_empty() { UsefulWithWitness(witnesses) } else { NotUseful }
|
||||||
|
}
|
||||||
|
|
||||||
fn apply_constructor<'p>(
|
fn apply_constructor<'p>(
|
||||||
self,
|
self,
|
||||||
pcx: PatCtxt<'_, 'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
|
@ -975,29 +992,22 @@ fn is_useful<'p, 'tcx>(
|
||||||
}
|
}
|
||||||
(u, span)
|
(u, span)
|
||||||
});
|
});
|
||||||
Usefulness::merge(usefulnesses)
|
Usefulness::merge_or_patterns(usefulnesses)
|
||||||
} else {
|
} else {
|
||||||
v.head_ctor(cx)
|
// We split the head constructor of `v`.
|
||||||
.split(pcx, Some(hir_id))
|
let ctors = v.head_ctor(cx).split(pcx, Some(hir_id));
|
||||||
.into_iter()
|
// For each constructor, we compute whether there's a value that starts with it that would
|
||||||
.map(|ctor| {
|
// witness the usefulness of `v`.
|
||||||
// We cache the result of `Fields::wildcards` because it is used a lot.
|
let usefulnesses = ctors.into_iter().map(|ctor| {
|
||||||
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
|
// We cache the result of `Fields::wildcards` because it is used a lot.
|
||||||
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
|
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
|
||||||
let v = v.pop_head_constructor(&ctor_wild_subpatterns);
|
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
|
||||||
let usefulness = is_useful(
|
let v = v.pop_head_constructor(&ctor_wild_subpatterns);
|
||||||
pcx.cx,
|
let usefulness =
|
||||||
&matrix,
|
is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
|
||||||
&v,
|
usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
|
||||||
witness_preference,
|
});
|
||||||
hir_id,
|
Usefulness::merge_split_constructors(usefulnesses)
|
||||||
is_under_guard,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
|
|
||||||
})
|
|
||||||
.find(|result| result.is_useful())
|
|
||||||
.unwrap_or(NotUseful)
|
|
||||||
};
|
};
|
||||||
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
|
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub enum V {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match (T::T1(()), V::V2(true)) {
|
match (T::T1(()), V::V2(true)) {
|
||||||
//~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered
|
//~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
|
||||||
(T::T1(()), V::V1(i)) => (),
|
(T::T1(()), V::V1(i)) => (),
|
||||||
(T::T2(()), V::V2(b)) => (),
|
(T::T2(()), V::V2(b)) => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered
|
error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
|
||||||
--> $DIR/issue-15129.rs:12:11
|
--> $DIR/issue-15129.rs:12:11
|
||||||
|
|
|
|
||||||
LL | match (T::T1(()), V::V2(true)) {
|
LL | match (T::T1(()), V::V2(true)) {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
= note: the matched value is of type `(T, V)`
|
= note: the matched value is of type `(T, V)`
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
fn foo(a: Option<usize>, b: Option<usize>) {
|
fn foo(a: Option<usize>, b: Option<usize>) {
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
//~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
|
//~^ ERROR: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered
|
||||||
(Some(a), Some(b)) if a == b => {}
|
(Some(a), Some(b)) if a == b => {}
|
||||||
(Some(_), None) | (None, Some(_)) => {}
|
(Some(_), None) | (None, Some(_)) => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0004]: non-exhaustive patterns: `(None, None)` not covered
|
error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered
|
||||||
--> $DIR/issue-2111.rs:2:11
|
--> $DIR/issue-2111.rs:2:11
|
||||||
|
|
|
|
||||||
LL | match (a, b) {
|
LL | match (a, b) {
|
||||||
| ^^^^^^ pattern `(None, None)` not covered
|
| ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
= note: the matched value is of type `(Option<usize>, Option<usize>)`
|
= note: the matched value is of type `(Option<usize>, Option<usize>)`
|
||||||
|
|
|
@ -6,7 +6,7 @@ enum Foo {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match Foo::A(true) {
|
match Foo::A(true) {
|
||||||
//~^ ERROR non-exhaustive patterns: `A(false)` not covered
|
//~^ ERROR non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
|
||||||
Foo::A(true) => {}
|
Foo::A(true) => {}
|
||||||
Foo::B(true) => {}
|
Foo::B(true) => {}
|
||||||
Foo::C(true) => {}
|
Foo::C(true) => {}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
error[E0004]: non-exhaustive patterns: `A(false)` not covered
|
error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
|
||||||
--> $DIR/issue-56379.rs:8:11
|
--> $DIR/issue-56379.rs:8:11
|
||||||
|
|
|
|
||||||
LL | / enum Foo {
|
LL | / enum Foo {
|
||||||
LL | | A(bool),
|
LL | | A(bool),
|
||||||
| | - not covered
|
| | - not covered
|
||||||
LL | | B(bool),
|
LL | | B(bool),
|
||||||
|
| | - not covered
|
||||||
LL | | C(bool),
|
LL | | C(bool),
|
||||||
|
| | - not covered
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_- `Foo` defined here
|
| |_- `Foo` defined here
|
||||||
...
|
...
|
||||||
LL | match Foo::A(true) {
|
LL | match Foo::A(true) {
|
||||||
| ^^^^^^^^^^^^ pattern `A(false)` not covered
|
| ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
= note: the matched value is of type `Foo`
|
= note: the matched value is of type `Foo`
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn main() {
|
||||||
// and `(_, _, 5_i32..=i32::MAX)` not covered
|
// and `(_, _, 5_i32..=i32::MAX)` not covered
|
||||||
(_, _, 4) => {}
|
(_, _, 4) => {}
|
||||||
}
|
}
|
||||||
match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered
|
match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
|
||||||
(T::A, T::B) => {}
|
(T::A, T::B) => {}
|
||||||
(T::B, T::A) => {}
|
(T::B, T::A) => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,11 +45,11 @@ LL | match (2, 3, 4) {
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
= note: the matched value is of type `(i32, i32, i32)`
|
= note: the matched value is of type `(i32, i32, i32)`
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: `(A, A)` not covered
|
error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
|
||||||
--> $DIR/non-exhaustive-match.rs:18:11
|
--> $DIR/non-exhaustive-match.rs:18:11
|
||||||
|
|
|
|
||||||
LL | match (T::A, T::A) {
|
LL | match (T::A, T::A) {
|
||||||
| ^^^^^^^^^^^^ pattern `(A, A)` not covered
|
| ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
= note: the matched value is of type `(T, T)`
|
= note: the matched value is of type `(T, T)`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue