@@ -15,7 +15,7 @@ use rustc::mir::{
15
15
ConstraintCategory , Local , Location , Mir ,
16
16
} ;
17
17
use rustc:: ty:: { self , RegionVid , Ty , TyCtxt , TypeFoldable } ;
18
- use rustc:: util:: common;
18
+ use rustc:: util:: common:: { self , ErrorReported } ;
19
19
use rustc_data_structures:: bit_set:: BitSet ;
20
20
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
21
21
use rustc_data_structures:: graph:: scc:: Sccs ;
@@ -763,20 +763,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
763
763
764
764
debug ! ( "try_promote_type_test: ur={:?}" , ur) ;
765
765
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) ;
767
767
debug ! ( "try_promote_type_test: non_local_ub={:?}" , non_local_ub) ;
768
768
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
+ }
780
786
}
781
787
true
782
788
}
@@ -1157,63 +1163,109 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1157
1163
. is_none( )
1158
1164
) ;
1159
1165
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
+
1160
1186
// Find every region `o` such that `fr: o`
1161
1187
// (because `fr` includes `end(o)`).
1162
1188
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 ;
1168
1200
}
1201
+ }
1202
+ }
1169
1203
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
+ }
1174
1220
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
+ ) ;
1195
1225
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 {
1196
1249
// Push the constraint `fr-: shorter_fr+`
1197
1250
propagated_outlives_requirements. push ( ClosureOutlivesRequirement {
1198
1251
subject : ClosureOutlivesSubject :: Region ( fr_minus) ,
1199
- outlived_free_region : shorter_fr_plus ,
1252
+ outlived_free_region : fr ,
1200
1253
blame_span : blame_span_category. 1 ,
1201
1254
category : blame_span_category. 0 ,
1202
1255
} ) ;
1203
- continue ;
1204
1256
}
1257
+ return None ;
1205
1258
}
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
1216
1259
}
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 )
1217
1269
}
1218
1270
1219
1271
fn check_bound_universal_region < ' gcx > (
0 commit comments