@@ -567,39 +567,16 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
567
567
}
568
568
}
569
569
570
- /// A row of the matrix. Represents a pattern-tuple under investigation.
570
+ /// Represents a pattern-tuple under investigation.
571
571
#[derive(Clone)]
572
572
struct PatStack<'p, 'tcx> {
573
573
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
574
574
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,
586
575
}
587
576
588
577
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] }
603
580
}
604
581
605
582
fn is_empty(&self) -> bool {
@@ -622,10 +599,9 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
622
599
// an or-pattern. Panics if `self` is empty.
623
600
fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
624
601
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 }
629
605
})
630
606
}
631
607
@@ -635,19 +611,18 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
635
611
&self,
636
612
pcx: &PatCtxt<'_, 'p, 'tcx>,
637
613
ctor: &Constructor<'tcx>,
638
- parent_row: usize,
639
614
) -> PatStack<'p, 'tcx> {
640
615
// We pop the head pattern and push the new fields extracted from the arguments of
641
616
// `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 }
645
620
}
646
621
}
647
622
648
- /// Pretty-printing for a matrix row.
649
623
impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
650
624
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625
+ // We pretty-print similarly to the `Debug` impl of `Matrix`.
651
626
write!(f, "+")?;
652
627
for pat in self.iter() {
653
628
write!(f, " {pat:?} +")?;
@@ -656,6 +631,74 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
656
631
}
657
632
}
658
633
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
+
659
702
/// A 2D matrix. Represents a list of pattern-tuples under investigation.
660
703
///
661
704
/// 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> {
668
711
/// the matrix will correspond to `scrutinee.0.Some.0` and the second column to `scrutinee.1`.
669
712
#[derive(Clone)]
670
713
struct Matrix<'p, 'tcx> {
671
- rows: Vec<PatStack <'p, 'tcx>>,
714
+ rows: Vec<MatrixRow <'p, 'tcx>>,
672
715
/// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
673
716
/// each column. This must obey the same invariants as the real rows.
674
717
wildcard_row: PatStack<'p, 'tcx>,
@@ -677,7 +720,7 @@ struct Matrix<'p, 'tcx> {
677
720
impl<'p, 'tcx> Matrix<'p, 'tcx> {
678
721
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
679
722
/// 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>) {
681
724
if !row.is_empty() && row.head().is_or_pat() {
682
725
// Expand nested or-patterns.
683
726
for new_row in row.expand_or_pat() {
@@ -698,10 +741,15 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
698
741
'p: 'a,
699
742
{
700
743
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);
702
745
let mut matrix = Matrix { rows: vec![], wildcard_row };
703
746
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
+ };
705
753
matrix.expand_and_push(v);
706
754
}
707
755
matrix
@@ -733,13 +781,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
733
781
734
782
fn rows<'a>(
735
783
&'a self,
736
- ) -> impl Iterator<Item = &'a PatStack <'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
784
+ ) -> impl Iterator<Item = &'a MatrixRow <'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
737
785
{
738
786
self.rows.iter()
739
787
}
740
788
fn rows_mut<'a>(
741
789
&'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
743
791
{
744
792
self.rows.iter_mut()
745
793
}
@@ -757,7 +805,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
757
805
pcx: &PatCtxt<'_, 'p, 'tcx>,
758
806
ctor: &Constructor<'tcx>,
759
807
) -> 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);
761
809
let mut matrix = Matrix { rows: vec![], wildcard_row };
762
810
for (i, row) in self.rows().enumerate() {
763
811
if ctor.is_covered_by(pcx, row.head().ctor()) {
0 commit comments