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 ;
715716use smallvec:: { smallvec, SmallVec } ;
716717use 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
916921impl < ' 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> {
991998impl < ' 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