Skip to content

Commit 1c0e8f0

Browse files
committed
Track row intersections
1 parent f4d794e commit 1c0e8f0

File tree

1 file changed

+37
-18
lines changed

1 file changed

+37
-18
lines changed

compiler/rustc_pattern_analysis/src/usefulness.rs

+37-18
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@
712712
//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
713713
//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
714714
715+
use rustc_index::bit_set::BitSet;
715716
use smallvec::{smallvec, SmallVec};
716717
use std::fmt;
717718

@@ -911,6 +912,10 @@ struct MatrixRow<'p, Cx: TypeCx> {
911912
/// [`compute_exhaustiveness_and_usefulness`] if the arm is found to be useful.
912913
/// This is reset to `false` when specializing.
913914
useful: bool,
915+
/// Tracks which rows above this one have an intersection with this one, i.e. such that there is
916+
/// a value that matches both rows.
917+
/// FIXME: Because of relevancy we may miss some intersections.
918+
intersects: BitSet<usize>,
914919
}
915920

916921
impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
@@ -938,6 +943,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
938943
parent_row: self.parent_row,
939944
is_under_guard: self.is_under_guard,
940945
useful: false,
946+
intersects: BitSet::new_empty(0), // Initialized in `Matrix::expand_and_push`.
941947
})
942948
}
943949

@@ -955,6 +961,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
955961
parent_row,
956962
is_under_guard: self.is_under_guard,
957963
useful: false,
964+
intersects: BitSet::new_empty(0), // Initialized in `Matrix::expand_and_push`.
958965
}
959966
}
960967
}
@@ -991,13 +998,15 @@ struct Matrix<'p, Cx: TypeCx> {
991998
impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
992999
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
9931000
/// expands it. Internal method, prefer [`Matrix::new`].
994-
fn expand_and_push(&mut self, row: MatrixRow<'p, Cx>) {
1001+
fn expand_and_push(&mut self, mut row: MatrixRow<'p, Cx>) {
9951002
if !row.is_empty() && row.head().is_or_pat() {
9961003
// Expand nested or-patterns.
997-
for new_row in row.expand_or_pat() {
1004+
for mut new_row in row.expand_or_pat() {
1005+
new_row.intersects = BitSet::new_empty(self.rows.len());
9981006
self.rows.push(new_row);
9991007
}
10001008
} else {
1009+
row.intersects = BitSet::new_empty(self.rows.len());
10011010
self.rows.push(row);
10021011
}
10031012
}
@@ -1022,6 +1031,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10221031
parent_row: row_id, // dummy, we won't read it
10231032
is_under_guard: arm.has_guard,
10241033
useful: false,
1034+
intersects: BitSet::new_empty(row_id),
10251035
};
10261036
matrix.expand_and_push(v);
10271037
}
@@ -1348,21 +1358,19 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
13481358
let Some(ty) = matrix.head_ty(mcx) else {
13491359
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
13501360
// A row is useful iff it has no (unguarded) rows above it.
1351-
for row in matrix.rows_mut() {
1352-
// All rows are useful until they're not.
1353-
row.useful = true;
1354-
// When there's an unguarded row, the match is exhaustive and any subsequent row is not
1355-
// useful.
1356-
if !row.is_under_guard {
1357-
return WitnessMatrix::empty();
1358-
}
1361+
let mut useful = true; // Whether the next row is useful.
1362+
for (i, row) in matrix.rows_mut().enumerate() {
1363+
row.useful = useful;
1364+
row.intersects.insert_range(0..i);
1365+
// The next rows stays useful if this one is under a guard.
1366+
useful &= row.is_under_guard;
13591367
}
1360-
// No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
1361-
// irrelevant.
1362-
return if matrix.wildcard_row.relevant {
1368+
return if useful && matrix.wildcard_row.relevant {
1369+
// The wildcard row is useful; the match is non-exhaustive.
13631370
WitnessMatrix::unit_witness()
13641371
} else {
1365-
// We choose to not report anything here; see at the top for details.
1372+
// Either the match is exhaustive, or we choose not to report anything because of
1373+
// relevancy. See at the top for details.
13661374
WitnessMatrix::empty()
13671375
};
13681376
};
@@ -1423,10 +1431,21 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14231431
// Accumulate the found witnesses.
14241432
ret.extend(witnesses);
14251433

1426-
// A parent row is useful if any of its children is.
1427-
for child_row in spec_matrix.rows() {
1428-
let parent_row = &mut matrix.rows[child_row.parent_row];
1429-
parent_row.useful = parent_row.useful || child_row.useful;
1434+
for (child_row_id, child_row) in spec_matrix.rows().enumerate() {
1435+
let parent_row_id = child_row.parent_row;
1436+
let parent_row = &mut matrix.rows[parent_row_id];
1437+
// A parent row is useful if any of its children is.
1438+
parent_row.useful |= child_row.useful;
1439+
for child_intersects in child_row.intersects.iter() {
1440+
// Convert the intersecting ids into ids for the parent matrix.
1441+
let parent_intersects = spec_matrix.rows[child_intersects].parent_row;
1442+
debug!("child row {child_row_id} intersects with child row {child_intersects}");
1443+
debug!("parent row {parent_row_id} intersects with parent row {parent_intersects}");
1444+
if parent_intersects != parent_row_id {
1445+
// self-intersect can happen with or-patterns
1446+
parent_row.intersects.insert(parent_intersects);
1447+
}
1448+
}
14301449
}
14311450
}
14321451

0 commit comments

Comments
 (0)