Skip to content

Commit 168c14a

Browse files
committed
Avoid propagating redundant outlives constraints from closures
1 parent e544947 commit 168c14a

File tree

1 file changed

+93
-49
lines changed
  • src/librustc_mir/borrow_check/nll/region_infer

1 file changed

+93
-49
lines changed

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+93-49
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::mir::{
1515
ConstraintCategory, Local, Location, Mir,
1616
};
1717
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
18-
use rustc::util::common;
18+
use rustc::util::common::{self, ErrorReported};
1919
use rustc_data_structures::bit_set::BitSet;
2020
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2121
use rustc_data_structures::graph::scc::Sccs;
@@ -1157,63 +1157,107 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11571157
.is_none()
11581158
);
11591159

1160+
// Only check all of the relations for the main representative of each
1161+
// SCC, otherwise just check that we outlive said representative. This
1162+
// reduces the number of redundant relations propagated out of
1163+
// closures.
1164+
// Note that the representative will be a universal region if there is
1165+
// one in this SCC, so we will always check the representative here.
1166+
let representative = self.scc_representatives[longer_fr_scc];
1167+
if representative != longer_fr {
1168+
self.check_universal_region_relation(
1169+
longer_fr,
1170+
representative,
1171+
infcx,
1172+
mir,
1173+
mir_def_id,
1174+
propagated_outlives_requirements,
1175+
errors_buffer,
1176+
);
1177+
return;
1178+
}
1179+
11601180
// Find every region `o` such that `fr: o`
11611181
// (because `fr` includes `end(o)`).
11621182
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;
1183+
if let Some(ErrorReported) = self.check_universal_region_relation(
1184+
longer_fr,
1185+
shorter_fr,
1186+
infcx,
1187+
mir,
1188+
mir_def_id,
1189+
propagated_outlives_requirements,
1190+
errors_buffer,
1191+
) {
1192+
// continuing to iterate just reports more errors than necessary
1193+
return;
11681194
}
1195+
}
1196+
}
11691197

1170-
debug!(
1171-
"check_universal_region: fr={:?} does not outlive shorter_fr={:?}",
1172-
longer_fr, shorter_fr,
1173-
);
1198+
fn check_universal_region_relation(
1199+
&self,
1200+
longer_fr: RegionVid,
1201+
shorter_fr: RegionVid,
1202+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
1203+
mir: &Mir<'tcx>,
1204+
mir_def_id: DefId,
1205+
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
1206+
errors_buffer: &mut Vec<Diagnostic>,
1207+
) -> Option<ErrorReported> {
1208+
// If it is known that `fr: o`, carry on.
1209+
if self.universal_region_relations
1210+
.outlives(longer_fr, shorter_fr)
1211+
{
1212+
return None;
1213+
}
11741214

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-
);
1215+
debug!(
1216+
"check_universal_region_relation: fr={:?} does not outlive shorter_fr={:?}",
1217+
longer_fr, shorter_fr,
1218+
);
11951219

1196-
// Push the constraint `fr-: shorter_fr+`
1197-
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
1198-
subject: ClosureOutlivesSubject::Region(fr_minus),
1199-
outlived_free_region: shorter_fr_plus,
1200-
blame_span: blame_span_category.1,
1201-
category: blame_span_category.0,
1202-
});
1203-
continue;
1204-
}
1205-
}
12061220

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
1221+
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
1222+
// Shrink `fr` until we find a non-local region (if we do).
1223+
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
1224+
if let Some(fr_minus) = self.universal_region_relations
1225+
.non_local_lower_bound(longer_fr)
1226+
{
1227+
debug!("check_universal_region: fr_minus={:?}", fr_minus);
1228+
1229+
let blame_span_category = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
1230+
1231+
// Grow `shorter_fr` until we find a non-local
1232+
// region. (We always will.) We'll call that
1233+
// `shorter_fr+` -- it's ever so slightly larger than
1234+
// `fr`.
1235+
let shorter_fr_plus = self.universal_region_relations
1236+
.non_local_upper_bound(shorter_fr);
1237+
debug!(
1238+
"check_universal_region: shorter_fr_plus={:?}",
1239+
shorter_fr_plus
1240+
);
1241+
1242+
// Push the constraint `fr-: shorter_fr+`
1243+
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
1244+
subject: ClosureOutlivesSubject::Region(fr_minus),
1245+
outlived_free_region: shorter_fr_plus,
1246+
blame_span: blame_span_category.1,
1247+
category: blame_span_category.0,
1248+
});
1249+
return None;
1250+
}
12161251
}
1252+
1253+
// If we are not in a context where we can't propagate errors, or we
1254+
// could not shrink `fr` to something smaller, then just report an
1255+
// error.
1256+
//
1257+
// Note: in this case, we use the unapproximated regions to report the
1258+
// error. This gives better error messages in some cases.
1259+
self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
1260+
Some(ErrorReported)
12171261
}
12181262

12191263
fn check_bound_universal_region<'gcx>(

0 commit comments

Comments
 (0)