Skip to content

Commit 2d71a0b

Browse files
committed
Keep all witnesses of non-exhaustiveness
1 parent d7a6365 commit 2d71a0b

File tree

9 files changed

+51
-39
lines changed

9 files changed

+51
-39
lines changed

compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

+37-27
Original file line numberDiff line numberDiff line change
@@ -713,13 +713,9 @@ impl<'tcx> Usefulness<'tcx> {
713713
}
714714
}
715715

716-
fn is_useful(&self) -> bool {
717-
!matches!(*self, NotUseful)
718-
}
719-
720716
/// When trying several branches and each returns a `Usefulness`, we need to combine the
721717
/// results together.
722-
fn merge(usefulnesses: impl Iterator<Item = (Self, Span)>) -> Self {
718+
fn merge_or_patterns(usefulnesses: impl Iterator<Item = (Self, Span)>) -> Self {
723719
// If we have detected some unreachable sub-branches, we only want to keep them when they
724720
// were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable
725721
// 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> {
789785
}
790786
}
791787

788+
/// When trying several branches and each returns a `Usefulness`, we need to combine the
789+
/// results together.
790+
fn merge_split_constructors(usefulnesses: impl Iterator<Item = Self>) -> Self {
791+
// Witnesses of usefulness, if any.
792+
let mut witnesses = Vec::new();
793+
794+
for u in usefulnesses {
795+
match u {
796+
Useful(..) => {
797+
return u;
798+
}
799+
NotUseful => {}
800+
UsefulWithWitness(wits) => {
801+
witnesses.extend(wits);
802+
}
803+
}
804+
}
805+
806+
if !witnesses.is_empty() { UsefulWithWitness(witnesses) } else { NotUseful }
807+
}
808+
792809
fn apply_constructor<'p>(
793810
self,
794811
pcx: PatCtxt<'_, 'p, 'tcx>,
@@ -975,29 +992,22 @@ fn is_useful<'p, 'tcx>(
975992
}
976993
(u, span)
977994
});
978-
Usefulness::merge(usefulnesses)
995+
Usefulness::merge_or_patterns(usefulnesses)
979996
} else {
980-
v.head_ctor(cx)
981-
.split(pcx, Some(hir_id))
982-
.into_iter()
983-
.map(|ctor| {
984-
// We cache the result of `Fields::wildcards` because it is used a lot.
985-
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
986-
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
987-
let v = v.pop_head_constructor(&ctor_wild_subpatterns);
988-
let usefulness = is_useful(
989-
pcx.cx,
990-
&matrix,
991-
&v,
992-
witness_preference,
993-
hir_id,
994-
is_under_guard,
995-
false,
996-
);
997-
usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
998-
})
999-
.find(|result| result.is_useful())
1000-
.unwrap_or(NotUseful)
997+
// We split the head constructor of `v`.
998+
let ctors = v.head_ctor(cx).split(pcx, Some(hir_id));
999+
// For each constructor, we compute whether there's a value that starts with it that would
1000+
// witness the usefulness of `v`.
1001+
let usefulnesses = ctors.into_iter().map(|ctor| {
1002+
// We cache the result of `Fields::wildcards` because it is used a lot.
1003+
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
1004+
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
1005+
let v = v.pop_head_constructor(&ctor_wild_subpatterns);
1006+
let usefulness =
1007+
is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
1008+
usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
1009+
});
1010+
Usefulness::merge_split_constructors(usefulnesses)
10011011
};
10021012
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
10031013
ret

src/test/ui/pattern/usefulness/issue-15129.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub enum V {
1010

1111
fn main() {
1212
match (T::T1(()), V::V2(true)) {
13-
//~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered
13+
//~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
1414
(T::T1(()), V::V1(i)) => (),
1515
(T::T2(()), V::V2(b)) => (),
1616
}

src/test/ui/pattern/usefulness/issue-15129.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` not covered
1+
error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
22
--> $DIR/issue-15129.rs:12:11
33
|
44
LL | match (T::T1(()), V::V2(true)) {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(T1(()), V2(_))` not covered
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
66
|
77
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
88
= note: the matched value is of type `(T, V)`

src/test/ui/pattern/usefulness/issue-2111.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fn foo(a: Option<usize>, b: Option<usize>) {
22
match (a, b) {
3-
//~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
3+
//~^ ERROR: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered
44
(Some(a), Some(b)) if a == b => {}
55
(Some(_), None) | (None, Some(_)) => {}
66
}

src/test/ui/pattern/usefulness/issue-2111.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0004]: non-exhaustive patterns: `(None, None)` not covered
1+
error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` not covered
22
--> $DIR/issue-2111.rs:2:11
33
|
44
LL | match (a, b) {
5-
| ^^^^^^ pattern `(None, None)` not covered
5+
| ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
66
|
77
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
88
= note: the matched value is of type `(Option<usize>, Option<usize>)`

src/test/ui/pattern/usefulness/issue-56379.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ enum Foo {
66

77
fn main() {
88
match Foo::A(true) {
9-
//~^ ERROR non-exhaustive patterns: `A(false)` not covered
9+
//~^ ERROR non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
1010
Foo::A(true) => {}
1111
Foo::B(true) => {}
1212
Foo::C(true) => {}

src/test/ui/pattern/usefulness/issue-56379.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
error[E0004]: non-exhaustive patterns: `A(false)` not covered
1+
error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
22
--> $DIR/issue-56379.rs:8:11
33
|
44
LL | / enum Foo {
55
LL | | A(bool),
66
| | - not covered
77
LL | | B(bool),
8+
| | - not covered
89
LL | | C(bool),
10+
| | - not covered
911
LL | | }
1012
| |_- `Foo` defined here
1113
...
1214
LL | match Foo::A(true) {
13-
| ^^^^^^^^^^^^ pattern `A(false)` not covered
15+
| ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
1416
|
1517
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
1618
= note: the matched value is of type `Foo`

src/test/ui/pattern/usefulness/non-exhaustive-match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fn main() {
1515
// and `(_, _, 5_i32..=i32::MAX)` not covered
1616
(_, _, 4) => {}
1717
}
18-
match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered
18+
match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
1919
(T::A, T::B) => {}
2020
(T::B, T::A) => {}
2121
}

src/test/ui/pattern/usefulness/non-exhaustive-match.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ LL | match (2, 3, 4) {
4545
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
4646
= note: the matched value is of type `(i32, i32, i32)`
4747

48-
error[E0004]: non-exhaustive patterns: `(A, A)` not covered
48+
error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
4949
--> $DIR/non-exhaustive-match.rs:18:11
5050
|
5151
LL | match (T::A, T::A) {
52-
| ^^^^^^^^^^^^ pattern `(A, A)` not covered
52+
| ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
5353
|
5454
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
5555
= note: the matched value is of type `(T, T)`

0 commit comments

Comments
 (0)