Skip to content

Commit c7b6e1d

Browse files
committed
lub: don't bail out due to empty binders
1 parent 64a7aa7 commit c7b6e1d

File tree

5 files changed

+193
-12
lines changed

5 files changed

+193
-12
lines changed

compiler/rustc_infer/src/infer/glb.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,20 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
9595
T: Relate<'tcx>,
9696
{
9797
debug!("binders(a={:?}, b={:?})", a, b);
98-
99-
// When higher-ranked types are involved, computing the LUB is
100-
// very challenging, switch to invariance. This is obviously
101-
// overly conservative but works ok in practice.
102-
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
103-
Ok(a)
98+
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
99+
// When higher-ranked types are involved, computing the GLB is
100+
// very challenging, switch to invariance. This is obviously
101+
// overly conservative but works ok in practice.
102+
self.relate_with_variance(
103+
ty::Variance::Invariant,
104+
ty::VarianceDiagInfo::default(),
105+
a,
106+
b,
107+
)?;
108+
Ok(a)
109+
} else {
110+
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
111+
}
104112
}
105113
}
106114

compiler/rustc_infer/src/infer/lub.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,20 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
9595
T: Relate<'tcx>,
9696
{
9797
debug!("binders(a={:?}, b={:?})", a, b);
98-
99-
// When higher-ranked types are involved, computing the LUB is
100-
// very challenging, switch to invariance. This is obviously
101-
// overly conservative but works ok in practice.
102-
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
103-
Ok(a)
98+
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
99+
// When higher-ranked types are involved, computing the LUB is
100+
// very challenging, switch to invariance. This is obviously
101+
// overly conservative but works ok in practice.
102+
self.relate_with_variance(
103+
ty::Variance::Invariant,
104+
ty::VarianceDiagInfo::default(),
105+
a,
106+
b,
107+
)?;
108+
Ok(a)
109+
} else {
110+
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
111+
}
104112
}
105113
}
106114

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
fn lt<'a: 'a>() -> &'a () {
2+
&()
3+
}
4+
5+
fn lt_in_fn<'a: 'a>() -> fn(&'a ()) {
6+
|_| ()
7+
}
8+
9+
struct Contra<'a>(fn(&'a ()));
10+
fn lt_in_contra<'a: 'a>() -> Contra<'a> {
11+
Contra(|_| ())
12+
}
13+
14+
fn covariance<'a, 'b, 'upper, 'lower>(v: bool)
15+
where
16+
'upper: 'a,
17+
'upper: 'b,
18+
'a: 'lower,
19+
'b: 'lower,
20+
21+
{
22+
let _: &'upper () = match v {
23+
//~^ ERROR lifetime may not live long enough
24+
//~| ERROR lifetime may not live long enough
25+
true => lt::<'a>(),
26+
false => lt::<'b>(),
27+
};
28+
}
29+
30+
fn contra_fn<'a, 'b, 'upper, 'lower>(v: bool)
31+
where
32+
'upper: 'a,
33+
'upper: 'b,
34+
'a: 'lower,
35+
'b: 'lower,
36+
37+
{
38+
39+
let _: fn(&'lower ()) = match v {
40+
//~^ ERROR lifetime may not live long enough
41+
true => lt_in_fn::<'a>(),
42+
false => lt_in_fn::<'b>(),
43+
};
44+
}
45+
46+
fn contra_struct<'a, 'b, 'upper, 'lower>(v: bool)
47+
where
48+
'upper: 'a,
49+
'upper: 'b,
50+
'a: 'lower,
51+
'b: 'lower,
52+
53+
{
54+
let _: Contra<'lower> = match v {
55+
//~^ ERROR lifetime may not live long enough
56+
true => lt_in_contra::<'a>(),
57+
false => lt_in_contra::<'b>(),
58+
};
59+
}
60+
61+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/empty-binders-err.rs:22:12
3+
|
4+
LL | fn covariance<'a, 'b, 'upper, 'lower>(v: bool)
5+
| -- ------ lifetime `'upper` defined here
6+
| |
7+
| lifetime `'a` defined here
8+
...
9+
LL | let _: &'upper () = match v {
10+
| ^^^^^^^^^^ type annotation requires that `'a` must outlive `'upper`
11+
|
12+
= help: consider adding the following bound: `'a: 'upper`
13+
14+
error: lifetime may not live long enough
15+
--> $DIR/empty-binders-err.rs:22:12
16+
|
17+
LL | fn covariance<'a, 'b, 'upper, 'lower>(v: bool)
18+
| -- ------ lifetime `'upper` defined here
19+
| |
20+
| lifetime `'b` defined here
21+
...
22+
LL | let _: &'upper () = match v {
23+
| ^^^^^^^^^^ type annotation requires that `'b` must outlive `'upper`
24+
|
25+
= help: consider adding the following bound: `'b: 'upper`
26+
27+
help: the following changes may resolve your lifetime errors
28+
|
29+
= help: add bound `'a: 'upper`
30+
= help: add bound `'b: 'upper`
31+
32+
error: lifetime may not live long enough
33+
--> $DIR/empty-binders-err.rs:39:12
34+
|
35+
LL | fn contra_fn<'a, 'b, 'upper, 'lower>(v: bool)
36+
| -- ------ lifetime `'lower` defined here
37+
| |
38+
| lifetime `'a` defined here
39+
...
40+
LL | let _: fn(&'lower ()) = match v {
41+
| ^^^^^^^^^^^^^^ type annotation requires that `'lower` must outlive `'a`
42+
|
43+
= help: consider adding the following bound: `'lower: 'a`
44+
45+
error: lifetime may not live long enough
46+
--> $DIR/empty-binders-err.rs:54:12
47+
|
48+
LL | fn contra_struct<'a, 'b, 'upper, 'lower>(v: bool)
49+
| -- ------ lifetime `'lower` defined here
50+
| |
51+
| lifetime `'a` defined here
52+
...
53+
LL | let _: Contra<'lower> = match v {
54+
| ^^^^^^^^^^^^^^ type annotation requires that `'lower` must outlive `'a`
55+
|
56+
= help: consider adding the following bound: `'lower: 'a`
57+
58+
error: aborting due to 4 previous errors
59+

src/test/ui/lub-glb/empty-binders.rs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// check-pass
2+
//
3+
// Check that computing the lub works even for empty binders.
4+
fn lt<'a: 'a>() -> &'a () {
5+
&()
6+
}
7+
8+
fn lt_in_fn<'a: 'a>() -> fn(&'a ()) {
9+
|_| ()
10+
}
11+
12+
struct Contra<'a>(fn(&'a ()));
13+
fn lt_in_contra<'a: 'a>() -> Contra<'a> {
14+
Contra(|_| ())
15+
}
16+
17+
fn ok<'a, 'b, 'upper, 'lower>(v: bool)
18+
where
19+
'upper: 'a,
20+
'upper: 'b,
21+
'a: 'lower,
22+
'b: 'lower,
23+
24+
{
25+
let _: &'lower () = match v {
26+
true => lt::<'a>(),
27+
false => lt::<'b>(),
28+
};
29+
30+
// This errored in the past because LUB and GLB always
31+
// bailed out when encountering binders, even if they were
32+
// empty.
33+
let _: fn(&'upper ()) = match v {
34+
true => lt_in_fn::<'a>(),
35+
false => lt_in_fn::<'b>(),
36+
};
37+
38+
// This was already accepted, as relate didn't encounter any binders.
39+
let _: Contra<'upper> = match v {
40+
true => lt_in_contra::<'a>(),
41+
false => lt_in_contra::<'b>(),
42+
};
43+
}
44+
45+
fn main() {}

0 commit comments

Comments
 (0)