Lifetime error when using covariant attribute on struct that might be covariant
Closed this issue · 4 comments
I've recently been working on adding rental to allsorts in order to be able to hold font table data alongside its parsed representation in the same struct. I have it working with #[rental]
but with #[rental(covariant)]
a lifetime error is raised for one of the structs. It's possible that the compiler is identifying an actual issue but my colleagues are a bit confused as to why it's being rejected.
I've extracted the code and reduced it to a minimal example as much as possible here: https://github.com/wezm/rental-covariant-lifetime-param
It appears to be something about ReadArray
that is an issue, as the other example struct
works as expected. Any insight would be most appreciated.
The error is:
Compiling rental-covariant-lifetime-param v0.1.0 (/home/wmoore/Work/rental-covariant-lifetime-param) error[E0308]: mismatched types --> src/lib.rs:14:1 | 14 | / rental! { 15 | | mod tables { 16 | | use super::*; 17 | | ... | 23 | | } 24 | | } | |_^ lifetime mismatch | = note: expected struct `std::marker::PhantomData>` found struct `std::marker::PhantomData>` note: the lifetime `'__s` as defined on the method body at 6:37... --> src/lib.rs:14:1 | 14 | / rental! { 15 | | mod tables { 16 | | use super::*; 17 | | ... | 23 | | } 24 | | } | |_^ = note: ...does not necessarily outlive the static lifetime = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)error[E0495]: cannot infer an appropriate lifetime for lifetime parameter
'data
due to conflicting requirements
--> src/lib.rs:14:1
|
14 | / rental! {
15 | | mod tables {
16 | | use super::;
17 | |
... |
23 | | }
24 | | }
| |_^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:37...
--> src/lib.rs:14:1
|
14 | / rental! {
15 | | mod tables {
16 | | use super::;
17 | |
... |
23 | | }
24 | | }
| |^
note: ...so that the types are compatible
--> src/lib.rs:14:1
|
14 | / rental! {
15 | | mod tables {
16 | | use super::*;
17 | |
... |
23 | | }
24 | | }
| |^
= note: expectedrental::__rental_prelude::Rental2<'_, '_>
foundrental::__rental_prelude::Rental2<'_, '_>
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> src/lib.rs:14:1
|
14 | / rental! {
15 | | mod tables {
16 | | use super::*;
17 | |
... |
23 | | }
24 | | }
| |_^
= note: expected&TestTable<'_>
found&TestTable<'static>
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)error: aborting due to 2 previous errors
Taking a quick look, it's probably the ReadCtxt
param in ReadBinaryDep
's read_dep
method that's causing it. The lifetime 'a
appears in a type behind a mutable reference, which according to rust's variance rules, forces the lifetime 'a
to be invariant, which will break rental's covariant feature. In the working example, the lifetime 'a
appears only behind a shared reference, allowing it to remain covariant.
Thanks for taking a look and quick reply. Your insights are helpful. My colleagues and I were a little surprised that a method on a trait might be able influence the variance of the struct, even when the mutable reference supplied to the method is not self
. Nonetheless is it your understanding that this can be the case?
The variance of a struct or trait is determined solely by any lifetime parameters it takes. If 'a
is used in an invariant context, it must be invariant, making the trait invariant over that lifetime, and any structs that implement that trait invariant over that lifetime, and so on. self
has no special meaning or bearing with respect to lifetime variance.
Great, thanks for the explanation, it helps.