summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2023-11-19 23:56:27 +0100
committerNadrieril <nadrieril+git@gmail.com>2023-11-22 03:25:15 +0100
commit273cbb73047436927a680da5d1636d87be9aafe3 (patch)
tree1d2be0c327cab98080ac327fc85a83ad2f0b76fe
parent41e8f58fdc7c676681a09aebc71595a23de3d5b3 (diff)
downloadrust-273cbb73047436927a680da5d1636d87be9aafe3.tar.gz
rust-273cbb73047436927a680da5d1636d87be9aafe3.zip
Separate `PatStack` and `MatrixRow`
This disentangles the row-specific tracking of `parent_row` etc from the
logical operation of specialization. This means `wildcard_row` doesn't
need to provide dummy values for `parent_row` etc anymore.
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs132
1 files changed, 90 insertions, 42 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 65d762d8b5f..8f017833531 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -567,39 +567,16 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
     }
 }
 
-/// A row of the matrix. Represents a pattern-tuple under investigation.
+/// Represents a pattern-tuple under investigation.
 #[derive(Clone)]
 struct PatStack<'p, 'tcx> {
     // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
     pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
-    /// Whether the original arm had a guard.
-    is_under_guard: bool,
-    /// When we specialize, we remember which row of the original matrix produced a given row of the
-    /// specialized matrix. When we unspecialize, we use this to propagate reachability back up the
-    /// callstack.
-    /// At the start of the algorithm, this is the id of the arm this comes from (but we don't use
-    /// this fact anywhere).
-    parent_row: usize,
-    /// False when the matrix is just built. This is set to `true` by
-    /// [`compute_exhaustiveness_and_reachability`] if the arm is found to be reachable.
-    reachable: bool,
 }
 
 impl<'p, 'tcx> PatStack<'p, 'tcx> {
-    fn from_pattern(
-        pat: &'p DeconstructedPat<'p, 'tcx>,
-        parent_row: usize,
-        is_under_guard: bool,
-    ) -> Self {
-        PatStack { pats: smallvec![pat], parent_row, is_under_guard, reachable: false }
-    }
-
-    fn from_vec(
-        pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
-        parent_row: usize,
-        is_under_guard: bool,
-    ) -> Self {
-        PatStack { pats, parent_row, is_under_guard, reachable: false }
+    fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>) -> Self {
+        PatStack { pats: smallvec![pat] }
     }
 
     fn is_empty(&self) -> bool {
@@ -622,10 +599,9 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
     // 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().flatten_or_pat().into_iter().map(move |pat| {
-            let mut new_patstack =
-                PatStack::from_pattern(pat, self.parent_row, self.is_under_guard);
-            new_patstack.pats.extend_from_slice(&self.pats[1..]);
-            new_patstack
+            let mut new_pats = smallvec![pat];
+            new_pats.extend_from_slice(&self.pats[1..]);
+            PatStack { pats: new_pats }
         })
     }
 
@@ -635,19 +611,18 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         &self,
         pcx: &PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
-        parent_row: usize,
     ) -> PatStack<'p, 'tcx> {
         // We pop the head pattern and push the new fields extracted from the arguments of
         // `self.head()`.
-        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
-        new_fields.extend_from_slice(&self.pats[1..]);
-        PatStack::from_vec(new_fields, parent_row, self.is_under_guard)
+        let mut new_pats = self.head().specialize(pcx, ctor);
+        new_pats.extend_from_slice(&self.pats[1..]);
+        PatStack { pats: new_pats }
     }
 }
 
-/// Pretty-printing for a matrix row.
 impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // We pretty-print similarly to the `Debug` impl of `Matrix`.
         write!(f, "+")?;
         for pat in self.iter() {
             write!(f, " {pat:?} +")?;
@@ -656,6 +631,74 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
     }
 }
 
+/// A row of the matrix.
+#[derive(Clone)]
+struct MatrixRow<'p, 'tcx> {
+    // The patterns in the row.
+    pats: PatStack<'p, 'tcx>,
+    /// Whether the original arm had a guard. This is inherited when specializing.
+    is_under_guard: bool,
+    /// When we specialize, we remember which row of the original matrix produced a given row of the
+    /// specialized matrix. When we unspecialize, we use this to propagate reachability back up the
+    /// callstack.
+    parent_row: usize,
+    /// False when the matrix is just built. This is set to `true` by
+    /// [`compute_exhaustiveness_and_reachability`] if the arm is found to be reachable.
+    /// This is reset to `false` when specializing.
+    reachable: bool,
+}
+
+impl<'p, 'tcx> MatrixRow<'p, 'tcx> {
+    fn is_empty(&self) -> bool {
+        self.pats.is_empty()
+    }
+
+    fn len(&self) -> usize {
+        self.pats.len()
+    }
+
+    fn head(&self) -> &'p DeconstructedPat<'p, 'tcx> {
+        self.pats.head()
+    }
+
+    fn iter(&self) -> impl Iterator<Item = &DeconstructedPat<'p, 'tcx>> {
+        self.pats.iter()
+    }
+
+    // Recursively expand the first or-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 = MatrixRow<'p, 'tcx>> + Captures<'a> {
+        self.pats.expand_or_pat().map(|patstack| MatrixRow {
+            pats: patstack,
+            parent_row: self.parent_row,
+            is_under_guard: self.is_under_guard,
+            reachable: false,
+        })
+    }
+
+    /// This computes `specialize(ctor, self)`. See top of the file for explanations.
+    /// Only call if `ctor.is_covered_by(self.head().ctor())` is true.
+    fn pop_head_constructor(
+        &self,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
+        ctor: &Constructor<'tcx>,
+        parent_row: usize,
+    ) -> MatrixRow<'p, 'tcx> {
+        MatrixRow {
+            pats: self.pats.pop_head_constructor(pcx, ctor),
+            parent_row,
+            is_under_guard: self.is_under_guard,
+            reachable: false,
+        }
+    }
+}
+
+impl<'p, 'tcx> fmt::Debug for MatrixRow<'p, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.pats.fmt(f)
+    }
+}
+
 /// A 2D matrix. Represents a list of pattern-tuples under investigation.
 ///
 /// Invariant: each row must have the same length, and each column must have the same type.
@@ -668,7 +711,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
 /// the matrix will correspond to `scrutinee.0.Some.0` and the second column to `scrutinee.1`.
 #[derive(Clone)]
 struct Matrix<'p, 'tcx> {
-    rows: Vec<PatStack<'p, 'tcx>>,
+    rows: Vec<MatrixRow<'p, 'tcx>>,
     /// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
     /// each column. This must obey the same invariants as the real rows.
     wildcard_row: PatStack<'p, 'tcx>,
@@ -677,7 +720,7 @@ struct Matrix<'p, 'tcx> {
 impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
     /// expands it. Internal method, prefer [`Matrix::new`].
-    fn expand_and_push(&mut self, row: PatStack<'p, 'tcx>) {
+    fn expand_and_push(&mut self, row: MatrixRow<'p, 'tcx>) {
         if !row.is_empty() && row.head().is_or_pat() {
             // Expand nested or-patterns.
             for new_row in row.expand_or_pat() {
@@ -698,10 +741,15 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         'p: 'a,
     {
         let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
-        let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false);
+        let wildcard_row = PatStack::from_pattern(wild_pattern);
         let mut matrix = Matrix { rows: vec![], wildcard_row };
         for (row_id, arm) in iter.enumerate() {
-            let v = PatStack::from_pattern(arm.pat, row_id, arm.has_guard);
+            let v = MatrixRow {
+                pats: PatStack::from_pattern(arm.pat),
+                parent_row: row_id, // dummy, we won't read it
+                is_under_guard: arm.has_guard,
+                reachable: false,
+            };
             matrix.expand_and_push(v);
         }
         matrix
@@ -733,13 +781,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
 
     fn rows<'a>(
         &'a self,
-    ) -> impl Iterator<Item = &'a PatStack<'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
+    ) -> impl Iterator<Item = &'a MatrixRow<'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
     {
         self.rows.iter()
     }
     fn rows_mut<'a>(
         &'a mut self,
-    ) -> impl Iterator<Item = &'a mut PatStack<'p, 'tcx>> + DoubleEndedIterator + ExactSizeIterator
+    ) -> impl Iterator<Item = &'a mut MatrixRow<'p, 'tcx>> + DoubleEndedIterator + ExactSizeIterator
     {
         self.rows.iter_mut()
     }
@@ -757,7 +805,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         pcx: &PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
     ) -> Matrix<'p, 'tcx> {
-        let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, usize::MAX);
+        let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor);
         let mut matrix = Matrix { rows: vec![], wildcard_row };
         for (i, row) in self.rows().enumerate() {
             if ctor.is_covered_by(pcx, row.head().ctor()) {