about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2021-01-01 22:14:22 +0000
committerNadrieril <nadrieril+git@gmail.com>2021-01-24 20:28:30 +0000
commit0162d603b335e7f08b86cdddbb51197202a5a79a (patch)
tree7a65634df17ae7402b295c655a3725cfc37921b9
parent293af417903b1a718795e60a1b6de0dea8fc4af0 (diff)
downloadrust-0162d603b335e7f08b86cdddbb51197202a5a79a.tar.gz
rust-0162d603b335e7f08b86cdddbb51197202a5a79a.zip
Factor or-pattern expansion
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs60
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs3
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr32
3 files changed, 58 insertions, 37 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 6f94edb9932..d31b5f104e5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -385,6 +385,27 @@ impl<'tcx> Pat<'tcx> {
     pub(super) fn is_wildcard(&self) -> bool {
         matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
     }
+
+    fn is_or_pat(&self) -> bool {
+        matches!(*self.kind, PatKind::Or { .. })
+    }
+
+    /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
+    fn expand_or_pat(&self) -> Vec<&Self> {
+        fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
+            if let PatKind::Or { pats } = pat.kind.as_ref() {
+                for pat in pats {
+                    expand(pat, vec);
+                }
+            } else {
+                vec.push(pat)
+            }
+        }
+
+        let mut pats = Vec::new();
+        expand(self, &mut pats);
+        pats
+    }
 }
 
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
@@ -425,23 +446,14 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         self.pats.iter().copied()
     }
 
-    // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
-    fn expand_or_pat(&self) -> Option<Vec<Self>> {
-        if self.is_empty() {
-            None
-        } else if let PatKind::Or { pats } = &*self.head().kind {
-            Some(
-                pats.iter()
-                    .map(|pat| {
-                        let mut new_patstack = PatStack::from_pattern(pat);
-                        new_patstack.pats.extend_from_slice(&self.pats[1..]);
-                        new_patstack
-                    })
-                    .collect(),
-            )
-        } else {
-            None
-        }
+    // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
+    // or-pattern. Panics if `self` is empty.
+    fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
+        self.head().expand_or_pat().into_iter().map(move |pat| {
+            let mut new_patstack = PatStack::from_pattern(pat);
+            new_patstack.pats.extend_from_slice(&self.pats[1..]);
+            new_patstack
+        })
     }
 
     /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
@@ -508,13 +520,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         self.patterns.get(0).map(|r| r.len())
     }
 
-    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
+    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
+    /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
-        if let Some(rows) = row.expand_or_pat() {
-            for row in rows {
-                // We recursively expand the or-patterns of the new rows.
-                // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`.
-                self.push(row)
+        if !row.is_empty() && row.head().is_or_pat() {
+            for row in row.expand_or_pat() {
+                self.patterns.push(row);
             }
         } else {
             self.patterns.push(row);
@@ -968,8 +979,9 @@ fn is_useful<'p, 'tcx>(
     let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
 
     // If the first pattern is an or-pattern, expand it.
-    let ret = if let Some(vs) = v.expand_or_pat() {
+    let ret = if v.head().is_or_pat() {
         debug!("expanding or-pattern");
+        let vs: Vec<_> = v.expand_or_pat().collect();
         let subspans: Vec<_> = vs.iter().map(|v| v.head().span).collect();
         // We expand the or pattern, trying each of its branches in turn and keeping careful track
         // of possible unreachable sub-branches.
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
index f51ba683cab..9718396ed48 100644
--- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -53,8 +53,11 @@ fn main() {
         _ => {}
     }
     match 0 {
+        // We get two errors because recursive or-pattern expansion means we don't notice the two
+        // errors span a whole pattern. This could be better but doesn't matter much
         0 | (0 | 0) => {}
         //~^ ERROR unreachable
+        //~| ERROR unreachable
         _ => {}
     }
     match None {
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
index f61e7f2281a..901a71885eb 100644
--- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -83,71 +83,77 @@ LL |         (0 | 1) | 1 => {}
    |                   ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:56:14
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
    |
 LL |         0 | (0 | 0) => {}
-   |              ^^^^^
+   |              ^
+
+error: unreachable pattern
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
+   |
+LL |         0 | (0 | 0) => {}
+   |                  ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:63:13
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
    |
 LL | /             Some(
 LL | |                 0 | 0) => {}
    | |______________________^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:69:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
    |
 LL |             | 0
    |               ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:71:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
    |
 LL |             | 0] => {}
    |               ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:79:10
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:82:10
    |
 LL |         [1
    |          ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:91:10
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:94:10
    |
 LL |         [true
    |          ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:98:36
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:101:36
    |
 LL |         (true | false, None | Some(true
    |                                    ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:114:14
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:117:14
    |
 LL |         Some(0
    |              ^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:133:19
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:136:19
    |
 LL |                 | false) => {}
    |                   ^^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:141:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:144:15
    |
 LL |             | true) => {}
    |               ^^^^
 
 error: unreachable pattern
-  --> $DIR/exhaustiveness-unreachable-pattern.rs:147:15
+  --> $DIR/exhaustiveness-unreachable-pattern.rs:150:15
    |
 LL |             | true,
    |               ^^^^
 
-error: aborting due to 24 previous errors
+error: aborting due to 25 previous errors