@@ -760,9 +760,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
760760 fn ctor_arity ( & self , ctor : & Constructor < Cx > ) -> usize {
761761 self . cx . ctor_arity ( ctor, self . ty )
762762 }
763- fn ctors_for_ty ( & self ) -> Result < ConstructorSet < Cx > , Cx :: Error > {
764- self . cx . ctors_for_ty ( self . ty )
765- }
766763 fn wild_from_ctor ( & self , ctor : Constructor < Cx > ) -> WitnessPat < Cx > {
767764 WitnessPat :: wild_from_ctor ( self . cx , ctor, self . ty . clone ( ) )
768765 }
@@ -815,7 +812,8 @@ impl fmt::Display for ValidityConstraint {
815812 }
816813}
817814
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.
819817struct PlaceInfo < Cx : TypeCx > {
820818 /// The type of the place.
821819 ty : Cx :: Ty ,
@@ -826,6 +824,8 @@ struct PlaceInfo<Cx: TypeCx> {
826824}
827825
828826impl < Cx : TypeCx > PlaceInfo < Cx > {
827+ /// Given a constructor for the current place, we return one `PlaceInfo` for each field of the
828+ /// constructor.
829829 fn specialize < ' a > (
830830 & ' a self ,
831831 cx : & ' a Cx ,
@@ -839,6 +839,77 @@ impl<Cx: TypeCx> PlaceInfo<Cx> {
839839 is_scrutinee : false ,
840840 } )
841841 }
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+ }
842913}
843914
844915impl < Cx : TypeCx > Clone for PlaceInfo < Cx > {
@@ -1462,61 +1533,13 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14621533 } ;
14631534 } ;
14641535
1465- let ty = & place. ty . clone ( ) ; // Clone it out so we can mutate `matrix` later.
1466- let pcx = & PlaceCtxt { cx : mcx. tycx , ty } ;
1467- debug ! ( "ty: {:?}" , pcx. ty) ;
1468- let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1469-
1470- // We treat match scrutinees of type `!` or `EmptyEnum` differently.
1471- let is_toplevel_exception =
1472- place. is_scrutinee && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1473- // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
1474- // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
1475- let empty_arms_are_unreachable = place. validity . is_known_valid ( )
1476- && ( is_toplevel_exception
1477- || mcx. tycx . is_exhaustive_patterns_feature_on ( )
1478- || mcx. tycx . is_min_exhaustive_patterns_feature_on ( ) ) ;
1479- // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
1480- // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
1481- let can_omit_empty_arms = empty_arms_are_unreachable
1482- || is_toplevel_exception
1483- || mcx. tycx . is_exhaustive_patterns_feature_on ( ) ;
1484-
14851536 // Analyze the constructors present in this column.
1537+ debug ! ( "ty: {:?}" , place. ty) ;
14861538 let ctors = matrix. heads ( ) . map ( |p| p. ctor ( ) ) ;
1487- let mut split_set = ctors_for_ty. split ( ctors) ;
1488- let all_missing = split_set. present . is_empty ( ) ;
1489- // Build the set of constructors we will specialize with. It must cover the whole type.
1490- // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1491- // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1492- let mut split_ctors = split_set. present ;
1493- if !( split_set. missing . is_empty ( )
1494- && ( split_set. missing_empty . is_empty ( ) || empty_arms_are_unreachable) )
1495- {
1496- split_ctors. push ( Constructor :: Missing ) ;
1497- }
1498-
1499- // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
1500- // split_ctors.contains(Missing)`. The converse usually holds except when
1501- // `!place_validity.is_known_valid()`.
1502- let mut missing_ctors = split_set. missing ;
1503- if !can_omit_empty_arms {
1504- missing_ctors. append ( & mut split_set. missing_empty ) ;
1505- }
1506-
1507- // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top
1508- // level we prefer to list all constructors.
1509- let report_individual_missing_ctors = place. is_scrutinee || !all_missing;
1510- if !missing_ctors. is_empty ( ) && !report_individual_missing_ctors {
1511- // Report `_` as missing.
1512- missing_ctors = vec ! [ Constructor :: Wildcard ] ;
1513- } else if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
1514- // We need to report a `_` anyway, so listing other constructors would be redundant.
1515- // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
1516- // up by diagnostics to add a note about why `_` is required here.
1517- missing_ctors = vec ! [ Constructor :: NonExhaustive ] ;
1518- }
1539+ let ( split_ctors, missing_ctors) = place. split_column_ctors ( mcx. tycx , ctors) ?;
15191540
1541+ let ty = & place. ty . clone ( ) ; // Clone it out so we can mutate `matrix` later.
1542+ let pcx = & PlaceCtxt { cx : mcx. tycx , ty } ;
15201543 let mut ret = WitnessMatrix :: empty ( ) ;
15211544 for ctor in split_ctors {
15221545 // Dig into rows that match `ctor`.
0 commit comments