@@ -931,12 +931,37 @@ impl<'tcx> IntRange<'tcx> {
931
931
}
932
932
}
933
933
934
- // Return a set of constructors equivalent to `all_ctors \ used_ctors`.
934
+ // A request for missing constructor data in terms of either:
935
+ // - whether or not there any missing constructors; or
936
+ // - the actual set of missing constructors.
937
+ #[ derive( PartialEq ) ]
938
+ enum MissingCtorsInfo {
939
+ Emptiness ,
940
+ Ctors ,
941
+ }
942
+
943
+ // Used by `compute_missing_ctors`.
944
+ #[ derive( Debug , PartialEq ) ]
945
+ enum MissingCtors < ' tcx > {
946
+ Empty ,
947
+ NonEmpty ,
948
+
949
+ // Note that the Vec can be empty.
950
+ Ctors ( Vec < Constructor < ' tcx > > ) ,
951
+ }
952
+
953
+ // When `info` is `MissingCtorsInfo::Ctors`, compute a set of constructors
954
+ // equivalent to `all_ctors \ used_ctors`. When `info` is
955
+ // `MissingCtorsInfo::Emptiness`, just determines if that set is empty or not.
956
+ // (The split logic gives a performance win, because we always need to know if
957
+ // the set is empty, but we rarely need the full set, and it can be expensive
958
+ // to compute the full set.)
935
959
fn compute_missing_ctors < ' a , ' tcx : ' a > (
960
+ info : MissingCtorsInfo ,
936
961
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
937
962
all_ctors : & Vec < Constructor < ' tcx > > ,
938
963
used_ctors : & Vec < Constructor < ' tcx > > ,
939
- ) -> Vec < Constructor < ' tcx > > {
964
+ ) -> MissingCtors < ' tcx > {
940
965
let mut missing_ctors = vec ! [ ] ;
941
966
942
967
for req_ctor in all_ctors {
@@ -965,10 +990,22 @@ fn compute_missing_ctors<'a, 'tcx: 'a>(
965
990
// We add `refined_ctors` instead of `req_ctor`, because then we can
966
991
// provide more detailed error information about precisely which
967
992
// ranges have been omitted.
968
- missing_ctors. extend ( refined_ctors) ;
993
+ if info == MissingCtorsInfo :: Emptiness {
994
+ if !refined_ctors. is_empty ( ) {
995
+ // The set is non-empty; return early.
996
+ return MissingCtors :: NonEmpty ;
997
+ }
998
+ } else {
999
+ missing_ctors. extend ( refined_ctors) ;
1000
+ }
969
1001
}
970
1002
971
- missing_ctors
1003
+ if info == MissingCtorsInfo :: Emptiness {
1004
+ // If we reached here, the set is empty.
1005
+ MissingCtors :: Empty
1006
+ } else {
1007
+ MissingCtors :: Ctors ( missing_ctors)
1008
+ }
972
1009
}
973
1010
974
1011
/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
@@ -1081,20 +1118,23 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
1081
1118
// feature flag is not present, so this is only
1082
1119
// needed for that case.
1083
1120
1084
- // Find those constructors that are not matched by any non-wildcard patterns in the
1085
- // current column.
1086
- let missing_ctors = compute_missing_ctors ( cx. tcx , & all_ctors, & used_ctors) ;
1121
+ // Missing constructors are those that are not matched by any
1122
+ // non-wildcard patterns in the current column. We always determine if
1123
+ // the set is empty, but we only fully construct them on-demand,
1124
+ // because they're rarely used and can be big.
1125
+ let cheap_missing_ctors =
1126
+ compute_missing_ctors ( MissingCtorsInfo :: Emptiness , cx. tcx , & all_ctors, & used_ctors) ;
1087
1127
1088
1128
let is_privately_empty = all_ctors. is_empty ( ) && !cx. is_uninhabited ( pcx. ty ) ;
1089
1129
let is_declared_nonexhaustive = cx. is_non_exhaustive_enum ( pcx. ty ) && !cx. is_local ( pcx. ty ) ;
1090
- debug ! ( "missing_ctors ={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}" ,
1091
- missing_ctors , is_privately_empty, is_declared_nonexhaustive) ;
1130
+ debug ! ( "cheap_missing_ctors ={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}" ,
1131
+ cheap_missing_ctors , is_privately_empty, is_declared_nonexhaustive) ;
1092
1132
1093
1133
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
1094
1134
// `_` constructor for the type, so we can never match over all constructors.
1095
1135
let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
1096
1136
1097
- if missing_ctors . is_empty ( ) && !is_non_exhaustive {
1137
+ if cheap_missing_ctors == MissingCtors :: Empty && !is_non_exhaustive {
1098
1138
split_grouped_constructors ( cx. tcx , all_ctors, matrix, pcx. ty ) . into_iter ( ) . map ( |c| {
1099
1139
is_useful_specialized ( cx, matrix, v, c, pcx. ty , witness)
1100
1140
} ) . find ( |result| result. is_useful ( ) ) . unwrap_or ( NotUseful )
@@ -1165,15 +1205,22 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
1165
1205
witness
1166
1206
} ) . collect ( )
1167
1207
} else {
1168
- pats. into_iter ( ) . flat_map ( |witness| {
1169
- missing_ctors. iter ( ) . map ( move |ctor| {
1170
- // Extends the witness with a "wild" version of this
1171
- // constructor, that matches everything that can be built with
1172
- // it. For example, if `ctor` is a `Constructor::Variant` for
1173
- // `Option::Some`, this pushes the witness for `Some(_)`.
1174
- witness. clone ( ) . push_wild_constructor ( cx, ctor, pcx. ty )
1175
- } )
1176
- } ) . collect ( )
1208
+ let expensive_missing_ctors =
1209
+ compute_missing_ctors ( MissingCtorsInfo :: Ctors , cx. tcx , & all_ctors,
1210
+ & used_ctors) ;
1211
+ if let MissingCtors :: Ctors ( missing_ctors) = expensive_missing_ctors {
1212
+ pats. into_iter ( ) . flat_map ( |witness| {
1213
+ missing_ctors. iter ( ) . map ( move |ctor| {
1214
+ // Extends the witness with a "wild" version of this
1215
+ // constructor, that matches everything that can be built with
1216
+ // it. For example, if `ctor` is a `Constructor::Variant` for
1217
+ // `Option::Some`, this pushes the witness for `Some(_)`.
1218
+ witness. clone ( ) . push_wild_constructor ( cx, ctor, pcx. ty )
1219
+ } )
1220
+ } ) . collect ( )
1221
+ } else {
1222
+ bug ! ( "cheap missing ctors" )
1223
+ }
1177
1224
} ;
1178
1225
UsefulWithWitness ( new_witnesses)
1179
1226
}
0 commit comments