@@ -760,9 +760,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
760
760
fn ctor_arity ( & self , ctor : & Constructor < Cx > ) -> usize {
761
761
self . cx . ctor_arity ( ctor, self . ty )
762
762
}
763
- fn ctors_for_ty ( & self ) -> Result < ConstructorSet < Cx > , Cx :: Error > {
764
- self . cx . ctors_for_ty ( self . ty )
765
- }
766
763
fn wild_from_ctor ( & self , ctor : Constructor < Cx > ) -> WitnessPat < Cx > {
767
764
WitnessPat :: wild_from_ctor ( self . cx , ctor, self . ty . clone ( ) )
768
765
}
@@ -815,7 +812,8 @@ impl fmt::Display for ValidityConstraint {
815
812
}
816
813
}
817
814
818
- /// Data about a place under investigation.
815
+ /// Data about a place under investigation. Its methods contain a lot of the logic used to analyze
816
+ /// the constructors in the matrix.
819
817
struct PlaceInfo < Cx : TypeCx > {
820
818
/// The type of the place.
821
819
ty : Cx :: Ty ,
@@ -826,6 +824,8 @@ struct PlaceInfo<Cx: TypeCx> {
826
824
}
827
825
828
826
impl < Cx : TypeCx > PlaceInfo < Cx > {
827
+ /// Given a constructor for the current place, we return one `PlaceInfo` for each field of the
828
+ /// constructor.
829
829
fn specialize < ' a > (
830
830
& ' a self ,
831
831
cx : & ' a Cx ,
@@ -839,6 +839,77 @@ impl<Cx: TypeCx> PlaceInfo<Cx> {
839
839
is_scrutinee : false ,
840
840
} )
841
841
}
842
+
843
+ /// This analyzes a column of constructors corresponding to the current place. It returns a pair
844
+ /// `(split_ctors, missing_ctors)`.
845
+ ///
846
+ /// `split_ctors` is a splitted list of constructors that cover the whole type. This will be
847
+ /// used to specialize the matrix.
848
+ ///
849
+ /// `missing_ctors` is a list of the constructors not found in the column, for reporting
850
+ /// purposes.
851
+ fn split_column_ctors < ' a > (
852
+ & self ,
853
+ cx : & Cx ,
854
+ ctors : impl Iterator < Item = & ' a Constructor < Cx > > + Clone ,
855
+ ) -> Result < ( SmallVec < [ Constructor < Cx > ; 1 ] > , Vec < Constructor < Cx > > ) , Cx :: Error >
856
+ where
857
+ Cx : ' a ,
858
+ {
859
+ let ctors_for_ty = cx. ctors_for_ty ( & self . ty ) ?;
860
+
861
+ // We treat match scrutinees of type `!` or `EmptyEnum` differently.
862
+ let is_toplevel_exception =
863
+ self . is_scrutinee && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
864
+ // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
865
+ // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
866
+ let empty_arms_are_unreachable = self . validity . is_known_valid ( )
867
+ && ( is_toplevel_exception
868
+ || cx. is_exhaustive_patterns_feature_on ( )
869
+ || cx. is_min_exhaustive_patterns_feature_on ( ) ) ;
870
+ // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
871
+ // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
872
+ let can_omit_empty_arms = empty_arms_are_unreachable
873
+ || is_toplevel_exception
874
+ || cx. is_exhaustive_patterns_feature_on ( ) ;
875
+
876
+ // Analyze the constructors present in this column.
877
+ let mut split_set = ctors_for_ty. split ( ctors) ;
878
+ let all_missing = split_set. present . is_empty ( ) ;
879
+
880
+ // Build the set of constructors we will specialize with. It must cover the whole type, so
881
+ // we add `Missing` to represent the missing ones. This is explained under "Constructor
882
+ // Splitting" at the top of this file.
883
+ let mut split_ctors = split_set. present ;
884
+ if !( split_set. missing . is_empty ( )
885
+ && ( split_set. missing_empty . is_empty ( ) || empty_arms_are_unreachable) )
886
+ {
887
+ split_ctors. push ( Constructor :: Missing ) ;
888
+ }
889
+
890
+ // Which empty constructors are considered missing. We ensure that
891
+ // `!missing_ctors.is_empty() => split_ctors.contains(Missing)`. The converse usually holds
892
+ // except when `!self.validity.is_known_valid()`.
893
+ let mut missing_ctors = split_set. missing ;
894
+ if !can_omit_empty_arms {
895
+ missing_ctors. append ( & mut split_set. missing_empty ) ;
896
+ }
897
+
898
+ // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top
899
+ // level we prefer to list all constructors.
900
+ let report_individual_missing_ctors = self . is_scrutinee || !all_missing;
901
+ if !missing_ctors. is_empty ( ) && !report_individual_missing_ctors {
902
+ // Report `_` as missing.
903
+ missing_ctors = vec ! [ Constructor :: Wildcard ] ;
904
+ } else if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
905
+ // We need to report a `_` anyway, so listing other constructors would be redundant.
906
+ // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
907
+ // up by diagnostics to add a note about why `_` is required here.
908
+ missing_ctors = vec ! [ Constructor :: NonExhaustive ] ;
909
+ }
910
+
911
+ Ok ( ( split_ctors, missing_ctors) )
912
+ }
842
913
}
843
914
844
915
impl < Cx : TypeCx > Clone for PlaceInfo < Cx > {
@@ -1314,40 +1385,23 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
1314
1385
pcx : & PlaceCtxt < ' _ , Cx > ,
1315
1386
missing_ctors : & [ Constructor < Cx > ] ,
1316
1387
ctor : & Constructor < Cx > ,
1317
- report_individual_missing_ctors : bool ,
1318
1388
) {
1319
1389
if self . is_empty ( ) {
1320
1390
return ;
1321
1391
}
1322
1392
if matches ! ( ctor, Constructor :: Missing ) {
1323
1393
// We got the special `Missing` constructor that stands for the constructors not present
1324
- // in the match.
1325
- if missing_ctors. is_empty ( ) {
1326
- // Nothing to report.
1327
- * self = Self :: empty ( ) ;
1328
- } else if !report_individual_missing_ctors {
1329
- // Report `_` as missing.
1330
- let pat = pcx. wild_from_ctor ( Constructor :: Wildcard ) ;
1331
- self . push_pattern ( pat) ;
1332
- } else if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
1333
- // We need to report a `_` anyway, so listing other constructors would be redundant.
1334
- // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
1335
- // up by diagnostics to add a note about why `_` is required here.
1336
- let pat = pcx. wild_from_ctor ( Constructor :: NonExhaustive ) ;
1337
- self . push_pattern ( pat) ;
1338
- } else {
1339
- // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately
1340
- // filled with wildcards.
1341
- let mut ret = Self :: empty ( ) ;
1342
- for ctor in missing_ctors {
1343
- let pat = pcx. wild_from_ctor ( ctor. clone ( ) ) ;
1344
- // Clone `self` and add `c(_, _, _)` to each of its witnesses.
1345
- let mut wit_matrix = self . clone ( ) ;
1346
- wit_matrix. push_pattern ( pat) ;
1347
- ret. extend ( wit_matrix) ;
1348
- }
1349
- * self = ret;
1394
+ // in the match. For each missing constructor `c`, we add a `c(_, _, _)` witness
1395
+ // appropriately filled with wildcards.
1396
+ let mut ret = Self :: empty ( ) ;
1397
+ for ctor in missing_ctors {
1398
+ let pat = pcx. wild_from_ctor ( ctor. clone ( ) ) ;
1399
+ // Clone `self` and add `c(_, _, _)` to each of its witnesses.
1400
+ let mut wit_matrix = self . clone ( ) ;
1401
+ wit_matrix. push_pattern ( pat) ;
1402
+ ret. extend ( wit_matrix) ;
1350
1403
}
1404
+ * self = ret;
1351
1405
} else {
1352
1406
// Any other constructor we unspecialize as expected.
1353
1407
for witness in self . 0 . iter_mut ( ) {
@@ -1479,51 +1533,13 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1479
1533
} ;
1480
1534
} ;
1481
1535
1482
- let ty = & place. ty . clone ( ) ; // Clone it out so we can mutate `matrix` later.
1483
- let pcx = & PlaceCtxt { cx : mcx. tycx , ty } ;
1484
- debug ! ( "ty: {:?}" , pcx. ty) ;
1485
- let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1486
-
1487
- // We treat match scrutinees of type `!` or `EmptyEnum` differently.
1488
- let is_toplevel_exception =
1489
- place. is_scrutinee && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1490
- // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
1491
- // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
1492
- let empty_arms_are_unreachable = place. validity . is_known_valid ( )
1493
- && ( is_toplevel_exception
1494
- || mcx. tycx . is_exhaustive_patterns_feature_on ( )
1495
- || mcx. tycx . is_min_exhaustive_patterns_feature_on ( ) ) ;
1496
- // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
1497
- // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
1498
- let can_omit_empty_arms = empty_arms_are_unreachable
1499
- || is_toplevel_exception
1500
- || mcx. tycx . is_exhaustive_patterns_feature_on ( ) ;
1501
-
1502
1536
// Analyze the constructors present in this column.
1537
+ debug ! ( "ty: {:?}" , place. ty) ;
1503
1538
let ctors = matrix. heads ( ) . map ( |p| p. ctor ( ) ) ;
1504
- let mut split_set = ctors_for_ty. split ( ctors) ;
1505
- let all_missing = split_set. present . is_empty ( ) ;
1506
- // Build the set of constructors we will specialize with. It must cover the whole type.
1507
- // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1508
- // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1509
- let mut split_ctors = split_set. present ;
1510
- if !( split_set. missing . is_empty ( )
1511
- && ( split_set. missing_empty . is_empty ( ) || empty_arms_are_unreachable) )
1512
- {
1513
- split_ctors. push ( Constructor :: Missing ) ;
1514
- }
1515
-
1516
- // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top
1517
- // level we prefer to list all constructors.
1518
- let report_individual_missing_ctors = place. is_scrutinee || !all_missing;
1519
- // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
1520
- // split_ctors.contains(Missing)`. The converse usually holds except when
1521
- // `!place_validity.is_known_valid()`.
1522
- let mut missing_ctors = split_set. missing ;
1523
- if !can_omit_empty_arms {
1524
- missing_ctors. append ( & mut split_set. missing_empty ) ;
1525
- }
1539
+ let ( split_ctors, missing_ctors) = place. split_column_ctors ( mcx. tycx , ctors) ?;
1526
1540
1541
+ let ty = & place. ty . clone ( ) ; // Clone it out so we can mutate `matrix` later.
1542
+ let pcx = & PlaceCtxt { cx : mcx. tycx , ty } ;
1527
1543
let mut ret = WitnessMatrix :: empty ( ) ;
1528
1544
for ctor in split_ctors {
1529
1545
// Dig into rows that match `ctor`.
@@ -1538,7 +1554,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1538
1554
} ) ?;
1539
1555
1540
1556
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1541
- witnesses. apply_constructor ( pcx, & missing_ctors, & ctor, report_individual_missing_ctors ) ;
1557
+ witnesses. apply_constructor ( pcx, & missing_ctors, & ctor) ;
1542
1558
// Accumulate the found witnesses.
1543
1559
ret. extend ( witnesses) ;
1544
1560
0 commit comments