@@ -15,7 +15,7 @@ use rustc::mir::{
1515 ConstraintCategory , Local , Location , Mir ,
1616} ;
1717use rustc:: ty:: { self , RegionVid , Ty , TyCtxt , TypeFoldable } ;
18- use rustc:: util:: common;
18+ use rustc:: util:: common:: { self , ErrorReported } ;
1919use rustc_data_structures:: bit_set:: BitSet ;
2020use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
2121use rustc_data_structures:: graph:: scc:: Sccs ;
@@ -763,20 +763,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
763763
764764 debug ! ( "try_promote_type_test: ur={:?}" , ur) ;
765765
766- let non_local_ub = self . universal_region_relations . non_local_upper_bound ( ur) ;
766+ let non_local_ub = self . universal_region_relations . non_local_upper_bounds ( & ur) ;
767767 debug ! ( "try_promote_type_test: non_local_ub={:?}" , non_local_ub) ;
768768
769- assert ! ( self . universal_regions. is_universal_region( non_local_ub) ) ;
770- assert ! ( !self . universal_regions. is_local_free_region( non_local_ub) ) ;
771-
772- let requirement = ClosureOutlivesRequirement {
773- subject,
774- outlived_free_region : non_local_ub,
775- blame_span : locations. span ( mir) ,
776- category : ConstraintCategory :: Boring ,
777- } ;
778- debug ! ( "try_promote_type_test: pushing {:#?}" , requirement) ;
779- propagated_outlives_requirements. push ( requirement) ;
769+ // This is slightly too conservative. To show T: '1, given `'2: '1`
770+ // and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
771+ // avoid potential non-determinism we approximate this by requiring
772+ // T: '1 and T: '2.
773+ for & upper_bound in non_local_ub {
774+ debug_assert ! ( self . universal_regions. is_universal_region( upper_bound) ) ;
775+ debug_assert ! ( !self . universal_regions. is_local_free_region( upper_bound) ) ;
776+
777+ let requirement = ClosureOutlivesRequirement {
778+ subject,
779+ outlived_free_region : upper_bound,
780+ blame_span : locations. span ( mir) ,
781+ category : ConstraintCategory :: Boring ,
782+ } ;
783+ debug ! ( "try_promote_type_test: pushing {:#?}" , requirement) ;
784+ propagated_outlives_requirements. push ( requirement) ;
785+ }
780786 }
781787 true
782788 }
@@ -1157,63 +1163,109 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11571163 . is_none( )
11581164 ) ;
11591165
1166+ // Only check all of the relations for the main representative of each
1167+ // SCC, otherwise just check that we outlive said representative. This
1168+ // reduces the number of redundant relations propagated out of
1169+ // closures.
1170+ // Note that the representative will be a universal region if there is
1171+ // one in this SCC, so we will always check the representative here.
1172+ let representative = self . scc_representatives [ longer_fr_scc] ;
1173+ if representative != longer_fr {
1174+ self . check_universal_region_relation (
1175+ longer_fr,
1176+ representative,
1177+ infcx,
1178+ mir,
1179+ mir_def_id,
1180+ propagated_outlives_requirements,
1181+ errors_buffer,
1182+ ) ;
1183+ return ;
1184+ }
1185+
11601186 // Find every region `o` such that `fr: o`
11611187 // (because `fr` includes `end(o)`).
11621188 for shorter_fr in self . scc_values . universal_regions_outlived_by ( longer_fr_scc) {
1163- // If it is known that `fr: o`, carry on.
1164- if self . universal_region_relations
1165- . outlives ( longer_fr, shorter_fr)
1166- {
1167- continue ;
1189+ if let Some ( ErrorReported ) = self . check_universal_region_relation (
1190+ longer_fr,
1191+ shorter_fr,
1192+ infcx,
1193+ mir,
1194+ mir_def_id,
1195+ propagated_outlives_requirements,
1196+ errors_buffer,
1197+ ) {
1198+ // continuing to iterate just reports more errors than necessary
1199+ return ;
11681200 }
1201+ }
1202+ }
11691203
1170- debug ! (
1171- "check_universal_region: fr={:?} does not outlive shorter_fr={:?}" ,
1172- longer_fr, shorter_fr,
1173- ) ;
1204+ fn check_universal_region_relation (
1205+ & self ,
1206+ longer_fr : RegionVid ,
1207+ shorter_fr : RegionVid ,
1208+ infcx : & InferCtxt < ' _ , ' gcx , ' tcx > ,
1209+ mir : & Mir < ' tcx > ,
1210+ mir_def_id : DefId ,
1211+ propagated_outlives_requirements : & mut Option < & mut Vec < ClosureOutlivesRequirement < ' gcx > > > ,
1212+ errors_buffer : & mut Vec < Diagnostic > ,
1213+ ) -> Option < ErrorReported > {
1214+ // If it is known that `fr: o`, carry on.
1215+ if self . universal_region_relations
1216+ . outlives ( longer_fr, shorter_fr)
1217+ {
1218+ return None ;
1219+ }
11741220
1175- let blame_span_category = self . find_outlives_blame_span ( mir, longer_fr, shorter_fr) ;
1176-
1177- if let Some ( propagated_outlives_requirements) = propagated_outlives_requirements {
1178- // Shrink `fr` until we find a non-local region (if we do).
1179- // We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
1180- if let Some ( fr_minus) = self . universal_region_relations
1181- . non_local_lower_bound ( longer_fr)
1182- {
1183- debug ! ( "check_universal_region: fr_minus={:?}" , fr_minus) ;
1184-
1185- // Grow `shorter_fr` until we find a non-local
1186- // region. (We always will.) We'll call that
1187- // `shorter_fr+` -- it's ever so slightly larger than
1188- // `fr`.
1189- let shorter_fr_plus = self . universal_region_relations
1190- . non_local_upper_bound ( shorter_fr) ;
1191- debug ! (
1192- "check_universal_region: shorter_fr_plus={:?}" ,
1193- shorter_fr_plus
1194- ) ;
1221+ debug ! (
1222+ "check_universal_region_relation: fr={:?} does not outlive shorter_fr={:?}" ,
1223+ longer_fr, shorter_fr,
1224+ ) ;
11951225
1226+ if let Some ( propagated_outlives_requirements) = propagated_outlives_requirements {
1227+ // Shrink `longer_fr` until we find a non-local region (if we do).
1228+ // We'll call it `fr-` -- it's ever so slightly smaller than
1229+ // `longer_fr`.
1230+
1231+ if let Some ( fr_minus) = self
1232+ . universal_region_relations
1233+ . non_local_lower_bound ( longer_fr)
1234+ {
1235+ debug ! ( "check_universal_region: fr_minus={:?}" , fr_minus) ;
1236+
1237+ let blame_span_category = self . find_outlives_blame_span ( mir, longer_fr, shorter_fr) ;
1238+
1239+ // Grow `shorter_fr` until we find some non-local regions. (We
1240+ // always will.) We'll call them `shorter_fr+` -- they're ever
1241+ // so slightly larger than `shorter_fr`.
1242+ let shorter_fr_plus = self . universal_region_relations
1243+ . non_local_upper_bounds ( & shorter_fr) ;
1244+ debug ! (
1245+ "check_universal_region: shorter_fr_plus={:?}" ,
1246+ shorter_fr_plus
1247+ ) ;
1248+ for & & fr in & shorter_fr_plus {
11961249 // Push the constraint `fr-: shorter_fr+`
11971250 propagated_outlives_requirements. push ( ClosureOutlivesRequirement {
11981251 subject : ClosureOutlivesSubject :: Region ( fr_minus) ,
1199- outlived_free_region : shorter_fr_plus ,
1252+ outlived_free_region : fr ,
12001253 blame_span : blame_span_category. 1 ,
12011254 category : blame_span_category. 0 ,
12021255 } ) ;
1203- continue ;
12041256 }
1257+ return None ;
12051258 }
1206-
1207- // If we are not in a context where we can propagate
1208- // errors, or we could not shrink `fr` to something
1209- // smaller, then just report an error.
1210- //
1211- // Note: in this case, we use the unapproximated regions
1212- // to report the error. This gives better error messages
1213- // in some cases.
1214- self . report_error ( mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer) ;
1215- return ; // continuing to iterate just reports more errors than necessary
12161259 }
1260+
1261+ // If we are not in a context where we can't propagate errors, or we
1262+ // could not shrink `fr` to something smaller, then just report an
1263+ // error.
1264+ //
1265+ // Note: in this case, we use the unapproximated regions to report the
1266+ // error. This gives better error messages in some cases.
1267+ self . report_error ( mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer) ;
1268+ Some ( ErrorReported )
12171269 }
12181270
12191271 fn check_bound_universal_region < ' gcx > (
0 commit comments