diff options
| author | Nadrieril <nadrieril+git@gmail.com> | 2023-11-19 23:56:27 +0100 |
|---|---|---|
| committer | Nadrieril <nadrieril+git@gmail.com> | 2023-11-22 03:25:15 +0100 |
| commit | 273cbb73047436927a680da5d1636d87be9aafe3 (patch) | |
| tree | 1d2be0c327cab98080ac327fc85a83ad2f0b76fe | |
| parent | 41e8f58fdc7c676681a09aebc71595a23de3d5b3 (diff) | |
| download | rust-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.rs | 132 |
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()) { |
