Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit ab090d4

Browse files
committed
Store wildcard row in the matrix
1 parent fb9f837 commit ab090d4

File tree

1 file changed

+41
-27
lines changed

1 file changed

+41
-27
lines changed

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

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -463,12 +463,17 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
463463
/// A 2D matrix.
464464
#[derive(Clone)]
465465
struct Matrix<'p, 'tcx> {
466+
/// The rows of this matrix.
467+
/// Invariant: `row.head()` is never an or-pattern.
466468
rows: Vec<PatStack<'p, 'tcx>>,
469+
/// Fake row that stores wildcard patterns that match the other rows. This is used only to track
470+
/// the type and number of columns of the matrix.
471+
wildcard_row: PatStack<'p, 'tcx>,
467472
}
468473

469474
impl<'p, 'tcx> Matrix<'p, 'tcx> {
470-
fn empty() -> Self {
471-
Matrix { rows: vec![] }
475+
fn empty(wildcard_row: PatStack<'p, 'tcx>) -> Self {
476+
Matrix { rows: vec![], wildcard_row }
472477
}
473478

474479
fn len(&self) -> usize {
@@ -477,25 +482,43 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
477482

478483
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
479484
/// expands it.
480-
fn push(&mut self, row: PatStack<'p, 'tcx>) -> usize {
485+
fn push(&mut self, row: PatStack<'p, 'tcx>) {
481486
if !row.is_empty() && row.head().is_or_pat() {
482-
let mut count = 0;
483487
for new_row in row.expand_or_pat() {
484-
count += self.push(new_row);
488+
self.push(new_row);
485489
}
486-
count
487490
} else {
488491
self.rows.push(row);
489-
1
490492
}
491493
}
492494

495+
fn column_count(&self) -> usize {
496+
self.wildcard_row.len()
497+
}
498+
fn head_ty(&self) -> Ty<'tcx> {
499+
let mut ty = self.wildcard_row.head().ty();
500+
// Opaque types can't get destructured/split, but the patterns can
501+
// actually hint at hidden types, so we use the patterns' types instead.
502+
if let ty::Alias(ty::Opaque, ..) = ty.kind() {
503+
if let Some(row) = self.rows().next() {
504+
ty = row.head().ty();
505+
}
506+
}
507+
ty
508+
}
509+
493510
fn rows<'a>(
494511
&'a self,
495512
) -> impl Iterator<Item = &'a PatStack<'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
496513
{
497514
self.rows.iter()
498515
}
516+
fn rows_mut<'a>(
517+
&'a mut self,
518+
) -> impl Iterator<Item = &'a mut PatStack<'p, 'tcx>> + DoubleEndedIterator + ExactSizeIterator
519+
{
520+
self.rows.iter_mut()
521+
}
499522
/// Iterate over the first component of each row
500523
fn heads<'a>(
501524
&'a self,
@@ -509,7 +532,8 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
509532
pcx: &PatCtxt<'_, 'p, 'tcx>,
510533
ctor: &Constructor<'tcx>,
511534
) -> Matrix<'p, 'tcx> {
512-
let mut matrix = Matrix::empty();
535+
let mut matrix =
536+
Matrix::empty(self.wildcard_row.pop_head_constructor(pcx, ctor, usize::MAX));
513537
for (i, row) in self.rows().enumerate() {
514538
if ctor.is_covered_by(pcx, row.head().ctor()) {
515539
let new_row = row.pop_head_constructor(pcx, ctor, i);
@@ -741,18 +765,17 @@ impl<'tcx> WitnessMatrix<'tcx> {
741765
fn compute_usefulness<'p, 'tcx>(
742766
cx: &MatchCheckCtxt<'p, 'tcx>,
743767
matrix: &mut Matrix<'p, 'tcx>,
744-
v: &PatStack<'p, 'tcx>,
745768
collect_witnesses: bool,
746769
lint_root: HirId,
747770
is_top_level: bool,
748771
) -> WitnessMatrix<'tcx> {
749-
debug_assert!(matrix.rows().all(|r| r.len() == v.len()));
772+
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
750773

751774
// The base case. We are pattern-matching on () and the return value is based on whether our
752775
// matrix has a row or not.
753-
if v.is_empty() {
776+
if matrix.column_count() == 0 {
754777
let mut useful = true;
755-
for row in matrix.rows.iter_mut() {
778+
for row in matrix.rows_mut() {
756779
row.is_useful = useful;
757780
useful = useful && row.is_under_guard;
758781
if !useful {
@@ -766,14 +789,7 @@ fn compute_usefulness<'p, 'tcx>(
766789
}
767790
}
768791

769-
let mut ty = v.head().ty();
770-
// Opaque types can't get destructured/split, but the patterns can
771-
// actually hint at hidden types, so we use the patterns' types instead.
772-
if let ty::Alias(ty::Opaque, ..) = ty.kind() {
773-
if let Some(row) = matrix.rows().next() {
774-
ty = row.head().ty();
775-
}
776-
}
792+
let ty = matrix.head_ty();
777793
debug!("ty: {ty:?}");
778794
let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level };
779795

@@ -870,9 +886,8 @@ fn compute_usefulness<'p, 'tcx>(
870886
|| matches!(ctor, Constructor::Wildcard | Constructor::Missing));
871887
debug!("specialize({:?})", ctor);
872888
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor);
873-
let v = v.pop_head_constructor(pcx, &ctor, usize::MAX);
874889
let mut witnesses = ensure_sufficient_stack(|| {
875-
compute_usefulness(cx, &mut spec_matrix, &v, collect_witnesses, lint_root, false)
890+
compute_usefulness(cx, &mut spec_matrix, collect_witnesses, lint_root, false)
876891
});
877892
if collect_witnesses {
878893
witnesses.apply_constructor(pcx, &missing_ctors, &ctor);
@@ -1009,16 +1024,15 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
10091024
scrut_ty: Ty<'tcx>,
10101025
scrut_span: Span,
10111026
) -> UsefulnessReport<'p, 'tcx> {
1012-
let mut matrix = Matrix::empty();
1027+
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
1028+
let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false);
1029+
let mut matrix = Matrix::empty(wildcard_row);
10131030
for (row_id, arm) in arms.iter().enumerate() {
10141031
let v = PatStack::from_pattern(arm.pat, row_id, arm.has_guard);
10151032
matrix.push(v);
10161033
}
10171034

1018-
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
1019-
let v = PatStack::from_pattern(wild_pattern, usize::MAX, false);
1020-
let non_exhaustiveness_witnesses =
1021-
compute_usefulness(cx, &mut matrix, &v, true, lint_root, true);
1035+
let non_exhaustiveness_witnesses = compute_usefulness(cx, &mut matrix, true, lint_root, true);
10221036
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
10231037
let arm_usefulness: Vec<_> = arms
10241038
.iter()

0 commit comments

Comments
 (0)