lub: don't bail out due to empty binders
This commit is contained in:
parent
64a7aa7016
commit
c7b6e1de66
5 changed files with 193 additions and 12 deletions
|
@ -95,12 +95,20 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||||
T: Relate<'tcx>,
|
T: Relate<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("binders(a={:?}, b={:?})", a, b);
|
debug!("binders(a={:?}, b={:?})", a, b);
|
||||||
|
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
|
||||||
// When higher-ranked types are involved, computing the LUB is
|
// When higher-ranked types are involved, computing the GLB is
|
||||||
// very challenging, switch to invariance. This is obviously
|
// very challenging, switch to invariance. This is obviously
|
||||||
// overly conservative but works ok in practice.
|
// overly conservative but works ok in practice.
|
||||||
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
|
self.relate_with_variance(
|
||||||
|
ty::Variance::Invariant,
|
||||||
|
ty::VarianceDiagInfo::default(),
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
)?;
|
||||||
Ok(a)
|
Ok(a)
|
||||||
|
} else {
|
||||||
|
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,12 +95,20 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||||
T: Relate<'tcx>,
|
T: Relate<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("binders(a={:?}, b={:?})", a, b);
|
debug!("binders(a={:?}, b={:?})", a, b);
|
||||||
|
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
|
||||||
// When higher-ranked types are involved, computing the LUB is
|
// When higher-ranked types are involved, computing the LUB is
|
||||||
// very challenging, switch to invariance. This is obviously
|
// very challenging, switch to invariance. This is obviously
|
||||||
// overly conservative but works ok in practice.
|
// overly conservative but works ok in practice.
|
||||||
self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
|
self.relate_with_variance(
|
||||||
|
ty::Variance::Invariant,
|
||||||
|
ty::VarianceDiagInfo::default(),
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
)?;
|
||||||
Ok(a)
|
Ok(a)
|
||||||
|
} else {
|
||||||
|
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
61
src/test/ui/lub-glb/empty-binders-err.rs
Normal file
61
src/test/ui/lub-glb/empty-binders-err.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
fn lt<'a: 'a>() -> &'a () {
|
||||||
|
&()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lt_in_fn<'a: 'a>() -> fn(&'a ()) {
|
||||||
|
|_| ()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Contra<'a>(fn(&'a ()));
|
||||||
|
fn lt_in_contra<'a: 'a>() -> Contra<'a> {
|
||||||
|
Contra(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn covariance<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
where
|
||||||
|
'upper: 'a,
|
||||||
|
'upper: 'b,
|
||||||
|
'a: 'lower,
|
||||||
|
'b: 'lower,
|
||||||
|
|
||||||
|
{
|
||||||
|
let _: &'upper () = match v {
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
//~| ERROR lifetime may not live long enough
|
||||||
|
true => lt::<'a>(),
|
||||||
|
false => lt::<'b>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contra_fn<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
where
|
||||||
|
'upper: 'a,
|
||||||
|
'upper: 'b,
|
||||||
|
'a: 'lower,
|
||||||
|
'b: 'lower,
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
let _: fn(&'lower ()) = match v {
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
true => lt_in_fn::<'a>(),
|
||||||
|
false => lt_in_fn::<'b>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contra_struct<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
where
|
||||||
|
'upper: 'a,
|
||||||
|
'upper: 'b,
|
||||||
|
'a: 'lower,
|
||||||
|
'b: 'lower,
|
||||||
|
|
||||||
|
{
|
||||||
|
let _: Contra<'lower> = match v {
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
true => lt_in_contra::<'a>(),
|
||||||
|
false => lt_in_contra::<'b>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
59
src/test/ui/lub-glb/empty-binders-err.stderr
Normal file
59
src/test/ui/lub-glb/empty-binders-err.stderr
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/empty-binders-err.rs:22:12
|
||||||
|
|
|
||||||
|
LL | fn covariance<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
| -- ------ lifetime `'upper` defined here
|
||||||
|
| |
|
||||||
|
| lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | let _: &'upper () = match v {
|
||||||
|
| ^^^^^^^^^^ type annotation requires that `'a` must outlive `'upper`
|
||||||
|
|
|
||||||
|
= help: consider adding the following bound: `'a: 'upper`
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/empty-binders-err.rs:22:12
|
||||||
|
|
|
||||||
|
LL | fn covariance<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
| -- ------ lifetime `'upper` defined here
|
||||||
|
| |
|
||||||
|
| lifetime `'b` defined here
|
||||||
|
...
|
||||||
|
LL | let _: &'upper () = match v {
|
||||||
|
| ^^^^^^^^^^ type annotation requires that `'b` must outlive `'upper`
|
||||||
|
|
|
||||||
|
= help: consider adding the following bound: `'b: 'upper`
|
||||||
|
|
||||||
|
help: the following changes may resolve your lifetime errors
|
||||||
|
|
|
||||||
|
= help: add bound `'a: 'upper`
|
||||||
|
= help: add bound `'b: 'upper`
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/empty-binders-err.rs:39:12
|
||||||
|
|
|
||||||
|
LL | fn contra_fn<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
| -- ------ lifetime `'lower` defined here
|
||||||
|
| |
|
||||||
|
| lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | let _: fn(&'lower ()) = match v {
|
||||||
|
| ^^^^^^^^^^^^^^ type annotation requires that `'lower` must outlive `'a`
|
||||||
|
|
|
||||||
|
= help: consider adding the following bound: `'lower: 'a`
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/empty-binders-err.rs:54:12
|
||||||
|
|
|
||||||
|
LL | fn contra_struct<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
| -- ------ lifetime `'lower` defined here
|
||||||
|
| |
|
||||||
|
| lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | let _: Contra<'lower> = match v {
|
||||||
|
| ^^^^^^^^^^^^^^ type annotation requires that `'lower` must outlive `'a`
|
||||||
|
|
|
||||||
|
= help: consider adding the following bound: `'lower: 'a`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
45
src/test/ui/lub-glb/empty-binders.rs
Normal file
45
src/test/ui/lub-glb/empty-binders.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// check-pass
|
||||||
|
//
|
||||||
|
// Check that computing the lub works even for empty binders.
|
||||||
|
fn lt<'a: 'a>() -> &'a () {
|
||||||
|
&()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lt_in_fn<'a: 'a>() -> fn(&'a ()) {
|
||||||
|
|_| ()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Contra<'a>(fn(&'a ()));
|
||||||
|
fn lt_in_contra<'a: 'a>() -> Contra<'a> {
|
||||||
|
Contra(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ok<'a, 'b, 'upper, 'lower>(v: bool)
|
||||||
|
where
|
||||||
|
'upper: 'a,
|
||||||
|
'upper: 'b,
|
||||||
|
'a: 'lower,
|
||||||
|
'b: 'lower,
|
||||||
|
|
||||||
|
{
|
||||||
|
let _: &'lower () = match v {
|
||||||
|
true => lt::<'a>(),
|
||||||
|
false => lt::<'b>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// This errored in the past because LUB and GLB always
|
||||||
|
// bailed out when encountering binders, even if they were
|
||||||
|
// empty.
|
||||||
|
let _: fn(&'upper ()) = match v {
|
||||||
|
true => lt_in_fn::<'a>(),
|
||||||
|
false => lt_in_fn::<'b>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// This was already accepted, as relate didn't encounter any binders.
|
||||||
|
let _: Contra<'upper> = match v {
|
||||||
|
true => lt_in_contra::<'a>(),
|
||||||
|
false => lt_in_contra::<'b>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue