Skip to content

Commit 29ad85c

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

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12921292
// so slightly larger than `shorter_fr`.
12931293
let shorter_fr_plus =
12941294
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
1295+
1296+
// If any of the `shorter_fr+` regions are already outlived by `fr-`, we propagate only those.
1297+
// Otherwise, we might incorrectly reject valid code.
1298+
//
1299+
// Consider this example (`'b: 'a` == `a -> b`), where we try to propagate `'d: 'a`:
1300+
// a --> b --> d
1301+
// \
1302+
// \-> c
1303+
// Here, `shorter_fr+` of `'a` == `['b, 'c]`.
1304+
// Propagating `'d: 'b` is correct and should occur; `'d: 'c` is redundant because of `'d: 'b`
1305+
// and could reject valid code.
1306+
//
1307+
// So we filter `shorter_fr+` to regions already outlived by `fr-`, but if the filter yields an empty set,
1308+
// we fall back to the original one.
1309+
let subset: Vec<_> = shorter_fr_plus
1310+
.iter()
1311+
.filter(|&&fr_plus| self.eval_outlives(fr_minus, fr_plus))
1312+
.copied()
1313+
.collect();
1314+
let shorter_fr_plus = if subset.is_empty() { shorter_fr_plus } else { subset };
12951315
debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
12961316
for fr in shorter_fr_plus {
12971317
// Push the constraint `fr-: shorter_fr+`
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ check-pass
2+
// This checks that the compiler does not require that 'a: 'b. '_ has 'a and 'b as non-local
3+
// upper bounds, but the compiler should not propagate 'a: 'b OR 'b: 'a when checking
4+
// the closures. If it did, this would fail to compile, eventhough it's a valid program.
5+
// PR #148329 explains this in detail.
6+
7+
struct MyTy<'x, 'a, 'b>(std::cell::Cell<(&'x &'a u8, &'x &'b u8)>);
8+
fn wf<T>(_: T) {}
9+
fn test<'a, 'b>() {
10+
|_: &'a u8, x: MyTy<'_, 'a, 'b>| wf(x);
11+
|x: MyTy<'_, 'a, 'b>, _: &'a u8| wf(x);
12+
}
13+
14+
fn main(){}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ check-pass
2+
// This test checks that the compiler does not propagate 'd: 'c when propagating region errors
3+
// for the closure argument. If it did, this would fail to compile, eventhough it's a valid program.
4+
// It should only propagate 'd: 'b.
5+
// PR #148329 explains this in detail.
6+
7+
#[derive(Clone, Copy)]
8+
struct Inv<'a>(*mut &'a ());
9+
impl<'a> Inv<'a> {
10+
fn outlived_by<'b: 'a>(self, _: Inv<'b>) {}
11+
}
12+
struct OutlivedBy<'a, 'b: 'a>(Inv<'a>, Inv<'b>);
13+
14+
fn closure_arg<'b, 'c, 'd>(
15+
_: impl for<'a> FnOnce(Inv<'a>, OutlivedBy<'a, 'b>, OutlivedBy<'a, 'c>, Inv<'d>),
16+
) {
17+
}
18+
fn foo<'b, 'c, 'd: 'b>() {
19+
closure_arg::<'b, 'c, 'd>(|a, b, c, d| {
20+
a.outlived_by(b.1);
21+
a.outlived_by(c.1);
22+
b.1.outlived_by(d);
23+
});
24+
}
25+
26+
fn main() {}

0 commit comments

Comments
 (0)