@@ -695,20 +695,9 @@ impl<'tcx> Constructor<'tcx> {
695
695
/// Two constructors that are not in the matrix will either both be caught (by a wildcard), or
696
696
/// both not be caught. Therefore we can keep the missing constructors grouped together.
697
697
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)
712
701
}
713
702
714
703
/// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
@@ -811,7 +800,7 @@ impl<'tcx> Constructor<'tcx> {
811
800
/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
812
801
/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
813
802
/// `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 ] > {
815
804
debug ! ( "all_constructors({:?})" , pcx. ty) ;
816
805
let cx = pcx. cx ;
817
806
let make_range = |start, end| {
@@ -821,19 +810,19 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
821
810
)
822
811
} ;
823
812
match pcx. ty . kind ( ) {
824
- ty:: Bool => vec ! [ make_range( 0 , 1 ) ] ,
813
+ ty:: Bool => smallvec ! [ make_range( 0 , 1 ) ] ,
825
814
ty:: Array ( sub_ty, len) if len. try_eval_usize ( cx. tcx , cx. param_env ) . is_some ( ) => {
826
815
let len = len. eval_usize ( cx. tcx , cx. param_env ) ;
827
816
if len != 0 && cx. is_uninhabited ( sub_ty) {
828
- vec ! [ ]
817
+ smallvec ! [ ]
829
818
} else {
830
- vec ! [ Slice ( Slice :: new( Some ( len) , VarLen ( 0 , 0 ) ) ) ]
819
+ smallvec ! [ Slice ( Slice :: new( Some ( len) , VarLen ( 0 , 0 ) ) ) ]
831
820
}
832
821
}
833
822
// Treat arrays of a constant but unknown length like slices.
834
823
ty:: Array ( sub_ty, _) | ty:: Slice ( sub_ty) => {
835
824
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) ) ]
837
826
}
838
827
ty:: Adt ( def, substs) if def. is_enum ( ) => {
839
828
// 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
863
852
&& !pcx. is_top_level ;
864
853
865
854
if is_secretly_empty || is_declared_nonexhaustive {
866
- vec ! [ NonExhaustive ]
855
+ smallvec ! [ NonExhaustive ]
867
856
} else if cx. tcx . features ( ) . exhaustive_patterns {
868
857
// If `exhaustive_patterns` is enabled, we exclude variants known to be
869
858
// uninhabited.
@@ -880,7 +869,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
880
869
}
881
870
}
882
871
ty:: Char => {
883
- vec ! [
872
+ smallvec ! [
884
873
// The valid Unicode Scalar Value ranges.
885
874
make_range( '\u{0000}' as u128 , '\u{D7FF}' as u128 ) ,
886
875
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
893
882
// `usize`/`isize` are not allowed to be matched exhaustively unless the
894
883
// `precise_pointer_size_matching` feature is enabled. So we treat those types like
895
884
// `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
896
- vec ! [ NonExhaustive ]
885
+ smallvec ! [ NonExhaustive ]
897
886
}
898
887
& ty:: Int ( ity) => {
899
888
let bits = Integer :: from_attr ( & cx. tcx , SignedInt ( ity) ) . size ( ) . bits ( ) as u128 ;
900
889
let min = 1u128 << ( bits - 1 ) ;
901
890
let max = min - 1 ;
902
- vec ! [ make_range( min, max) ]
891
+ smallvec ! [ make_range( min, max) ]
903
892
}
904
893
& ty:: Uint ( uty) => {
905
894
let size = Integer :: from_attr ( & cx. tcx , UnsignedInt ( uty) ) . size ( ) ;
906
895
let max = size. truncate ( u128:: MAX ) ;
907
- vec ! [ make_range( 0 , max) ]
896
+ smallvec ! [ make_range( 0 , max) ]
908
897
}
909
898
// If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot
910
899
// expose its emptiness. The exception is if the pattern is at the top level, because we
911
900
// want empty matches to be considered exhaustive.
912
901
ty:: Never if !cx. tcx . features ( ) . exhaustive_patterns && !pcx. is_top_level => {
913
- vec ! [ NonExhaustive ]
902
+ smallvec ! [ NonExhaustive ]
914
903
}
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 ] ,
918
907
// This type is one for which we cannot list constructors, like `str` or `f64`.
919
- _ => vec ! [ NonExhaustive ] ,
908
+ _ => smallvec ! [ NonExhaustive ] ,
920
909
}
921
910
}
922
911
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.
924
919
#[ 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
926
924
all_ctors : SmallVec < [ Constructor < ' tcx > ; 1 ] > ,
927
- used_ctors : Vec < Constructor < ' tcx > > ,
928
925
}
929
926
930
- impl < ' tcx > MissingConstructors < ' tcx > {
927
+ impl < ' tcx > SplitWildcard < ' tcx > {
931
928
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 =
933
938
pcx. matrix . head_ctors ( pcx. cx ) . cloned ( ) . filter ( |c| !c. is_wildcard ( ) ) . collect ( ) ;
934
939
// 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 ( ) ;
939
941
}
940
942
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 ( )
943
946
}
944
947
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 > (
947
950
& ' a self ,
948
951
pcx : PatCtxt < ' a , ' p , ' tcx > ,
949
952
) -> 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
951
968
}
952
969
953
970
/// List the patterns corresponding to the missing constructors. In some cases, instead of
954
971
/// 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 > (
956
973
& self ,
957
974
pcx : PatCtxt < ' _ , ' p , ' tcx > ,
958
975
) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
@@ -984,7 +1001,7 @@ impl<'tcx> MissingConstructors<'tcx> {
984
1001
// The exception is: if we are at the top-level, for example in an empty match, we
985
1002
// sometimes prefer reporting the list of constructors instead of just `_`.
986
1003
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 {
988
1005
// All constructors are unused. Report only a wildcard
989
1006
// rather than each individual constructor.
990
1007
smallvec ! [ Pat :: wildcard_from_ty( pcx. ty) ]
@@ -993,7 +1010,7 @@ impl<'tcx> MissingConstructors<'tcx> {
993
1010
// constructor, that matches everything that can be built with
994
1011
// it. For example, if `ctor` is a `Constructor::Variant` for
995
1012
// `Option::Some`, we get the pattern `Some(_)`.
996
- self . iter ( pcx)
1013
+ self . iter_missing ( pcx)
997
1014
. map ( |missing_ctor| Fields :: wildcards ( pcx, & missing_ctor) . apply ( pcx, missing_ctor) )
998
1015
. collect ( )
999
1016
}
0 commit comments