Skip to content

Commit f6fa49f

Browse files
committed
Store wildcard row in the matrix
1 parent 91ab856 commit f6fa49f

File tree

1 file changed

+48
-39
lines changed

1 file changed

+48
-39
lines changed

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

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -666,16 +666,15 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
666666
#[derive(Clone)]
667667
struct Matrix<'p, 'tcx> {
668668
rows: Vec<PatStack<'p, 'tcx>>,
669+
/// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
670+
/// each column. This must obey the same invariants as the real rows.
671+
wildcard_row: PatStack<'p, 'tcx>,
669672
}
670673

671674
impl<'p, 'tcx> Matrix<'p, 'tcx> {
672-
/// Make an empty matrix. Internal method, prefer [`Matrix::new`].
673-
fn empty() -> Self {
674-
Matrix { rows: vec![] }
675-
}
676675
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
677676
/// expands it. Internal method, prefer [`Matrix::new`].
678-
fn push(&mut self, row: PatStack<'p, 'tcx>) {
677+
fn expand_and_push(&mut self, row: PatStack<'p, 'tcx>) {
679678
if !row.is_empty() && row.head().is_or_pat() {
680679
// Expand nested or-patterns.
681680
for new_row in row.expand_or_pat() {
@@ -687,18 +686,48 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
687686
}
688687

689688
/// Build a new matrix from an iterator of `MatchArm`s.
690-
fn new<'a>(iter: impl Iterator<Item = &'a MatchArm<'p, 'tcx>>) -> Self
689+
fn new<'a>(
690+
cx: &MatchCheckCtxt<'p, 'tcx>,
691+
iter: impl Iterator<Item = &'a MatchArm<'p, 'tcx>>,
692+
scrut_ty: Ty<'tcx>,
693+
) -> Self
691694
where
692695
'p: 'a,
693696
{
694-
let mut matrix = Matrix::empty();
697+
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
698+
let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false);
699+
let mut matrix = Matrix { rows: vec![], wildcard_row };
695700
for (row_id, arm) in iter.enumerate() {
696701
let v = PatStack::from_pattern(arm.pat, row_id, arm.has_guard);
697-
matrix.push(v);
702+
matrix.expand_and_push(v);
698703
}
699704
matrix
700705
}
701706

707+
fn head_ty(&self) -> Option<Ty<'tcx>> {
708+
if self.column_count() == 0 {
709+
return None;
710+
}
711+
712+
let mut ty = self.wildcard_row.head().ty();
713+
// If the type is opaque and it is revealed anywhere in the column, we take the revealed
714+
// version. Otherwise we could encounter constructors for the revealed type and crash.
715+
let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..));
716+
if is_opaque(ty) {
717+
for pat in self.heads() {
718+
let pat_ty = pat.ty();
719+
if !is_opaque(pat_ty) {
720+
ty = pat_ty;
721+
break;
722+
}
723+
}
724+
}
725+
Some(ty)
726+
}
727+
fn column_count(&self) -> usize {
728+
self.wildcard_row.len()
729+
}
730+
702731
fn rows<'a>(
703732
&'a self,
704733
) -> impl Iterator<Item = &'a PatStack<'p, 'tcx>> + Clone + DoubleEndedIterator + ExactSizeIterator
@@ -725,11 +754,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
725754
pcx: &PatCtxt<'_, 'p, 'tcx>,
726755
ctor: &Constructor<'tcx>,
727756
) -> Matrix<'p, 'tcx> {
728-
let mut matrix = Matrix::empty();
757+
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, usize::MAX);
758+
let mut matrix = Matrix { rows: vec![], wildcard_row };
729759
for (i, row) in self.rows().enumerate() {
730760
if ctor.is_covered_by(pcx, row.head().ctor()) {
731761
let new_row = row.pop_head_constructor(pcx, ctor, i);
732-
matrix.push(new_row);
762+
matrix.expand_and_push(new_row);
733763
}
734764
}
735765
matrix
@@ -964,21 +994,17 @@ impl<'tcx> WitnessMatrix<'tcx> {
964994
/// - unspecialization, where we lift the results from the previous step into results for this step
965995
/// (using `apply_constructor` and by updating `row.reachable` for each parent row).
966996
/// This is all explained at the top of the file.
967-
///
968-
/// `wildcard_row` is a fictitious matrix row that has only wildcards, with the appropriate types to
969-
/// match what's in the columns of `matrix`.
970997
#[instrument(level = "debug", skip(cx, is_top_level), ret)]
971998
fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
972999
cx: &MatchCheckCtxt<'p, 'tcx>,
9731000
matrix: &mut Matrix<'p, 'tcx>,
974-
wildcard_row: &PatStack<'p, 'tcx>,
9751001
is_top_level: bool,
9761002
) -> WitnessMatrix<'tcx> {
977-
debug_assert!(matrix.rows().all(|r| r.len() == wildcard_row.len()));
1003+
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
9781004

979-
if wildcard_row.is_empty() {
980-
// The base case. We are morally pattern-matching on (). A row is reachable iff it has no
981-
// (unguarded) rows above it.
1005+
let Some(ty) = matrix.head_ty() else {
1006+
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
1007+
// A row is reachable iff it has no (unguarded) rows above it.
9821008
for row in matrix.rows_mut() {
9831009
// All rows are reachable until we find one without a guard.
9841010
row.reachable = true;
@@ -990,21 +1016,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
9901016
}
9911017
// No (unguarded) rows, so the match is not exhaustive. We return a new witness.
9921018
return WitnessMatrix::unit_witness();
993-
}
994-
995-
let mut ty = wildcard_row.head().ty();
996-
// If the type is opaque and it is revealed anywhere in the column, we take the revealed
997-
// version. Otherwise we could encounter constructors for the revealed type and crash.
998-
let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..));
999-
if is_opaque(ty) {
1000-
for pat in matrix.heads() {
1001-
let pat_ty = pat.ty();
1002-
if !is_opaque(pat_ty) {
1003-
ty = pat_ty;
1004-
break;
1005-
}
1006-
}
1007-
}
1019+
};
10081020

10091021
debug!("ty: {ty:?}");
10101022
let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level };
@@ -1032,9 +1044,8 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
10321044
debug!("specialize({:?})", ctor);
10331045
// Dig into rows that match `ctor`.
10341046
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor);
1035-
let wildcard_row = wildcard_row.pop_head_constructor(pcx, &ctor, usize::MAX);
10361047
let mut witnesses = ensure_sufficient_stack(|| {
1037-
compute_exhaustiveness_and_reachability(cx, &mut spec_matrix, &wildcard_row, false)
1048+
compute_exhaustiveness_and_reachability(cx, &mut spec_matrix, false)
10381049
});
10391050
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
10401051
witnesses.apply_constructor(pcx, &split_set.missing, &ctor);
@@ -1311,11 +1322,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
13111322
scrut_ty: Ty<'tcx>,
13121323
scrut_span: Span,
13131324
) -> UsefulnessReport<'p, 'tcx> {
1314-
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
1315-
let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false);
1316-
let mut matrix = Matrix::new(arms.iter());
1325+
let mut matrix = Matrix::new(cx, arms.iter(), scrut_ty);
13171326
let non_exhaustiveness_witnesses =
1318-
compute_exhaustiveness_and_reachability(cx, &mut matrix, &wildcard_row, true);
1327+
compute_exhaustiveness_and_reachability(cx, &mut matrix, true);
13191328

13201329
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
13211330
let arm_usefulness: Vec<_> = arms

0 commit comments

Comments
 (0)