@@ -931,12 +931,37 @@ impl<'tcx> IntRange<'tcx> {
931931 }
932932}
933933
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.)
935959fn compute_missing_ctors < ' a , ' tcx : ' a > (
960+ info : MissingCtorsInfo ,
936961 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
937962 all_ctors : & Vec < Constructor < ' tcx > > ,
938963 used_ctors : & Vec < Constructor < ' tcx > > ,
939- ) -> Vec < Constructor < ' tcx > > {
964+ ) -> MissingCtors < ' tcx > {
940965 let mut missing_ctors = vec ! [ ] ;
941966
942967 for req_ctor in all_ctors {
@@ -965,10 +990,22 @@ fn compute_missing_ctors<'a, 'tcx: 'a>(
965990 // We add `refined_ctors` instead of `req_ctor`, because then we can
966991 // provide more detailed error information about precisely which
967992 // 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+ }
9691001 }
9701002
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+ }
9721009}
9731010
9741011/// 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>,
10811118 // feature flag is not present, so this is only
10821119 // needed for that case.
10831120
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) ;
10871127
10881128 let is_privately_empty = all_ctors. is_empty ( ) && !cx. is_uninhabited ( pcx. ty ) ;
10891129 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) ;
10921132
10931133 // For privately empty and non-exhaustive enums, we work as if there were an "extra"
10941134 // `_` constructor for the type, so we can never match over all constructors.
10951135 let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
10961136
1097- if missing_ctors . is_empty ( ) && !is_non_exhaustive {
1137+ if cheap_missing_ctors == MissingCtors :: Empty && !is_non_exhaustive {
10981138 split_grouped_constructors ( cx. tcx , all_ctors, matrix, pcx. ty ) . into_iter ( ) . map ( |c| {
10991139 is_useful_specialized ( cx, matrix, v, c. clone ( ) , pcx. ty , witness)
11001140 } ) . 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>,
11651205 witness
11661206 } ) . collect ( )
11671207 } 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+ }
11771224 } ;
11781225 UsefulWithWitness ( new_witnesses)
11791226 }
0 commit comments