712
712
//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
713
713
//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
714
714
715
+ use rustc_index:: bit_set:: BitSet ;
715
716
use smallvec:: { smallvec, SmallVec } ;
716
717
use std:: fmt;
717
718
@@ -911,6 +912,11 @@ struct MatrixRow<'p, Cx: TypeCx> {
911
912
/// [`compute_exhaustiveness_and_usefulness`] if the arm is found to be useful.
912
913
/// This is reset to `false` when specializing.
913
914
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
+ /// Note: Because of relevancy we may miss some intersections. The intersections we do find are
918
+ /// correct.
919
+ intersects : BitSet < usize > ,
914
920
}
915
921
916
922
impl < ' p , Cx : TypeCx > MatrixRow < ' p , Cx > {
@@ -938,6 +944,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
938
944
parent_row : self . parent_row ,
939
945
is_under_guard : self . is_under_guard ,
940
946
useful : false ,
947
+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
941
948
} )
942
949
}
943
950
@@ -955,6 +962,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
955
962
parent_row,
956
963
is_under_guard : self . is_under_guard ,
957
964
useful : false ,
965
+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
958
966
}
959
967
}
960
968
}
@@ -993,13 +1001,15 @@ struct Matrix<'p, Cx: TypeCx> {
993
1001
impl < ' p , Cx : TypeCx > Matrix < ' p , Cx > {
994
1002
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
995
1003
/// expands it. Internal method, prefer [`Matrix::new`].
996
- fn expand_and_push ( & mut self , row : MatrixRow < ' p , Cx > ) {
1004
+ fn expand_and_push ( & mut self , mut row : MatrixRow < ' p , Cx > ) {
997
1005
if !row. is_empty ( ) && row. head ( ) . is_or_pat ( ) {
998
1006
// Expand nested or-patterns.
999
- for new_row in row. expand_or_pat ( ) {
1007
+ for mut new_row in row. expand_or_pat ( ) {
1008
+ new_row. intersects = BitSet :: new_empty ( self . rows . len ( ) ) ;
1000
1009
self . rows . push ( new_row) ;
1001
1010
}
1002
1011
} else {
1012
+ row. intersects = BitSet :: new_empty ( self . rows . len ( ) ) ;
1003
1013
self . rows . push ( row) ;
1004
1014
}
1005
1015
}
@@ -1019,9 +1029,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
1019
1029
for ( row_id, arm) in arms. iter ( ) . enumerate ( ) {
1020
1030
let v = MatrixRow {
1021
1031
pats : PatStack :: from_pattern ( arm. pat ) ,
1022
- parent_row : row_id, // dummy, we won 't read it
1032
+ parent_row : row_id, // dummy, we don 't read it
1023
1033
is_under_guard : arm. has_guard ,
1024
1034
useful : false ,
1035
+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
1025
1036
} ;
1026
1037
matrix. expand_and_push ( v) ;
1027
1038
}
@@ -1349,21 +1360,19 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1349
1360
let Some ( ty) = matrix. head_ty ( ) else {
1350
1361
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
1351
1362
// A row is useful iff it has no (unguarded) rows above it.
1352
- for row in matrix. rows_mut ( ) {
1353
- // All rows are useful until they're not.
1354
- row. useful = true ;
1355
- // When there's an unguarded row, the match is exhaustive and any subsequent row is not
1356
- // useful.
1357
- if !row. is_under_guard {
1358
- return Ok ( WitnessMatrix :: empty ( ) ) ;
1359
- }
1363
+ let mut useful = true ; // Whether the next row is useful.
1364
+ for ( i, row) in matrix. rows_mut ( ) . enumerate ( ) {
1365
+ row. useful = useful;
1366
+ row. intersects . insert_range ( 0 ..i) ;
1367
+ // The next rows stays useful if this one is under a guard.
1368
+ useful &= row. is_under_guard ;
1360
1369
}
1361
- // No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
1362
- // irrelevant.
1363
- return if matrix. wildcard_row_is_relevant {
1370
+ return if useful && matrix. wildcard_row_is_relevant {
1371
+ // The wildcard row is useful; the match is non-exhaustive.
1364
1372
Ok ( WitnessMatrix :: unit_witness ( ) )
1365
1373
} else {
1366
- // We choose to not report anything here; see at the top for details.
1374
+ // Either the match is exhaustive, or we choose not to report anything because of
1375
+ // relevancy. See at the top for details.
1367
1376
Ok ( WitnessMatrix :: empty ( ) )
1368
1377
} ;
1369
1378
} ;
@@ -1424,10 +1433,19 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1424
1433
// Accumulate the found witnesses.
1425
1434
ret. extend ( witnesses) ;
1426
1435
1427
- // A parent row is useful if any of its children is.
1428
1436
for child_row in spec_matrix. rows ( ) {
1429
- let parent_row = & mut matrix. rows [ child_row. parent_row ] ;
1430
- parent_row. useful = parent_row. useful || child_row. useful ;
1437
+ let parent_row_id = child_row. parent_row ;
1438
+ let parent_row = & mut matrix. rows [ parent_row_id] ;
1439
+ // A parent row is useful if any of its children is.
1440
+ parent_row. useful |= child_row. useful ;
1441
+ for child_intersection in child_row. intersects . iter ( ) {
1442
+ // Convert the intersecting ids into ids for the parent matrix.
1443
+ let parent_intersection = spec_matrix. rows [ child_intersection] . parent_row ;
1444
+ // Note: self-intersection can happen with or-patterns.
1445
+ if parent_intersection != parent_row_id {
1446
+ parent_row. intersects . insert ( parent_intersection) ;
1447
+ }
1448
+ }
1431
1449
}
1432
1450
}
1433
1451
0 commit comments