@@ -695,20 +695,9 @@ impl<'tcx> Constructor<'tcx> {
695695 /// Two constructors that are not in the matrix will either both be caught (by a wildcard), or
696696 /// both not be caught. Therefore we can keep the missing constructors grouped together.
697697 fn split_wildcard < ' p > ( pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> SmallVec < [ Self ; 1 ] > {
698- // Missing constructors are those that are not matched by any non-wildcard patterns in the
699- // current column. We only fully construct them on-demand, because they're rarely used and
700- // can be big.
701- let missing_ctors = MissingConstructors :: new ( pcx) ;
702- if missing_ctors. is_empty ( pcx) {
703- // All the constructors are present in the matrix, so we just go through them all.
704- // We must also split them first.
705- missing_ctors. all_ctors
706- } else {
707- // Some constructors are missing, thus we can specialize with the wildcard constructor,
708- // which will stand for those constructors that are missing, and behaves like any of
709- // them.
710- smallvec ! [ Wildcard ]
711- }
698+ let mut split_wildcard = SplitWildcard :: new ( pcx) ;
699+ split_wildcard. split ( pcx) ;
700+ split_wildcard. into_ctors ( pcx)
712701 }
713702
714703 /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
@@ -811,7 +800,7 @@ impl<'tcx> Constructor<'tcx> {
811800/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
812801/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
813802/// `cx.is_uninhabited()`).
814- fn all_constructors < ' p , ' tcx > ( pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> Vec < Constructor < ' tcx > > {
803+ fn all_constructors < ' p , ' tcx > ( pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> SmallVec < [ Constructor < ' tcx > ; 1 ] > {
815804 debug ! ( "all_constructors({:?})" , pcx. ty) ;
816805 let cx = pcx. cx ;
817806 let make_range = |start, end| {
@@ -821,19 +810,19 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
821810 )
822811 } ;
823812 match pcx. ty . kind ( ) {
824- ty:: Bool => vec ! [ make_range( 0 , 1 ) ] ,
813+ ty:: Bool => smallvec ! [ make_range( 0 , 1 ) ] ,
825814 ty:: Array ( sub_ty, len) if len. try_eval_usize ( cx. tcx , cx. param_env ) . is_some ( ) => {
826815 let len = len. eval_usize ( cx. tcx , cx. param_env ) ;
827816 if len != 0 && cx. is_uninhabited ( sub_ty) {
828- vec ! [ ]
817+ smallvec ! [ ]
829818 } else {
830- vec ! [ Slice ( Slice :: new( Some ( len) , VarLen ( 0 , 0 ) ) ) ]
819+ smallvec ! [ Slice ( Slice :: new( Some ( len) , VarLen ( 0 , 0 ) ) ) ]
831820 }
832821 }
833822 // Treat arrays of a constant but unknown length like slices.
834823 ty:: Array ( sub_ty, _) | ty:: Slice ( sub_ty) => {
835824 let kind = if cx. is_uninhabited ( sub_ty) { FixedLen ( 0 ) } else { VarLen ( 0 , 0 ) } ;
836- vec ! [ Slice ( Slice :: new( None , kind) ) ]
825+ smallvec ! [ Slice ( Slice :: new( None , kind) ) ]
837826 }
838827 ty:: Adt ( def, substs) if def. is_enum ( ) => {
839828 // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
@@ -863,7 +852,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
863852 && !pcx. is_top_level ;
864853
865854 if is_secretly_empty || is_declared_nonexhaustive {
866- vec ! [ NonExhaustive ]
855+ smallvec ! [ NonExhaustive ]
867856 } else if cx. tcx . features ( ) . exhaustive_patterns {
868857 // If `exhaustive_patterns` is enabled, we exclude variants known to be
869858 // uninhabited.
@@ -880,7 +869,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
880869 }
881870 }
882871 ty:: Char => {
883- vec ! [
872+ smallvec ! [
884873 // The valid Unicode Scalar Value ranges.
885874 make_range( '\u{0000}' as u128 , '\u{D7FF}' as u128 ) ,
886875 make_range( '\u{E000}' as u128 , '\u{10FFFF}' as u128 ) ,
@@ -893,66 +882,94 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
893882 // `usize`/`isize` are not allowed to be matched exhaustively unless the
894883 // `precise_pointer_size_matching` feature is enabled. So we treat those types like
895884 // `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
896- vec ! [ NonExhaustive ]
885+ smallvec ! [ NonExhaustive ]
897886 }
898887 & ty:: Int ( ity) => {
899888 let bits = Integer :: from_attr ( & cx. tcx , SignedInt ( ity) ) . size ( ) . bits ( ) as u128 ;
900889 let min = 1u128 << ( bits - 1 ) ;
901890 let max = min - 1 ;
902- vec ! [ make_range( min, max) ]
891+ smallvec ! [ make_range( min, max) ]
903892 }
904893 & ty:: Uint ( uty) => {
905894 let size = Integer :: from_attr ( & cx. tcx , UnsignedInt ( uty) ) . size ( ) ;
906895 let max = size. truncate ( u128:: MAX ) ;
907- vec ! [ make_range( 0 , max) ]
896+ smallvec ! [ make_range( 0 , max) ]
908897 }
909898 // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
910899 // expose its emptiness. The exception is if the pattern is at the top level, because we
911900 // want empty matches to be considered exhaustive.
912901 ty:: Never if !cx. tcx . features ( ) . exhaustive_patterns && !pcx. is_top_level => {
913- vec ! [ NonExhaustive ]
902+ smallvec ! [ NonExhaustive ]
914903 }
915- ty:: Never => vec ! [ ] ,
916- _ if cx. is_uninhabited ( pcx. ty ) => vec ! [ ] ,
917- ty:: Adt ( ..) | ty:: Tuple ( ..) | ty:: Ref ( ..) => vec ! [ Single ] ,
904+ ty:: Never => smallvec ! [ ] ,
905+ _ if cx. is_uninhabited ( pcx. ty ) => smallvec ! [ ] ,
906+ ty:: Adt ( ..) | ty:: Tuple ( ..) | ty:: Ref ( ..) => smallvec ! [ Single ] ,
918907 // This type is one for which we cannot list constructors, like `str` or `f64`.
919- _ => vec ! [ NonExhaustive ] ,
908+ _ => smallvec ! [ NonExhaustive ] ,
920909 }
921910}
922911
923- // A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
912+ /// A wildcard constructor that we split relative to the constructors in the matrix, as explained
913+ /// at the top of the file.
914+ /// For splitting wildcards, there are two groups of constructors: there are the constructors
915+ /// actually present in the matrix (`matrix_ctors`), and the constructors not present. Two
916+ /// constructors that are not in the matrix will either both be covered (by a wildcard), or both
917+ /// not be covered by any given row. Therefore we can keep the missing constructors grouped
918+ /// together.
924919#[ derive( Debug ) ]
925- pub ( super ) struct MissingConstructors < ' tcx > {
920+ pub ( super ) struct SplitWildcard < ' tcx > {
921+ /// Constructors seen in the matrix.
922+ matrix_ctors : Vec < Constructor < ' tcx > > ,
923+ /// All the constructors for this type
926924 all_ctors : SmallVec < [ Constructor < ' tcx > ; 1 ] > ,
927- used_ctors : Vec < Constructor < ' tcx > > ,
928925}
929926
930- impl < ' tcx > MissingConstructors < ' tcx > {
927+ impl < ' tcx > SplitWildcard < ' tcx > {
931928 pub ( super ) fn new < ' p > ( pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> Self {
932- let used_ctors: Vec < Constructor < ' _ > > =
929+ let matrix_ctors = Vec :: new ( ) ;
930+ let all_ctors = all_constructors ( pcx) ;
931+ SplitWildcard { matrix_ctors, all_ctors }
932+ }
933+
934+ /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't
935+ /// do what you want.
936+ pub ( super ) fn split ( & mut self , pcx : PatCtxt < ' _ , ' _ , ' tcx > ) {
937+ self . matrix_ctors =
933938 pcx. matrix . head_ctors ( pcx. cx ) . cloned ( ) . filter ( |c| !c. is_wildcard ( ) ) . collect ( ) ;
934939 // Since `all_ctors` never contains wildcards, this won't recurse further.
935- let all_ctors =
936- all_constructors ( pcx) . into_iter ( ) . flat_map ( |ctor| ctor. split ( pcx) ) . collect ( ) ;
937-
938- MissingConstructors { all_ctors, used_ctors }
940+ self . all_ctors = self . all_ctors . iter ( ) . flat_map ( |ctor| ctor. split ( pcx) ) . collect ( ) ;
939941 }
940942
941- fn is_empty < ' p > ( & self , pcx : PatCtxt < ' _ , ' p , ' tcx > ) -> bool {
942- self . iter ( pcx) . next ( ) . is_none ( )
943+ /// Whether there are any value constructors for this type that are not present in the matrix.
944+ fn any_missing ( & self , pcx : PatCtxt < ' _ , ' _ , ' tcx > ) -> bool {
945+ self . iter_missing ( pcx) . next ( ) . is_some ( )
943946 }
944947
945- /// Iterate over all_ctors \ used_ctors
946- fn iter < ' a , ' p > (
948+ /// Iterate over the constructors for this type that are not present in the matrix.
949+ fn iter_missing < ' a , ' p > (
947950 & ' a self ,
948951 pcx : PatCtxt < ' a , ' p , ' tcx > ,
949952 ) -> impl Iterator < Item = & ' a Constructor < ' tcx > > + Captures < ' p > {
950- self . all_ctors . iter ( ) . filter ( move |ctor| !ctor. is_covered_by_any ( pcx, & self . used_ctors ) )
953+ self . all_ctors . iter ( ) . filter ( move |ctor| !ctor. is_covered_by_any ( pcx, & self . matrix_ctors ) )
954+ }
955+
956+ /// Return the set of constructors resulting from splitting the wildcard. As explained at the
957+ /// top of the file, if any constructors are missing we can ignore the present ones.
958+ fn into_ctors ( self , pcx : PatCtxt < ' _ , ' _ , ' tcx > ) -> SmallVec < [ Constructor < ' tcx > ; 1 ] > {
959+ if self . any_missing ( pcx) {
960+ // Some constructors are missing, thus we can specialize with the wildcard constructor,
961+ // which will stand for those constructors that are missing, and matches the same rows
962+ // as any of them (namely the wildcard rows).
963+ return smallvec ! [ Wildcard ] ;
964+ }
965+
966+ // All the constructors are present in the matrix, so we just go through them all.
967+ self . all_ctors
951968 }
952969
953970 /// List the patterns corresponding to the missing constructors. In some cases, instead of
954971 /// listing all constructors of a given type, we prefer to simply report a wildcard.
955- pub ( super ) fn report_patterns < ' p > (
972+ pub ( super ) fn report_missing_patterns < ' p > (
956973 & self ,
957974 pcx : PatCtxt < ' _ , ' p , ' tcx > ,
958975 ) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
@@ -984,7 +1001,7 @@ impl<'tcx> MissingConstructors<'tcx> {
9841001 // The exception is: if we are at the top-level, for example in an empty match, we
9851002 // sometimes prefer reporting the list of constructors instead of just `_`.
9861003 let report_when_all_missing = pcx. is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
987- if self . used_ctors . is_empty ( ) && !report_when_all_missing {
1004+ if self . matrix_ctors . is_empty ( ) && !report_when_all_missing {
9881005 // All constructors are unused. Report only a wildcard
9891006 // rather than each individual constructor.
9901007 smallvec ! [ Pat :: wildcard_from_ty( pcx. ty) ]
@@ -993,7 +1010,7 @@ impl<'tcx> MissingConstructors<'tcx> {
9931010 // constructor, that matches everything that can be built with
9941011 // it. For example, if `ctor` is a `Constructor::Variant` for
9951012 // `Option::Some`, we get the pattern `Some(_)`.
996- self . iter ( pcx)
1013+ self . iter_missing ( pcx)
9971014 . map ( |missing_ctor| Fields :: wildcards ( pcx, & missing_ctor) . apply ( pcx, missing_ctor) )
9981015 . collect ( )
9991016 }
0 commit comments