Skip to content

Commit b7f5bca

Browse files
propagate region error for every non-local lower bound
1 parent 477a820 commit b7f5bca

File tree

2 files changed

+39
-36
lines changed

2 files changed

+39
-36
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,13 +1275,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12751275
shorter_fr: RegionVid,
12761276
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
12771277
) -> RegionRelationCheckResult {
1278-
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements
1279-
// Shrink `longer_fr` until we find a non-local region (if we do).
1280-
// We'll call it `fr-` -- it's ever so slightly smaller than
1278+
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
1279+
// Shrink `longer_fr` until we find some non-local regions.
1280+
// We'll call them `longer_fr-` -- they are ever so slightly smaller than
12811281
// `longer_fr`.
1282-
&& let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
1283-
{
1284-
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
1282+
let longer_fr_minus = self.universal_region_relations.non_local_lower_bounds(longer_fr);
1283+
1284+
debug!("try_propagate_universal_region_error: fr_minus={:?}", longer_fr_minus);
1285+
1286+
// If we don't find a any non-local regions, we should error out as there is nothing
1287+
// to propagate.
1288+
if longer_fr_minus.is_empty() {
1289+
return RegionRelationCheckResult::Error;
1290+
}
12851291

12861292
let blame_constraint = self
12871293
.best_blame_constraint(longer_fr, NllRegionVariableOrigin::FreeRegion, shorter_fr)
@@ -1292,8 +1298,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12921298
// so slightly larger than `shorter_fr`.
12931299
let shorter_fr_plus =
12941300
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
1301+
debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
12951302

1296-
// If any of the `shorter_fr+` regions are already outlived by `fr-`, we propagate only those.
1303+
// We then create constraints `longer_fr-: shorter_fr+` that may or may not be propagated (see below).
1304+
let mut constraints = vec![];
1305+
for fr_minus in longer_fr_minus {
1306+
for shorter_fr_plus in &shorter_fr_plus {
1307+
constraints.push((fr_minus, *shorter_fr_plus));
1308+
}
1309+
}
1310+
1311+
// If any of the `shorter_fr+` regions are already outlived by `longer_fr-`, we propagate only those.
12971312
// Otherwise, we might incorrectly reject valid code.
12981313
//
12991314
// Consider this example (`'b: 'a` == `a -> b`), where we try to propagate `'d: 'a`:
@@ -1304,20 +1319,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
13041319
// Propagating `'d: 'b` is correct and should occur; `'d: 'c` is redundant because of `'d: 'b`
13051320
// and could reject valid code.
13061321
//
1307-
// So we filter `shorter_fr+` to regions already outlived by `fr-`, but if the filter yields an empty set,
1322+
// So we filter the constraints to regions already outlived by `longer_fr-`, but if the filter yields an empty set,
13081323
// we fall back to the original one.
1309-
let subset: Vec<_> = shorter_fr_plus
1324+
let subset: Vec<_> = constraints
13101325
.iter()
1311-
.filter(|&&fr_plus| self.eval_outlives(fr_minus, fr_plus))
1326+
.filter(|&&(fr_minus, shorter_fr_plus)| {
1327+
self.eval_outlives(fr_minus, shorter_fr_plus)
1328+
})
13121329
.copied()
13131330
.collect();
1314-
let shorter_fr_plus = if subset.is_empty() { shorter_fr_plus } else { subset };
1315-
debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
1316-
for fr in shorter_fr_plus {
1317-
// Push the constraint `fr-: shorter_fr+`
1331+
let propagated_constraints = if subset.is_empty() { constraints } else { subset };
1332+
debug!(
1333+
"try_propagate_universal_region_error: constraints={:?}",
1334+
propagated_constraints
1335+
);
1336+
1337+
for (fr_minus, fr_plus) in propagated_constraints {
1338+
// Push the constraint `long_fr-: shorter_fr+`
13181339
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
13191340
subject: ClosureOutlivesSubject::Region(fr_minus),
1320-
outlived_free_region: fr,
1341+
outlived_free_region: fr_plus,
13211342
blame_span: blame_constraint.cause.span,
13221343
category: blame_constraint.category,
13231344
});

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,28 +94,10 @@ impl UniversalRegionRelations<'_> {
9494
/// words, returns the largest (*) known region `fr1` that (a) is
9595
/// outlived by `fr` and (b) is not local.
9696
///
97-
/// (*) If there are multiple competing choices, we pick the "postdominating"
98-
/// one. See `TransitiveRelation::postdom_upper_bound` for details.
99-
pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
97+
/// (*) If there are multiple competing choices, we return all of them.
98+
pub(crate) fn non_local_lower_bounds(&self, fr: RegionVid) -> Vec<RegionVid> {
10099
debug!("non_local_lower_bound(fr={:?})", fr);
101-
let lower_bounds = self.non_local_bounds(&self.outlives, fr);
102-
103-
// In case we find more than one, reduce to one for
104-
// convenience. This is to prevent us from generating more
105-
// complex constraints, but it will cause spurious errors.
106-
let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
107-
108-
debug!("non_local_bound: post_dom={:?}", post_dom);
109-
110-
post_dom.and_then(|post_dom| {
111-
// If the mutual immediate postdom is not local, then
112-
// there is no non-local result we can return.
113-
if !self.universal_regions.is_local_free_region(post_dom) {
114-
Some(post_dom)
115-
} else {
116-
None
117-
}
118-
})
100+
self.non_local_bounds(&self.outlives, fr)
119101
}
120102

121103
/// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`.

0 commit comments

Comments
 (0)