diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 5af155bd746a..02b5e0eb3b22 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -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 /// results together. - fn merge(usefulnesses: impl Iterator) -> Self { + fn merge_or_patterns(usefulnesses: impl Iterator) -> Self { // 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 // 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) -> 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>( self, pcx: PatCtxt<'_, 'p, 'tcx>, @@ -975,29 +992,22 @@ fn is_useful<'p, 'tcx>( } (u, span) }); - Usefulness::merge(usefulnesses) + Usefulness::merge_or_patterns(usefulnesses) } else { - v.head_ctor(cx) - .split(pcx, Some(hir_id)) - .into_iter() - .map(|ctor| { - // We cache the result of `Fields::wildcards` because it is used a lot. - let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); - let v = v.pop_head_constructor(&ctor_wild_subpatterns); - let usefulness = is_useful( - pcx.cx, - &matrix, - &v, - witness_preference, - hir_id, - is_under_guard, - false, - ); - usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) - }) - .find(|result| result.is_useful()) - .unwrap_or(NotUseful) + // We split the head constructor of `v`. + let ctors = v.head_ctor(cx).split(pcx, Some(hir_id)); + // For each constructor, we compute whether there's a value that starts with it that would + // witness the usefulness of `v`. + let usefulnesses = ctors.into_iter().map(|ctor| { + // We cache the result of `Fields::wildcards` because it is used a lot. + let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); + let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); + let v = v.pop_head_constructor(&ctor_wild_subpatterns); + let usefulness = + is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); + usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns) + }); + Usefulness::merge_split_constructors(usefulnesses) }; debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); ret diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs index bcfc32be9a48..d2b72a86b74c 100644 --- a/src/test/ui/pattern/usefulness/issue-15129.rs +++ b/src/test/ui/pattern/usefulness/issue-15129.rs @@ -10,7 +10,7 @@ pub enum V { fn main() { 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::T2(()), V::V2(b)) => (), } diff --git a/src/test/ui/pattern/usefulness/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr index aa4434e72b5c..79a77240937a 100644 --- a/src/test/ui/pattern/usefulness/issue-15129.stderr +++ b/src/test/ui/pattern/usefulness/issue-15129.stderr @@ -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 | 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 = note: the matched value is of type `(T, V)` diff --git a/src/test/ui/pattern/usefulness/issue-2111.rs b/src/test/ui/pattern/usefulness/issue-2111.rs index 0847045cdaa9..d27beaeffd63 100644 --- a/src/test/ui/pattern/usefulness/issue-2111.rs +++ b/src/test/ui/pattern/usefulness/issue-2111.rs @@ -1,6 +1,6 @@ fn foo(a: Option, b: Option) { 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(_), None) | (None, Some(_)) => {} } diff --git a/src/test/ui/pattern/usefulness/issue-2111.stderr b/src/test/ui/pattern/usefulness/issue-2111.stderr index f0609ccebc16..60d9b8514b7f 100644 --- a/src/test/ui/pattern/usefulness/issue-2111.stderr +++ b/src/test/ui/pattern/usefulness/issue-2111.stderr @@ -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 | 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 = note: the matched value is of type `(Option, Option)` diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs index 5454e80cdb4f..9bccccca9c2b 100644 --- a/src/test/ui/pattern/usefulness/issue-56379.rs +++ b/src/test/ui/pattern/usefulness/issue-56379.rs @@ -6,7 +6,7 @@ enum Foo { fn main() { 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::B(true) => {} Foo::C(true) => {} diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr index 661e0dbb4392..6a231b868c8c 100644 --- a/src/test/ui/pattern/usefulness/issue-56379.stderr +++ b/src/test/ui/pattern/usefulness/issue-56379.stderr @@ -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 | LL | / enum Foo { LL | | A(bool), | | - not covered LL | | B(bool), + | | - not covered LL | | C(bool), + | | - not covered LL | | } | |_- `Foo` defined here ... 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 = note: the matched value is of type `Foo` diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs index a28cfb579f4f..4ff12aa2ff5e 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs @@ -15,7 +15,7 @@ fn main() { // and `(_, _, 5_i32..=i32::MAX)` not covered (_, _, 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::B, T::A) => {} } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index 12412743b83f..c953cd314406 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -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 = 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 | 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 = note: the matched value is of type `(T, T)`