about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2021-01-01 21:28:32 +0000
committerNadrieril <nadrieril+git@gmail.com>2021-01-24 20:28:29 +0000
commit293af417903b1a718795e60a1b6de0dea8fc4af0 (patch)
tree1fc6ba44814aef989dc825daff96e53943e7d2b9
parentf4f20c0663b686f76c5722fde481c83acf2dd1e9 (diff)
downloadrust-293af417903b1a718795e60a1b6de0dea8fc4af0.tar.gz
rust-293af417903b1a718795e60a1b6de0dea8fc4af0.zip
Split `Usefulness::NotUseful` into two
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs84
1 files changed, 52 insertions, 32 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index bb8213a98ac..6f94edb9932 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -680,24 +680,32 @@ impl SpanSet {
 
 #[derive(Clone, Debug)]
 enum Usefulness<'tcx> {
-    /// Pontentially carries a set of sub-branches that have been found to be unreachable. Used
+    /// Potentially carries a set of sub-branches that have been found to be unreachable. Used
     /// only in the presence of or-patterns, otherwise it stays empty.
-    Useful(SpanSet),
-    /// Carries a list of witnesses of non-exhaustiveness.
-    UsefulWithWitness(Vec<Witness<'tcx>>),
-    NotUseful,
+    NoWitnesses(SpanSet),
+    /// When not carrying witnesses, indicates that the whole pattern is unreachable.
+    NoWitnessesFull,
+    /// Carries a list of witnesses of non-exhaustiveness. Non-empty.
+    WithWitnesses(Vec<Witness<'tcx>>),
+    /// When carrying witnesses, indicates that the whole pattern is unreachable.
+    WithWitnessesEmpty,
 }
 
 impl<'tcx> Usefulness<'tcx> {
     fn new_useful(preference: WitnessPreference) -> Self {
         match preference {
-            ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
-            LeaveOutWitness => Useful(Default::default()),
+            ConstructWitness => WithWitnesses(vec![Witness(vec![])]),
+            LeaveOutWitness => NoWitnesses(Default::default()),
+        }
+    }
+    fn new_not_useful(preference: WitnessPreference) -> Self {
+        match preference {
+            ConstructWitness => WithWitnessesEmpty,
+            LeaveOutWitness => NoWitnessesFull,
         }
     }
 
-    /// Combine usefulnesses from two branches. This is an associative operation and `NotUseful` is
-    /// a unit.
+    /// Combine usefulnesses from two branches. This is an associative operation.
     fn extend(&mut self, other: 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
@@ -720,21 +728,29 @@ impl<'tcx> Usefulness<'tcx> {
         // }
         // ```
         match (&mut *self, other) {
-            (Useful(s), Useful(o)) => s.intersection_mut(&o),
-            (UsefulWithWitness(s), UsefulWithWitness(o)) => s.extend(o),
-            (_, NotUseful) => {}
-            (NotUseful, other) => *self = other,
-            (UsefulWithWitness(_), Useful(_)) | (Useful(_), UsefulWithWitness(_)) => unreachable!(),
+            (WithWitnesses(s), WithWitnesses(o)) => s.extend(o),
+            (WithWitnessesEmpty, WithWitnesses(o)) => *self = WithWitnesses(o),
+            (WithWitnesses(_), WithWitnessesEmpty) => {}
+            (WithWitnessesEmpty, WithWitnessesEmpty) => {}
+
+            (NoWitnesses(s), NoWitnesses(o)) => s.intersection_mut(&o),
+            (NoWitnessesFull, NoWitnesses(o)) => *self = NoWitnesses(o),
+            (NoWitnesses(_), NoWitnessesFull) => {}
+            (NoWitnessesFull, NoWitnessesFull) => {}
+
+            _ => {
+                unreachable!()
+            }
         }
     }
 
     /// When trying several branches and each returns a `Usefulness`, we need to combine the
     /// results together.
-    fn merge(usefulnesses: impl Iterator<Item = Self>) -> Self {
-        let mut ret = NotUseful;
+    fn merge(pref: WitnessPreference, usefulnesses: impl Iterator<Item = Self>) -> Self {
+        let mut ret = Self::new_not_useful(pref);
         for u in usefulnesses {
             ret.extend(u);
-            if let Useful(spans) = &ret {
+            if let NoWitnesses(spans) = &ret {
                 if spans.is_empty() {
                     // Once we reach the empty set, more intersections won't change the result.
                     return ret;
@@ -748,7 +764,7 @@ impl<'tcx> Usefulness<'tcx> {
     /// usefulness mergeable with those from the other branches.
     fn unsplit_or_pat(self, this_span: Span, or_pat_spans: &[Span]) -> Self {
         match self {
-            Useful(mut spans) => {
+            NoWitnesses(mut spans) => {
                 // We register the spans of the other branches of this or-pattern as being
                 // unreachable from this one. This ensures that intersecting together the sets of
                 // spans returns what we want.
@@ -759,9 +775,10 @@ impl<'tcx> Usefulness<'tcx> {
                         spans.push_nonintersecting(span);
                     }
                 }
-                Useful(spans)
+                NoWitnesses(spans)
             }
-            x => x,
+            NoWitnessesFull => NoWitnessesFull,
+            WithWitnesses(_) | WithWitnessesEmpty => bug!(),
         }
     }
 
@@ -776,7 +793,7 @@ impl<'tcx> Usefulness<'tcx> {
         ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Self {
         match self {
-            UsefulWithWitness(witnesses) => {
+            WithWitnesses(witnesses) => {
                 let new_witnesses = if matches!(ctor, Constructor::Missing) {
                     let mut split_wildcard = SplitWildcard::new(pcx);
                     split_wildcard.split(pcx, matrix.head_ctors(pcx.cx));
@@ -806,7 +823,7 @@ impl<'tcx> Usefulness<'tcx> {
                         .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
                         .collect()
                 };
-                UsefulWithWitness(new_witnesses)
+                WithWitnesses(new_witnesses)
             }
             x => x,
         }
@@ -935,8 +952,11 @@ fn is_useful<'p, 'tcx>(
     // first and then, if v is non-empty, the return value is based on whether
     // the type of the tuple we're checking is inhabited or not.
     if v.is_empty() {
-        let ret =
-            if rows.is_empty() { Usefulness::new_useful(witness_preference) } else { NotUseful };
+        let ret = if rows.is_empty() {
+            Usefulness::new_useful(witness_preference)
+        } else {
+            Usefulness::new_not_useful(witness_preference)
+        };
         debug!(?ret);
         return ret;
     }
@@ -966,7 +986,7 @@ fn is_useful<'p, 'tcx>(
             }
             usefulness.unsplit_or_pat(v_span, &subspans)
         });
-        Usefulness::merge(usefulnesses)
+        Usefulness::merge(witness_preference, usefulnesses)
     } else {
         let v_ctor = v.head_ctor(cx);
         if let Constructor::IntRange(ctor_range) = &v_ctor {
@@ -994,7 +1014,7 @@ fn is_useful<'p, 'tcx>(
                 is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
             usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns)
         });
-        Usefulness::merge(usefulnesses)
+        Usefulness::merge(witness_preference, usefulnesses)
     };
     debug!(?ret);
     ret
@@ -1049,9 +1069,9 @@ crate fn compute_match_usefulness<'p, 'tcx>(
                 matrix.push(v);
             }
             let reachability = match usefulness {
-                Useful(spans) => Reachability::Reachable(spans),
-                NotUseful => Reachability::Unreachable,
-                UsefulWithWitness(..) => bug!(),
+                NoWitnesses(spans) => Reachability::Reachable(spans),
+                NoWitnessesFull => Reachability::Unreachable,
+                WithWitnesses(..) | WithWitnessesEmpty => bug!(),
             };
             (arm, reachability)
         })
@@ -1061,15 +1081,15 @@ crate fn compute_match_usefulness<'p, 'tcx>(
     let v = PatStack::from_pattern(wild_pattern);
     let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
     let non_exhaustiveness_witnesses = match usefulness {
-        NotUseful => vec![], // Wildcard pattern isn't useful, so the match is exhaustive.
-        UsefulWithWitness(pats) => {
+        WithWitnessesEmpty => vec![], // Wildcard pattern isn't useful, so the match is exhaustive.
+        WithWitnesses(pats) => {
             if pats.is_empty() {
                 bug!("Exhaustiveness check returned no witnesses")
             } else {
                 pats.into_iter().map(|w| w.single_pattern()).collect()
             }
         }
-        Useful(_) => bug!(),
+        NoWitnesses(_) | NoWitnessesFull => bug!(),
     };
     UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
 }