@@ -767,12 +767,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
767767 fn ctor_arity ( & self , ctor : & Constructor < Cx > ) -> usize {
768768 self . cx . ctor_arity ( ctor, self . ty )
769769 }
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- }
776770 fn ctors_for_ty ( & self ) -> Result < ConstructorSet < Cx > , Cx :: Error > {
777771 self . cx . ctors_for_ty ( self . ty )
778772 }
@@ -828,6 +822,38 @@ impl fmt::Display for ValidityConstraint {
828822 }
829823}
830824
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+
831857/// Represents a pattern-tuple under investigation.
832858// The three lifetimes are:
833859// - 'p coming from the input
@@ -1001,10 +1027,9 @@ struct Matrix<'p, Cx: TypeCx> {
10011027 /// each column must have the same type. Each column corresponds to a place within the
10021028 /// scrutinee.
10031029 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 ] > ,
10081033 /// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top
10091034 /// of the file for details on relevancy.
10101035 wildcard_row_is_relevant : bool ,
@@ -1032,10 +1057,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10321057 scrut_ty : Cx :: Ty ,
10331058 scrut_validity : ValidityConstraint ,
10341059 ) -> Self {
1060+ let place_info = PlaceInfo { ty : scrut_ty, validity : scrut_validity, is_scrutinee : true } ;
10351061 let mut matrix = Matrix {
10361062 rows : Vec :: with_capacity ( arms. len ( ) ) ,
1037- place_ty : smallvec ! [ scrut_ty] ,
1038- place_validity : smallvec ! [ scrut_validity] ,
1063+ place_info : smallvec ! [ place_info] ,
10391064 wildcard_row_is_relevant : true ,
10401065 } ;
10411066 for ( row_id, arm) in arms. iter ( ) . enumerate ( ) {
@@ -1051,11 +1076,11 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10511076 matrix
10521077 }
10531078
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 ( )
10561081 }
10571082 fn column_count ( & self ) -> usize {
1058- self . place_ty . len ( )
1083+ self . place_info . len ( )
10591084 }
10601085
10611086 fn rows (
@@ -1083,18 +1108,13 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10831108 ctor : & Constructor < Cx > ,
10841109 ctor_is_relevant : bool ,
10851110 ) -> 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 ( ) ;
10941115 let mut matrix = Matrix {
10951116 rows : Vec :: new ( ) ,
1096- place_ty : specialized_place_ty,
1097- place_validity : specialized_place_validity,
1117+ place_info : specialized_place_info,
10981118 wildcard_row_is_relevant : self . wildcard_row_is_relevant && ctor_is_relevant,
10991119 } ;
11001120 for ( i, row) in self . rows ( ) . enumerate ( ) {
@@ -1127,11 +1147,11 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> {
11271147 . map ( |row| row. iter ( ) . map ( |pat| format ! ( "{pat:?}" ) ) . collect ( ) )
11281148 . collect ( ) ;
11291149 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 ( ) ) ;
11311151
11321152 let column_count = self . column_count ( ) ;
11331153 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) ;
11351155 let column_widths: Vec < usize > = ( 0 ..column_count)
11361156 . map ( |col| pretty_printed_matrix. iter ( ) . map ( |row| row[ col] . len ( ) ) . max ( ) . unwrap_or ( 0 ) )
11371157 . collect ( ) ;
@@ -1432,11 +1452,10 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
14321452/// - unspecialization, where we lift the results from the previous step into results for this step
14331453/// (using `apply_constructor` and by updating `row.useful` for each parent row).
14341454/// 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) ]
14361456fn compute_exhaustiveness_and_usefulness < ' a , ' p , Cx : TypeCx > (
14371457 mcx : UsefulnessCtxt < ' a , Cx > ,
14381458 matrix : & mut Matrix < ' p , Cx > ,
1439- is_top_level : bool ,
14401459) -> Result < WitnessMatrix < Cx > , Cx :: Error > {
14411460 debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix. column_count( ) ) ) ;
14421461
@@ -1447,7 +1466,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14471466 return Ok ( WitnessMatrix :: empty ( ) ) ;
14481467 }
14491468
1450- let Some ( ty ) = matrix. head_ty ( ) . cloned ( ) else {
1469+ let Some ( place ) = matrix. head_place ( ) else {
14511470 // The base case: there are no columns in the matrix. We are morally pattern-matching on ().
14521471 // A row is useful iff it has no (unguarded) rows above it.
14531472 let mut useful = true ; // Whether the next row is useful.
@@ -1467,18 +1486,17 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14671486 } ;
14681487 } ;
14691488
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) ;
14721492 let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
14731493
1474- // Whether the place/column we are inspecting is known to contain valid data.
1475- let place_validity = matrix. place_validity [ 0 ] ;
14761494 // We treat match scrutinees of type `!` or `EmptyEnum` differently.
14771495 let is_toplevel_exception =
1478- is_top_level && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1496+ place . is_scrutinee && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
14791497 // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
14801498 // 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 ( )
14821500 && ( is_toplevel_exception
14831501 || mcx. tycx . is_exhaustive_patterns_feature_on ( )
14841502 || mcx. tycx . is_min_exhaustive_patterns_feature_on ( ) ) ;
@@ -1504,7 +1522,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
15041522
15051523 // Decide what constructors to report.
15061524 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;
15081526 // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
15091527 let report_individual_missing_ctors = always_report_all || !all_missing;
15101528 // 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>(
15251543 let ctor_is_relevant = matches ! ( ctor, Constructor :: Missing ) || missing_ctors. is_empty ( ) ;
15261544 let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor, ctor_is_relevant) ?;
15271545 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)
15291547 } ) ?;
15301548
15311549 // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
@@ -1600,8 +1618,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
16001618) -> Result < UsefulnessReport < ' p , Cx > , Cx :: Error > {
16011619 let cx = UsefulnessCtxt { tycx } ;
16021620 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) ?;
16051622
16061623 let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
16071624 let arm_usefulness: Vec < _ > = arms
0 commit comments