Outlives relations are syntactic, so if Foo<'a>: 'b
, then 'a: 'b
, and vice-versa. The motivations are at the top of the RFC.
Variance is a property of super/subtyping, i.e. which lifetimes can coerce to one another. Bounds checks don't consider variance, they consider a specific type, ignoring its possible coercions. The bound is a property of the type, not some supertype or anything else it can coerce to.
I think this will be easier to explain with an example. Let's consider the function pointer type fn(&'a str)
.
fn witness_outlives<'a, T: 'a>() {}
fn example<'long: 'short, 'short>() {
// These are fine
witness_outlives::<'long, fn(&'long str)>();
witness_outlives::<'short, fn(&'short str)>();
witness_outlives::<'short, fn(&'long str)>();
// These are errors
witness_outlives::<'static, fn(&'long str)>();
witness_outlives::<'static, fn(&'short str)>();
witness_outlives::<'long, fn(&'short str)>();
}
Even though a fn(&'long str)
cannot coerce to a fn(&'short str)
, fn(&'long str): 'short
. And even though a fn(&'short str)
can coerce to a fn(&'long str)
or fn(&'static str)
due to covariance, it does not satisfy a : 'long
or : 'static
bound.
Generally this isn't a problem when lifetimes are inferred, as contravariance will kick in:
fn witness_outlives_value<'a, T: 'a>(_: T) {}
fn example_value<'long: 'short, 'short>(
contravar: fn(&'short str),
covar: &'short str,
invar: fn(&'short str) -> &'short str
) {
// OK
witness_outlives_value::<'long, _>(contravar);
}