Skip to content

Commit 8c66aab

Browse files
Do not propogate unnecessary closure constraints + tests.
1 parent 23c7bad commit 8c66aab

File tree

3 files changed

+70
-10
lines changed

3 files changed

+70
-10
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,17 +1290,44 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12901290
// Grow `shorter_fr` until we find some non-local regions. (We
12911291
// always will.) We'll call them `shorter_fr+` -- they're ever
12921292
// so slightly larger than `shorter_fr`.
1293-
let shorter_fr_plus =
1293+
let shorter_fr_plusses =
12941294
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
1295-
debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
1296-
for fr in shorter_fr_plus {
1297-
// Push the constraint `fr-: shorter_fr+`
1298-
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
1299-
subject: ClosureOutlivesSubject::Region(fr_minus),
1300-
outlived_free_region: fr,
1301-
blame_span: blame_constraint.cause.span,
1302-
category: blame_constraint.category,
1303-
});
1295+
debug!(
1296+
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
1297+
shorter_fr_plusses
1298+
);
1299+
1300+
let fr_static = self.universal_regions().fr_static;
1301+
let single_region = shorter_fr_plusses.len() == 1;
1302+
1303+
for shorter_fr_plus in shorter_fr_plusses {
1304+
// Don't propagate every `fr-: shorter_fr+`.
1305+
// A smaller "optimal subset" exists, since full propagation is overly conservative
1306+
// and can reject valid code. Consider this small example (`'b: 'a` == `a -> b`)
1307+
// were we try to propagate region error `'d: 'a`:
1308+
// a --> b --> d
1309+
// \
1310+
// \-> c
1311+
// Here `shorter_fr_plusses` == `['b, 'c]`.
1312+
// Propagating `'d: 'b` is correct and should happen; `'d: 'c` is redundant and can reject valid code.
1313+
// We can come closer to this "optimal subset" by checking if the `shorter_fr+` should be outlived by `fr-`.
1314+
// NOTE: [] is *not* a valid subset, so we check for that as well.
1315+
if single_region
1316+
|| shorter_fr_plus == fr_static // `fr-: 'static` should be propagated
1317+
|| self.eval_outlives(fr_minus, shorter_fr_plus)
1318+
{
1319+
debug!(
1320+
"try_propagate_universal_region_error: propagating {:?}: {:?}",
1321+
fr_minus, shorter_fr_plus,
1322+
);
1323+
// If that's the case, push the constraint `fr-: shorter_fr+`
1324+
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
1325+
subject: ClosureOutlivesSubject::Region(fr_minus),
1326+
outlived_free_region: shorter_fr_plus,
1327+
blame_span: blame_constraint.cause.span,
1328+
category: blame_constraint.category,
1329+
});
1330+
}
13041331
}
13051332
return RegionRelationCheckResult::Propagated;
13061333
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ check-pass
2+
3+
4+
struct MyTy<'x, 'a, 'b>(std::cell::Cell<(&'x &'a u8, &'x &'b u8)>);
5+
fn wf<T>(_: T) {}
6+
fn test<'a, 'b>() {
7+
|_: &'a u8, x: MyTy<'_, 'a, 'b>| wf(x);
8+
|x: MyTy<'_, 'a, 'b>, _: &'a u8| wf(x);
9+
}
10+
11+
fn main(){}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ check-pass
2+
3+
#[derive(Clone, Copy)]
4+
struct Inv<'a>(*mut &'a ());
5+
impl<'a> Inv<'a> {
6+
fn outlived_by<'b: 'a>(self, _: Inv<'b>) {}
7+
}
8+
struct OutlivedBy<'a, 'b: 'a>(Inv<'a>, Inv<'b>);
9+
10+
fn closure_arg<'b, 'c, 'd>(
11+
_: impl for<'a> FnOnce(Inv<'a>, OutlivedBy<'a, 'b>, OutlivedBy<'a, 'c>, Inv<'d>),
12+
) {
13+
}
14+
fn foo<'b, 'c, 'd: 'b>() {
15+
closure_arg::<'b, 'c, 'd>(|a, b, c, d| {
16+
a.outlived_by(b.1);
17+
a.outlived_by(c.1);
18+
b.1.outlived_by(d);
19+
});
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)