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,10 @@ 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
+ /// FIXME: Because of relevancy we may miss some intersections.
918
+ intersects : BitSet < usize > ,
914
919
}
915
920
916
921
impl < ' p , Cx : TypeCx > MatrixRow < ' p , Cx > {
@@ -938,6 +943,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
938
943
parent_row : self . parent_row ,
939
944
is_under_guard : self . is_under_guard ,
940
945
useful : false ,
946
+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
941
947
} )
942
948
}
943
949
@@ -955,6 +961,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
955
961
parent_row,
956
962
is_under_guard : self . is_under_guard ,
957
963
useful : false ,
964
+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
958
965
}
959
966
}
960
967
}
@@ -991,13 +998,15 @@ struct Matrix<'p, Cx: TypeCx> {
991
998
impl < ' p , Cx : TypeCx > Matrix < ' p , Cx > {
992
999
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
993
1000
/// 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 > ) {
995
1002
if !row. is_empty ( ) && row. head ( ) . is_or_pat ( ) {
996
1003
// 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 ( ) ) ;
998
1006
self . rows . push ( new_row) ;
999
1007
}
1000
1008
} else {
1009
+ row. intersects = BitSet :: new_empty ( self . rows . len ( ) ) ;
1001
1010
self . rows . push ( row) ;
1002
1011
}
1003
1012
}
@@ -1022,6 +1031,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
1022
1031
parent_row : row_id, // dummy, we won't read it
1023
1032
is_under_guard : arm. has_guard ,
1024
1033
useful : false ,
1034
+ intersects : BitSet :: new_empty ( row_id) ,
1025
1035
} ;
1026
1036
matrix. expand_and_push ( v) ;
1027
1037
}
@@ -1348,21 +1358,19 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1348
1358
let Some ( ty) = matrix. head_ty ( mcx) else {
1349
1359
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
1350
1360
// 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 ;
1359
1367
}
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.
1363
1370
WitnessMatrix :: unit_witness ( )
1364
1371
} 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.
1366
1374
WitnessMatrix :: empty ( )
1367
1375
} ;
1368
1376
} ;
@@ -1423,10 +1431,21 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1423
1431
// Accumulate the found witnesses.
1424
1432
ret. extend ( witnesses) ;
1425
1433
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
+ }
1430
1449
}
1431
1450
}
1432
1451
0 commit comments