I've been debugging some gnarly lifetime issues and have narrowed down the problem to a type being invariant when it should be covariant. I've reproduced it with a minimal example program:
// type TestType<'a> = Covariant<&'a u8>; // works if uncommented
type TestType<'a> = Invariant<&'a u8>; // doesn't work
// This struct is covariant.
struct Covariant<T>(T);
// This struct is invariant, but I don't know why.
struct Invariant<T: Item>(T::Type);
trait Item { type Type; }
impl<T> Item for T { type Type = T; }
// Verify that `TestType` is covariant.
fn test_covariance<'short, 'long: 'short>() {
let long: TestType<'long> = make();
let short: TestType<'short> = long;
}
fn make<T>() -> T { unimplemented!() }
Error:
error: lifetime may not live long enough
--> src/main.rs:16:15
|
15 | fn test_covariance<'short, 'long: 'short>() {
| ------ ----- lifetime `'long` defined here
| |
| lifetime `'short` defined here
16 | let long: TestType<'long> = make();
| ^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
|
= help: consider adding the following bound: `'short: 'long`
= note: requirement occurs because of the type `Invariant<&u8>`, which makes the generic argument `&u8` invariant
= note: the struct `Invariant<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
(Explorer)
For reasons I don't understand, Invariant
is invariant over T
, even though it is intended to be covariant. Why does passing T
through the Item
trait make it invariant?