about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2020-12-17 01:18:01 +0000
committerNadrieril <nadrieril+git@gmail.com>2020-12-18 16:21:38 +0000
commit2d71a0b9b9871966dd1f63b4113eeecc2d6e2f6f (patch)
tree6f921dc930e1a613f6d3063c64446923cf06854a
parentd7a6365b77e171337d4f4220ebdc618965524ecd (diff)
downloadrust-2d71a0b9b9871966dd1f63b4113eeecc2d6e2f6f.tar.gz
rust-2d71a0b9b9871966dd1f63b4113eeecc2d6e2f6f.zip
Keep all witnesses of non-exhaustiveness
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs64
-rw-r--r--src/test/ui/pattern/usefulness/issue-15129.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-15129.stderr4
-rw-r--r--src/test/ui/pattern/usefulness/issue-2111.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-2111.stderr4
-rw-r--r--src/test/ui/pattern/usefulness/issue-56379.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-56379.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match.rs2
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match.stderr4
9 files changed, 51 insertions, 39 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 5af155bd746..02b5e0eb3b2 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<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
         // 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<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>(
         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 bcfc32be9a4..d2b72a86b74 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 aa4434e72b5..79a77240937 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 0847045cdaa..d27beaeffd6 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<usize>, b: Option<usize>) {
     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 f0609ccebc1..60d9b8514b7 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<usize>, Option<usize>)`
diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs
index 5454e80cdb4..9bccccca9c2 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 661e0dbb439..6a231b868c8 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 a28cfb579f4..4ff12aa2ff5 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 12412743b83..c953cd31440 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)`