@@ -767,12 +767,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
767
767
fn ctor_arity ( & self , ctor : & Constructor < Cx > ) -> usize {
768
768
self . cx . ctor_arity ( ctor, self . ty )
769
769
}
770
- fn ctor_sub_tys (
771
- & ' a self ,
772
- ctor : & ' a Constructor < Cx > ,
773
- ) -> impl Iterator < Item = Cx :: Ty > + ExactSizeIterator + Captures < ' a > {
774
- self . cx . ctor_sub_tys ( ctor, self . ty )
775
- }
776
770
fn ctors_for_ty ( & self ) -> Result < ConstructorSet < Cx > , Cx :: Error > {
777
771
self . cx . ctors_for_ty ( self . ty )
778
772
}
@@ -828,6 +822,38 @@ impl fmt::Display for ValidityConstraint {
828
822
}
829
823
}
830
824
825
+ /// Data about a place under investigation.
826
+ struct PlaceInfo < Cx : TypeCx > {
827
+ /// The type of the place.
828
+ ty : Cx :: Ty ,
829
+ /// Whether the place is known to contain valid data.
830
+ validity : ValidityConstraint ,
831
+ /// Whether the place is the scrutinee itself or a subplace of it.
832
+ is_scrutinee : bool ,
833
+ }
834
+
835
+ impl < Cx : TypeCx > PlaceInfo < Cx > {
836
+ fn specialize < ' a > (
837
+ & ' a self ,
838
+ cx : & ' a Cx ,
839
+ ctor : & ' a Constructor < Cx > ,
840
+ ) -> impl Iterator < Item = Self > + ExactSizeIterator + Captures < ' a > {
841
+ let ctor_sub_tys = cx. ctor_sub_tys ( ctor, & self . ty ) ;
842
+ let ctor_sub_validity = self . validity . specialize ( ctor) ;
843
+ ctor_sub_tys. map ( move |ty| PlaceInfo {
844
+ ty,
845
+ validity : ctor_sub_validity,
846
+ is_scrutinee : false ,
847
+ } )
848
+ }
849
+ }
850
+
851
+ impl < Cx : TypeCx > Clone for PlaceInfo < Cx > {
852
+ fn clone ( & self ) -> Self {
853
+ Self { ty : self . ty . clone ( ) , validity : self . validity , is_scrutinee : self . is_scrutinee }
854
+ }
855
+ }
856
+
831
857
/// Represents a pattern-tuple under investigation.
832
858
// The three lifetimes are:
833
859
// - 'p coming from the input
@@ -1001,10 +1027,9 @@ struct Matrix<'p, Cx: TypeCx> {
1001
1027
/// each column must have the same type. Each column corresponds to a place within the
1002
1028
/// scrutinee.
1003
1029
rows : Vec < MatrixRow < ' p , Cx > > ,
1004
- /// Track the type of each column/place.
1005
- place_ty : SmallVec < [ Cx :: Ty ; 2 ] > ,
1006
- /// Track for each column/place whether it contains a known valid value.
1007
- place_validity : SmallVec < [ ValidityConstraint ; 2 ] > ,
1030
+ /// Track info about each place. Each place corresponds to a column in `rows`, and their types
1031
+ /// must match.
1032
+ place_info : SmallVec < [ PlaceInfo < Cx > ; 2 ] > ,
1008
1033
/// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top
1009
1034
/// of the file for details on relevancy.
1010
1035
wildcard_row_is_relevant : bool ,
@@ -1032,10 +1057,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
1032
1057
scrut_ty : Cx :: Ty ,
1033
1058
scrut_validity : ValidityConstraint ,
1034
1059
) -> Self {
1060
+ let place_info = PlaceInfo { ty : scrut_ty, validity : scrut_validity, is_scrutinee : true } ;
1035
1061
let mut matrix = Matrix {
1036
1062
rows : Vec :: with_capacity ( arms. len ( ) ) ,
1037
- place_ty : smallvec ! [ scrut_ty] ,
1038
- place_validity : smallvec ! [ scrut_validity] ,
1063
+ place_info : smallvec ! [ place_info] ,
1039
1064
wildcard_row_is_relevant : true ,
1040
1065
} ;
1041
1066
for ( row_id, arm) in arms. iter ( ) . enumerate ( ) {
@@ -1051,11 +1076,11 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
1051
1076
matrix
1052
1077
}
1053
1078
1054
- fn head_ty ( & self ) -> Option < & Cx :: Ty > {
1055
- self . place_ty . first ( )
1079
+ fn head_place ( & self ) -> Option < & PlaceInfo < Cx > > {
1080
+ self . place_info . first ( )
1056
1081
}
1057
1082
fn column_count ( & self ) -> usize {
1058
- self . place_ty . len ( )
1083
+ self . place_info . len ( )
1059
1084
}
1060
1085
1061
1086
fn rows (
@@ -1083,18 +1108,13 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
1083
1108
ctor : & Constructor < Cx > ,
1084
1109
ctor_is_relevant : bool ,
1085
1110
) -> Result < Matrix < ' p , Cx > , Cx :: Error > {
1086
- let ctor_sub_tys = pcx. ctor_sub_tys ( ctor) ;
1087
- let arity = ctor_sub_tys. len ( ) ;
1088
- let specialized_place_ty = ctor_sub_tys. chain ( self . place_ty [ 1 ..] . iter ( ) . cloned ( ) ) . collect ( ) ;
1089
- let ctor_sub_validity = self . place_validity [ 0 ] . specialize ( ctor) ;
1090
- let specialized_place_validity = std:: iter:: repeat ( ctor_sub_validity)
1091
- . take ( arity)
1092
- . chain ( self . place_validity [ 1 ..] . iter ( ) . copied ( ) )
1093
- . collect ( ) ;
1111
+ let subfield_place_info = self . place_info [ 0 ] . specialize ( pcx. cx , ctor) ;
1112
+ let arity = subfield_place_info. len ( ) ;
1113
+ let specialized_place_info =
1114
+ subfield_place_info. chain ( self . place_info [ 1 ..] . iter ( ) . cloned ( ) ) . collect ( ) ;
1094
1115
let mut matrix = Matrix {
1095
1116
rows : Vec :: new ( ) ,
1096
- place_ty : specialized_place_ty,
1097
- place_validity : specialized_place_validity,
1117
+ place_info : specialized_place_info,
1098
1118
wildcard_row_is_relevant : self . wildcard_row_is_relevant && ctor_is_relevant,
1099
1119
} ;
1100
1120
for ( i, row) in self . rows ( ) . enumerate ( ) {
@@ -1127,11 +1147,11 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> {
1127
1147
. map ( |row| row. iter ( ) . map ( |pat| format ! ( "{pat:?}" ) ) . collect ( ) )
1128
1148
. collect ( ) ;
1129
1149
pretty_printed_matrix
1130
- . push ( self . place_validity . iter ( ) . map ( |validity | format ! ( "{validity}" ) ) . collect ( ) ) ;
1150
+ . push ( self . place_info . iter ( ) . map ( |place | format ! ( "{}" , place . validity ) ) . collect ( ) ) ;
1131
1151
1132
1152
let column_count = self . column_count ( ) ;
1133
1153
assert ! ( self . rows. iter( ) . all( |row| row. len( ) == column_count) ) ;
1134
- assert ! ( self . place_validity . len( ) == column_count) ;
1154
+ assert ! ( self . place_info . len( ) == column_count) ;
1135
1155
let column_widths: Vec < usize > = ( 0 ..column_count)
1136
1156
. map ( |col| pretty_printed_matrix. iter ( ) . map ( |row| row[ col] . len ( ) ) . max ( ) . unwrap_or ( 0 ) )
1137
1157
. collect ( ) ;
@@ -1432,11 +1452,10 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
1432
1452
/// - unspecialization, where we lift the results from the previous step into results for this step
1433
1453
/// (using `apply_constructor` and by updating `row.useful` for each parent row).
1434
1454
/// This is all explained at the top of the file.
1435
- #[ instrument( level = "debug" , skip( mcx, is_top_level ) , ret) ]
1455
+ #[ instrument( level = "debug" , skip( mcx) , ret) ]
1436
1456
fn compute_exhaustiveness_and_usefulness < ' a , ' p , Cx : TypeCx > (
1437
1457
mcx : UsefulnessCtxt < ' a , Cx > ,
1438
1458
matrix : & mut Matrix < ' p , Cx > ,
1439
- is_top_level : bool ,
1440
1459
) -> Result < WitnessMatrix < Cx > , Cx :: Error > {
1441
1460
debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix. column_count( ) ) ) ;
1442
1461
@@ -1447,7 +1466,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1447
1466
return Ok ( WitnessMatrix :: empty ( ) ) ;
1448
1467
}
1449
1468
1450
- let Some ( ty ) = matrix. head_ty ( ) . cloned ( ) else {
1469
+ let Some ( place ) = matrix. head_place ( ) else {
1451
1470
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
1452
1471
// A row is useful iff it has no (unguarded) rows above it.
1453
1472
let mut useful = true ; // Whether the next row is useful.
@@ -1467,18 +1486,17 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1467
1486
} ;
1468
1487
} ;
1469
1488
1470
- debug ! ( "ty: {ty:?}" ) ;
1471
- let pcx = & PlaceCtxt { cx : mcx. tycx , ty : & ty } ;
1489
+ let ty = & place. ty . clone ( ) ; // Clone it out so we can mutate `matrix` later.
1490
+ let pcx = & PlaceCtxt { cx : mcx. tycx , ty } ;
1491
+ debug ! ( "ty: {:?}" , pcx. ty) ;
1472
1492
let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1473
1493
1474
- // Whether the place/column we are inspecting is known to contain valid data.
1475
- let place_validity = matrix. place_validity [ 0 ] ;
1476
1494
// We treat match scrutinees of type `!` or `EmptyEnum` differently.
1477
1495
let is_toplevel_exception =
1478
- is_top_level && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1496
+ place . is_scrutinee && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1479
1497
// Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
1480
1498
// it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
1481
- let empty_arms_are_unreachable = place_validity . is_known_valid ( )
1499
+ let empty_arms_are_unreachable = place . validity . is_known_valid ( )
1482
1500
&& ( is_toplevel_exception
1483
1501
|| mcx. tycx . is_exhaustive_patterns_feature_on ( )
1484
1502
|| mcx. tycx . is_min_exhaustive_patterns_feature_on ( ) ) ;
@@ -1504,7 +1522,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1504
1522
1505
1523
// Decide what constructors to report.
1506
1524
let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ;
1507
- let always_report_all = is_top_level && !is_integers;
1525
+ let always_report_all = place . is_scrutinee && !is_integers;
1508
1526
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
1509
1527
let report_individual_missing_ctors = always_report_all || !all_missing;
1510
1528
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
@@ -1525,7 +1543,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1525
1543
let ctor_is_relevant = matches ! ( ctor, Constructor :: Missing ) || missing_ctors. is_empty ( ) ;
1526
1544
let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor, ctor_is_relevant) ?;
1527
1545
let mut witnesses = ensure_sufficient_stack ( || {
1528
- compute_exhaustiveness_and_usefulness ( mcx, & mut spec_matrix, false )
1546
+ compute_exhaustiveness_and_usefulness ( mcx, & mut spec_matrix)
1529
1547
} ) ?;
1530
1548
1531
1549
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
@@ -1600,8 +1618,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
1600
1618
) -> Result < UsefulnessReport < ' p , Cx > , Cx :: Error > {
1601
1619
let cx = UsefulnessCtxt { tycx } ;
1602
1620
let mut matrix = Matrix :: new ( arms, scrut_ty, scrut_validity) ;
1603
- let non_exhaustiveness_witnesses =
1604
- compute_exhaustiveness_and_usefulness ( cx, & mut matrix, true ) ?;
1621
+ let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness ( cx, & mut matrix) ?;
1605
1622
1606
1623
let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
1607
1624
let arm_usefulness: Vec < _ > = arms
0 commit comments