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
@@ -915,6 +916,11 @@ struct MatrixRow<'p, Cx: TypeCx> {
915916 /// [`compute_exhaustiveness_and_usefulness`] if the arm is found to be useful.
916917 /// This is reset to `false` when specializing.
917918 useful : bool ,
919+ /// Tracks which rows above this one have an intersection with this one, i.e. such that there is
920+ /// a value that matches both rows.
921+ /// Note: Because of relevancy we may miss some intersections. The intersections we do find are
922+ /// correct.
923+ intersects : BitSet < usize > ,
918924}
919925
920926impl < ' p , Cx : TypeCx > MatrixRow < ' p , Cx > {
@@ -942,6 +948,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
942948 parent_row : self . parent_row ,
943949 is_under_guard : self . is_under_guard ,
944950 useful : false ,
951+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
945952 } )
946953 }
947954
@@ -960,6 +967,7 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
960967 parent_row,
961968 is_under_guard : self . is_under_guard ,
962969 useful : false ,
970+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
963971 }
964972 }
965973}
@@ -998,13 +1006,15 @@ struct Matrix<'p, Cx: TypeCx> {
9981006impl < ' p , Cx : TypeCx > Matrix < ' p , Cx > {
9991007 /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
10001008 /// expands it. Internal method, prefer [`Matrix::new`].
1001- fn expand_and_push ( & mut self , row : MatrixRow < ' p , Cx > ) {
1009+ fn expand_and_push ( & mut self , mut row : MatrixRow < ' p , Cx > ) {
10021010 if !row. is_empty ( ) && row. head ( ) . is_or_pat ( ) {
10031011 // Expand nested or-patterns.
1004- for new_row in row. expand_or_pat ( ) {
1012+ for mut new_row in row. expand_or_pat ( ) {
1013+ new_row. intersects = BitSet :: new_empty ( self . rows . len ( ) ) ;
10051014 self . rows . push ( new_row) ;
10061015 }
10071016 } else {
1017+ row. intersects = BitSet :: new_empty ( self . rows . len ( ) ) ;
10081018 self . rows . push ( row) ;
10091019 }
10101020 }
@@ -1024,9 +1034,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10241034 for ( row_id, arm) in arms. iter ( ) . enumerate ( ) {
10251035 let v = MatrixRow {
10261036 pats : PatStack :: from_pattern ( arm. pat ) ,
1027- parent_row : row_id, // dummy, we won 't read it
1037+ parent_row : row_id, // dummy, we don 't read it
10281038 is_under_guard : arm. has_guard ,
10291039 useful : false ,
1040+ intersects : BitSet :: new_empty ( 0 ) , // Initialized in `Matrix::expand_and_push`.
10301041 } ;
10311042 matrix. expand_and_push ( v) ;
10321043 }
@@ -1354,21 +1365,19 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
13541365 let Some ( ty) = matrix. head_ty ( ) else {
13551366 // The base case: there are no columns in the matrix. We are morally pattern-matching on ().
13561367 // A row is useful iff it has no (unguarded) rows above it.
1357- for row in matrix. rows_mut ( ) {
1358- // All rows are useful until they're not.
1359- row. useful = true ;
1360- // When there's an unguarded row, the match is exhaustive and any subsequent row is not
1361- // useful.
1362- if !row. is_under_guard {
1363- return WitnessMatrix :: empty ( ) ;
1364- }
1368+ let mut useful = true ; // Whether the next row is useful.
1369+ for ( i, row) in matrix. rows_mut ( ) . enumerate ( ) {
1370+ row. useful = useful;
1371+ row. intersects . insert_range ( 0 ..i) ;
1372+ // The next rows stays useful if this one is under a guard.
1373+ useful &= row. is_under_guard ;
13651374 }
1366- // No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
1367- // irrelevant.
1368- return if matrix. wildcard_row_is_relevant {
1375+ return if useful && matrix. wildcard_row_is_relevant {
1376+ // The wildcard row is useful; the match is non-exhaustive.
13691377 WitnessMatrix :: unit_witness ( )
13701378 } else {
1371- // We choose to not report anything here; see at the top for details.
1379+ // Either the match is exhaustive, or we choose not to report anything because of
1380+ // relevancy. See at the top for details.
13721381 WitnessMatrix :: empty ( )
13731382 } ;
13741383 } ;
@@ -1429,10 +1438,19 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14291438 // Accumulate the found witnesses.
14301439 ret. extend ( witnesses) ;
14311440
1432- // A parent row is useful if any of its children is.
14331441 for child_row in spec_matrix. rows ( ) {
1434- let parent_row = & mut matrix. rows [ child_row. parent_row ] ;
1435- parent_row. useful = parent_row. useful || child_row. useful ;
1442+ let parent_row_id = child_row. parent_row ;
1443+ let parent_row = & mut matrix. rows [ parent_row_id] ;
1444+ // A parent row is useful if any of its children is.
1445+ parent_row. useful |= child_row. useful ;
1446+ for child_intersection in child_row. intersects . iter ( ) {
1447+ // Convert the intersecting ids into ids for the parent matrix.
1448+ let parent_intersection = spec_matrix. rows [ child_intersection] . parent_row ;
1449+ // Note: self-intersection can happen with or-patterns.
1450+ if parent_intersection != parent_row_id {
1451+ parent_row. intersects . insert ( parent_intersection) ;
1452+ }
1453+ }
14361454 }
14371455 }
14381456
0 commit comments