@@ -767,9 +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 ctors_for_ty ( & self ) -> Result < ConstructorSet < Cx > , Cx :: Error > {
771- self . cx . ctors_for_ty ( self . ty )
772- }
773770 fn wild_from_ctor ( & self , ctor : Constructor < Cx > ) -> WitnessPat < Cx > {
774771 WitnessPat :: wild_from_ctor ( self . cx , ctor, self . ty . clone ( ) )
775772 }
@@ -822,7 +819,8 @@ impl fmt::Display for ValidityConstraint {
822819 }
823820}
824821
825- /// Data about a place under investigation.
822+ /// Data about a place under investigation. Its methods contain a lot of the logic used to analyze
823+ /// the constructors in the matrix.
826824struct PlaceInfo < Cx : TypeCx > {
827825 /// The type of the place.
828826 ty : Cx :: Ty ,
@@ -833,6 +831,8 @@ struct PlaceInfo<Cx: TypeCx> {
833831}
834832
835833impl < Cx : TypeCx > PlaceInfo < Cx > {
834+ /// Given a constructor for the current place, we return one `PlaceInfo` for each field of the
835+ /// constructor.
836836 fn specialize < ' a > (
837837 & ' a self ,
838838 cx : & ' a Cx ,
@@ -846,6 +846,79 @@ impl<Cx: TypeCx> PlaceInfo<Cx> {
846846 is_scrutinee : false ,
847847 } )
848848 }
849+
850+ /// This analyzes a column of constructors corresponding to the current place. It returns a pair
851+ /// `(split_ctors, missing_ctors)`.
852+ ///
853+ /// `split_ctors` is a splitted list of constructors that cover the whole type. This will be
854+ /// used to specialize the matrix.
855+ ///
856+ /// `missing_ctors` is a list of the constructors not found in the column, for reporting
857+ /// purposes.
858+ fn split_column_ctors < ' a > (
859+ & self ,
860+ cx : & Cx ,
861+ ctors : impl Iterator < Item = & ' a Constructor < Cx > > + Clone ,
862+ ) -> Result < ( SmallVec < [ Constructor < Cx > ; 1 ] > , Vec < Constructor < Cx > > ) , Cx :: Error >
863+ where
864+ Cx : ' a ,
865+ {
866+ let ctors_for_ty = cx. ctors_for_ty ( & self . ty ) ?;
867+
868+ // We treat match scrutinees of type `!` or `EmptyEnum` differently.
869+ let is_toplevel_exception =
870+ self . is_scrutinee && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
871+ // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
872+ // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
873+ let empty_arms_are_unreachable = self . validity . is_known_valid ( )
874+ && ( is_toplevel_exception
875+ || cx. is_exhaustive_patterns_feature_on ( )
876+ || cx. is_min_exhaustive_patterns_feature_on ( ) ) ;
877+ // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
878+ // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
879+ let can_omit_empty_arms = empty_arms_are_unreachable
880+ || is_toplevel_exception
881+ || cx. is_exhaustive_patterns_feature_on ( ) ;
882+
883+ // Analyze the constructors present in this column.
884+ let mut split_set = ctors_for_ty. split ( ctors) ;
885+ let all_missing = split_set. present . is_empty ( ) ;
886+
887+ // Build the set of constructors we will specialize with. It must cover the whole type, so
888+ // we add `Missing` to represent the missing ones. This is explained under "Constructor
889+ // Splitting" at the top of this file.
890+ let mut split_ctors = split_set. present ;
891+ if !( split_set. missing . is_empty ( )
892+ && ( split_set. missing_empty . is_empty ( ) || empty_arms_are_unreachable) )
893+ {
894+ split_ctors. push ( Constructor :: Missing ) ;
895+ }
896+
897+ // Which empty constructors are considered missing. We ensure that
898+ // `!missing_ctors.is_empty() => split_ctors.contains(Missing)`. The converse usually holds
899+ // except when `!self.validity.is_known_valid()`.
900+ let mut missing_ctors = split_set. missing ;
901+ if !can_omit_empty_arms {
902+ missing_ctors. append ( & mut split_set. missing_empty ) ;
903+ }
904+
905+ // Decide what constructors to report.
906+ let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ;
907+ let always_report_all = self . is_scrutinee && !is_integers;
908+ // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
909+ let report_individual_missing_ctors = always_report_all || !all_missing;
910+ if !missing_ctors. is_empty ( ) && !report_individual_missing_ctors {
911+ // Report `_` as missing.
912+ missing_ctors = vec ! [ Constructor :: Wildcard ] ;
913+ } else if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
914+ // We need to report a `_` anyway, so listing other constructors would be redundant.
915+ // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
916+ // up by diagnostics to add a note about why `_` is required here.
917+ missing_ctors = vec ! [ Constructor :: NonExhaustive ] ;
918+ }
919+
920+ Ok ( ( split_ctors, missing_ctors) )
921+ }
849922}
850923
851924impl < Cx : TypeCx > Clone for PlaceInfo < Cx > {
@@ -1469,63 +1542,13 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14691542 } ;
14701543 } ;
14711544
1472- let ty = & place. ty . clone ( ) ; // Clone it out so we can mutate `matrix` later.
1473- let pcx = & PlaceCtxt { cx : mcx. tycx , ty } ;
1474- debug ! ( "ty: {:?}" , pcx. ty) ;
1475- let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1476-
1477- // We treat match scrutinees of type `!` or `EmptyEnum` differently.
1478- let is_toplevel_exception =
1479- place. is_scrutinee && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1480- // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
1481- // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
1482- let empty_arms_are_unreachable = place. validity . is_known_valid ( )
1483- && ( is_toplevel_exception
1484- || mcx. tycx . is_exhaustive_patterns_feature_on ( )
1485- || mcx. tycx . is_min_exhaustive_patterns_feature_on ( ) ) ;
1486- // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
1487- // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
1488- let can_omit_empty_arms = empty_arms_are_unreachable
1489- || is_toplevel_exception
1490- || mcx. tycx . is_exhaustive_patterns_feature_on ( ) ;
1491-
14921545 // Analyze the constructors present in this column.
1546+ debug ! ( "ty: {:?}" , place. ty) ;
14931547 let ctors = matrix. heads ( ) . map ( |p| p. ctor ( ) ) ;
1494- let mut split_set = ctors_for_ty. split ( ctors) ;
1495- let all_missing = split_set. present . is_empty ( ) ;
1496- // Build the set of constructors we will specialize with. It must cover the whole type.
1497- // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1498- // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1499- let mut split_ctors = split_set. present ;
1500- if !( split_set. missing . is_empty ( )
1501- && ( split_set. missing_empty . is_empty ( ) || empty_arms_are_unreachable) )
1502- {
1503- split_ctors. push ( Constructor :: Missing ) ;
1504- }
1505-
1506- // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
1507- // split_ctors.contains(Missing)`. The converse usually holds except when
1508- // `!place_validity.is_known_valid()`.
1509- let mut missing_ctors = split_set. missing ;
1510- if !can_omit_empty_arms {
1511- missing_ctors. append ( & mut split_set. missing_empty ) ;
1512- }
1513-
1514- // Decide what constructors to report.
1515- let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ;
1516- let always_report_all = place. is_scrutinee && !is_integers;
1517- // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
1518- let report_individual_missing_ctors = always_report_all || !all_missing;
1519- if !missing_ctors. is_empty ( ) && !report_individual_missing_ctors {
1520- // Report `_` as missing.
1521- missing_ctors = vec ! [ Constructor :: Wildcard ] ;
1522- } else if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
1523- // We need to report a `_` anyway, so listing other constructors would be redundant.
1524- // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
1525- // up by diagnostics to add a note about why `_` is required here.
1526- missing_ctors = vec ! [ Constructor :: NonExhaustive ] ;
1527- }
1548+ let ( split_ctors, missing_ctors) = place. split_column_ctors ( mcx. tycx , ctors) ?;
15281549
1550+ let ty = & place. ty . clone ( ) ; // Clone it out so we can mutate `matrix` later.
1551+ let pcx = & PlaceCtxt { cx : mcx. tycx , ty } ;
15291552 let mut ret = WitnessMatrix :: empty ( ) ;
15301553 for ctor in split_ctors {
15311554 // Dig into rows that match `ctor`.
0 commit comments