summary refs log tree commit diff
path: root/compiler/rustc_pattern_analysis/src
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2024-01-24 23:08:36 +0100
committerNadrieril <nadrieril+git@gmail.com>2024-02-07 23:10:51 +0100
commitcb3ce6645f09929d2e9419aa0a45134db87ab991 (patch)
tree1348a37a412f1cfe0b920891ea03d202db445835 /compiler/rustc_pattern_analysis/src
parent8ace7ea1f7cbba7b4f031e66c54ca237a0d65de6 (diff)
downloadrust-cb3ce6645f09929d2e9419aa0a45134db87ab991.tar.gz
rust-cb3ce6645f09929d2e9419aa0a45134db87ab991.zip
Move usefulness-specific pattern computations to `usefulness`
Diffstat (limited to 'compiler/rustc_pattern_analysis/src')
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs37
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs37
2 files changed, 41 insertions, 33 deletions
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index 9bde23c7bf1..2314da7149b 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -29,7 +29,7 @@ pub struct DeconstructedPat<Cx: TypeCx> {
     /// correspond to a user-supplied pattern.
     data: Option<Cx::PatData>,
     /// Whether removing this arm would change the behavior of the match expression.
-    useful: Cell<bool>,
+    pub(crate) useful: Cell<bool>,
 }
 
 impl<Cx: TypeCx> DeconstructedPat<Cx> {
@@ -112,34 +112,17 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
     pub(crate) fn set_useful(&self) {
         self.useful.set(true)
     }
-    pub(crate) fn is_useful(&self) -> bool {
-        if self.useful.get() {
-            true
-        } else if self.is_or_pat() && self.iter_fields().any(|f| f.is_useful()) {
-            // We always expand or patterns in the matrix, so we will never see the actual
-            // or-pattern (the one with constructor `Or`) in the column. As such, it will not be
-            // marked as useful itself, only its children will. We recover this information here.
-            self.set_useful();
-            true
-        } else {
-            false
+
+    /// Walk top-down and call `it` in each place where a pattern occurs
+    /// starting with the root pattern `walk` is called on. If `it` returns
+    /// false then we will descend no further but siblings will be processed.
+    pub fn walk<'a>(&'a self, it: &mut impl FnMut(&'a Self) -> bool) {
+        if !it(self) {
+            return;
         }
-    }
 
-    /// Report the subpatterns that were not useful, if any.
-    pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> {
-        let mut subpats = Vec::new();
-        self.collect_redundant_subpatterns(&mut subpats);
-        subpats
-    }
-    fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
-        // We don't look at subpatterns if we already reported the whole pattern as redundant.
-        if !self.is_useful() {
-            subpats.push(self);
-        } else {
-            for p in self.iter_fields() {
-                p.collect_redundant_subpatterns(subpats);
-            }
+        for p in self.iter_fields() {
+            p.walk(it)
         }
     }
 }
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 576005b2c7f..219d774513d 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -1599,6 +1599,36 @@ pub enum Usefulness<'p, Cx: TypeCx> {
     Redundant,
 }
 
+/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
+fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) -> Usefulness<'p, Cx> {
+    fn pat_is_useful<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) -> bool {
+        if pat.useful.get() {
+            true
+        } else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(f)) {
+            // We always expand or patterns in the matrix, so we will never see the actual
+            // or-pattern (the one with constructor `Or`) in the column. As such, it will not be
+            // marked as useful itself, only its children will. We recover this information here.
+            true
+        } else {
+            false
+        }
+    }
+
+    let mut redundant_subpats = Vec::new();
+    pat.walk(&mut |p| {
+        if pat_is_useful(p) {
+            // The pattern is useful, so we recurse to find redundant subpatterns.
+            true
+        } else {
+            // The pattern is redundant.
+            redundant_subpats.push(p);
+            false // stop recursing
+        }
+    });
+
+    if pat_is_useful(pat) { Usefulness::Useful(redundant_subpats) } else { Usefulness::Redundant }
+}
+
 /// The output of checking a match for exhaustiveness and arm usefulness.
 pub struct UsefulnessReport<'p, Cx: TypeCx> {
     /// For each arm of the input, whether that arm is useful after the arms above it.
@@ -1626,12 +1656,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
         .copied()
         .map(|arm| {
             debug!(?arm);
-            // We warn when a pattern is not useful.
-            let usefulness = if arm.pat.is_useful() {
-                Usefulness::Useful(arm.pat.redundant_subpatterns())
-            } else {
-                Usefulness::Redundant
-            };
+            let usefulness = collect_pattern_usefulness(arm.pat);
             (arm, usefulness)
         })
         .collect();