Skip to content

Commit 273cbb7

Browse files
committed
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.
1 parent 41e8f58 commit 273cbb7

File tree

1 file changed

+90
-42
lines changed

1 file changed

+90
-42
lines changed

compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

+90-42
Original file line numberDiff line numberDiff line change
@@ -567,39 +567,16 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
567567
}
568568
}
569569

570-
/// A row of the matrix. Represents a pattern-tuple under investigation.
570+
/// Represents a pattern-tuple under investigation.
571571
#[derive(Clone)]
572572
struct PatStack<'p, 'tcx> {
573573
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
574574
pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
575-
/// Whether the original arm had a guard.
576-
is_under_guard: bool,
577-
/// When we specialize, we remember which row of the original matrix produced a given row of the
578-
/// specialized matrix. When we unspecialize, we use this to propagate reachability back up the
579-
/// callstack.
580-
/// At the start of the algorithm, this is the id of the arm this comes from (but we don't use
581-
/// this fact anywhere).
582-
parent_row: usize,
583-
/// False when the matrix is just built. This is set to `true` by
584-
/// [`compute_exhaustiveness_and_reachability`] if the arm is found to be reachable.
585-
reachable: bool,
586575
}
587576

588577
impl<'p, 'tcx> PatStack<'p, 'tcx> {
589-
fn from_pattern(
590-
pat: &'p DeconstructedPat<'p, 'tcx>,
591-
parent_row: usize,
592-
is_under_guard: bool,
593-
) -> Self {
594-
PatStack { pats: smallvec![pat], parent_row, is_under_guard, reachable: false }
595-
}
596-
597-
fn from_vec(
598-
pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
599-
parent_row: usize,
600-
is_under_guard: bool,
601-
) -> Self {
602-
PatStack { pats, parent_row, is_under_guard, reachable: false }
578+
fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>) -> Self {
579+
PatStack { pats: smallvec![pat] }
603580
}
604581

605582
fn is_empty(&self) -> bool {
@@ -622,10 +599,9 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
622599
// an or-pattern. Panics if `self` is empty.
623600
fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
624601
self.head().flatten_or_pat().into_iter().map(move |pat| {
625-
let mut new_patstack =
626-
PatStack::from_pattern(pat, self.parent_row, self.is_under_guard);
627-
new_patstack.pats.extend_from_slice(&self.pats[1..]);
628-
new_patstack
602+
let mut new_pats = smallvec![pat];
603+
new_pats.extend_from_slice(&self.pats[1..]);
604+
PatStack { pats: new_pats }
629605
})
630606
}
631607

@@ -635,19 +611,18 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
635611
&self,
636612
pcx: &PatCtxt<'_, 'p, 'tcx>,
637613
ctor: &Constructor<'tcx>,
638-
parent_row: usize,
639614
) -> PatStack<'p, 'tcx> {
640615
// We pop the head pattern and push the new fields extracted from the arguments of
641616
// `self.head()`.
642-
let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
643-
new_fields.extend_from_slice(&self.pats[1..]);
644-
PatStack::from_vec(new_fields, parent_row, self.is_under_guard)
617+
let mut new_pats = self.head().specialize(pcx, ctor);
618+
new_pats.extend_from_slice(&self.pats[1..]);
619+
PatStack { pats: new_pats }
645620
}
646621
}
647622

648-
/// Pretty-printing for a matrix row.
649623
impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
650624
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625+
// We pretty-print similarly to the `Debug` impl of `Matrix`.
651626
write!(f, "+")?;
652627
for pat in self.iter() {
653628
write!(f, " {pat:?} +")?;
@@ -656,6 +631,74 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
656631
}
657632
}
658633

634+
/// A row of the matrix.
635+
#[derive(Clone)]
636+
struct MatrixRow<'p, 'tcx> {
637+
// The patterns in the row.
638+
pats: PatStack<'p, 'tcx>,
639+
/// Whether the original arm had a guard. This is inherited when specializing.
640+
is_under_guard: bool,
641+
/// When we specialize, we remember which row of the original matrix produced a given row of the
642+
/// specialized matrix. When we unspecialize, we use this to propagate reachability back up the
643+
/// callstack.
644+
parent_row: usize,
645+
/// False when the matrix is just built. This is set to `true` by
646+
/// [`compute_exhaustiveness_and_reachability`] if the arm is found to be reachable.
647+
/// This is reset to `false` when specializing.
648+
reachable: bool,
649+
}
650+
651+
impl<'p, 'tcx> MatrixRow<'p, 'tcx> {
652+
fn is_empty(&self) -> bool {
653+
self.pats.is_empty()
654+
}
655+
656+
fn len(&self) -> usize {
657+
self.pats.len()
658+
}
659+
660+
fn head(&self) -> &'p DeconstructedPat<'p, 'tcx> {
661+
self.pats.head()
662+
}
663+
664+
fn iter(&self) -> impl Iterator<Item = &DeconstructedPat<'p, 'tcx>> {
665+
self.pats.iter()
666+
}
667+
668+
// Recursively expand the first or-pattern into its subpatterns. Only useful if the pattern is
669+
// an or-pattern. Panics if `self` is empty.
670+
fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = MatrixRow<'p, 'tcx>> + Captures<'a> {
671+
self.pats.expand_or_pat().map(|patstack| MatrixRow {
672+
pats: patstack,
673+
parent_row: self.parent_row,
674+
is_under_guard: self.is_under_guard,
675+
reachable: false,
676+
})
677+
}
678+
679+
/// This computes `specialize(ctor, self)`. See top of the file for explanations.
680+
/// Only call if `ctor.is_covered_by(self.head().ctor())` is true.
681+
fn pop_head_constructor(
682+
&self,
683+
pcx: &PatCtxt<'_, 'p, 'tcx>,
684+
ctor: &Constructor<'tcx>,
685+
parent_row: usize,
686+
) -> MatrixRow<'p, 'tcx> {
687+
MatrixRow {
688+
pats: self.pats.pop_head_constructor(pcx, ctor),
689+
parent_row,
690+
is_under_guard: self.is_under_guard,
691+
reachable: false,
692+
}
693+
}
694+
}
695+
696+
impl<'p, 'tcx> fmt::Debug for MatrixRow<'p, 'tcx> {
697+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
698+
self.pats.fmt(f)
699+
}
700+
}
701+
659702
/// A 2D matrix. Represents a list of pattern-tuples under investigation.
660703
///
661704
/// 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> {
668711
/// the matrix will correspond to `scrutinee.0.Some.0` and the second column to `scrutinee.1`.
669712
#[derive(Clone)]
670713
struct Matrix<'p, 'tcx> {
671-
rows: Vec<PatStack<'p, 'tcx>>,
714+
rows: Vec<MatrixRow<'p, 'tcx>>,
672715
/// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
673716
/// each column. This must obey the same invariants as the real rows.
674717
wildcard_row: PatStack<'p, 'tcx>,
@@ -677,7 +720,7 @@ struct Matrix<'p, 'tcx> {
677720
impl<'p, 'tcx> Matrix<'p, 'tcx> {
678721
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
679722
/// expands it. Internal method, prefer [`Matrix::new`].
680-
fn expand_and_push(&mut self, row: PatStack<'p, 'tcx>) {
723+
fn expand_and_push(&mut self, row: MatrixRow<'p, 'tcx>) {
681724
if !row.is_empty() && row.head().is_or_pat() {
682725
// Expand nested or-patterns.
683726
for new_row in row.expand_or_pat() {
@@ -698,10 +741,15 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
698741
'p: 'a,
699742
{
700743
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
701-
let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false);
744+
let wildcard_row = PatStack::from_pattern(wild_pattern);
702745
let mut matrix = Matrix { rows: vec![], wildcard_row };
703746
for (row_id, arm) in iter.enumerate() {
704-
let v = PatStack::from_pattern(arm.pat, row_id, arm.has_guard);
747+
let v = MatrixRow {
748+
pats: PatStack::from_pattern(arm.pat),
749+
parent_row: row_id, // dummy, we won't read it
750+
is_under_guard: arm.has_guard,
751+
reachable: false,
752+
};
705753
matrix.expand_and_push(v);
706754
}
707755
matrix
@@ -733,13 +781,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
733781

734782
fn rows<'a>(
735783
&'a self,
736-
) -> impl Iterator<Item = &'a PatStack<'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
784+
) -> impl Iterator<Item = &'a MatrixRow<'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
737785
{
738786
self.rows.iter()
739787
}
740788
fn rows_mut<'a>(
741789
&'a mut self,
742-
) -> impl Iterator<Item = &'a mut PatStack<'p, 'tcx>> + DoubleEndedIterator + ExactSizeIterator
790+
) -> impl Iterator<Item = &'a mut MatrixRow<'p, 'tcx>> + DoubleEndedIterator + ExactSizeIterator
743791
{
744792
self.rows.iter_mut()
745793
}
@@ -757,7 +805,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
757805
pcx: &PatCtxt<'_, 'p, 'tcx>,
758806
ctor: &Constructor<'tcx>,
759807
) -> Matrix<'p, 'tcx> {
760-
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, usize::MAX);
808+
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor);
761809
let mut matrix = Matrix { rows: vec![], wildcard_row };
762810
for (i, row) in self.rows().enumerate() {
763811
if ctor.is_covered_by(pcx, row.head().ctor()) {

0 commit comments

Comments
 (0)