Open
Description
Code
trait Slice {
type S<'a>: Copy
where
Self: 'a;
}
struct Foo<'a, L: Slice + 'a> {
foo: L::S<'a>,
}
impl<'a, L: Slice + 'a> Foo<'a, L> {
fn foo(&self) -> L::S<'_> {
self.foo
}
}
Current output
error: lifetime may not live long enough
--> src/lib.rs:13:9
|
11 | impl<'a, L: Slice + 'a> Foo<'a, L> {
| -- lifetime `'a` defined here
12 | fn foo(&self) -> L::S<'_> {
| - let's call the lifetime of this reference `'1`
13 | self.foo
| ^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
Desired output
error: GAT parameters are invariant
--> src/lib.rs:13:9
|
11 | impl<'a, L: Slice + 'a> Foo<'a, L> {
| -- lifetime `'a` defined here
12 | fn foo(&self) -> L::S<'_> {
| - let's call the lifetime of this reference `'1`
13 | self.foo
| ^^^^^^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
error: could not compile `playground` due to previous error
Rationale and extra context
The current error seems to assume a typical covariant-situation error where one is trying to return a long-lived value from behind a short-lived reference, and says that:
lifetime may not live long enough
associated function was supposed to return data with lifetime
'a
but it is returning data with lifetime'1
But actually the opposite is true: the function was supposed to return data with lifetime '1
but is returning data with lifetime 'a
because the GAT in question is invariant in 'a
. You could say that '1
doesn't live long enough, but in my opinion it would be better to say that 'a
is invariant (and thus doesn't "live short enough").
Witnessed in this URLO topic by nnotaka.
Other cases
// This one gives better diagnostics w.r.t. variance but
// still gets the "supposed to return" lifetimes backwards
struct Foo2<'a> {
foo: *mut &'a str,
}
impl<'a> Foo2<'a> {
fn foo(&self) -> *mut &str {
self.foo
}
}
// This contravariant case suggests a bound which is
// effectively invariant, but still gets the lifetimes
// backwards
struct Foo3<'a> {
foo: &'a dyn Fn(&'a str),
}
impl<'a> Foo3<'a> {
fn foo<'b>(&'b self) -> &'b dyn Fn(&'b str) {
self.foo
}
}
Anything else?
- Main playground
*mut
playgrounderror: lifetime may not live long enough --> src/lib.rs:7:9 | 5 | impl<'a> Foo2<'a> { | -- lifetime `'a` defined here 6 | fn foo(&self) -> *mut &str { | - let's call the lifetime of this reference `'1` 7 | self.foo | ^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` | = note: requirement occurs because of a mutable pointer to `&str` = note: mutable pointers are invariant over their type parameter = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
dyn Fn
playgrounderror: lifetime may not live long enough --> src/lib.rs:7:9 | 5 | impl<'a> Foo3<'a> { | -- lifetime `'a` defined here 6 | fn foo<'b>(&'b self) -> &'b dyn Fn(&'b str) { | -- lifetime `'b` defined here 7 | self.foo | ^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a`
- Covariant case where the "return data" lifetimes are correct
error: lifetime may not live long enough --> src/lib.rs:7:9 | 5 | impl<'a> Foo4<'a> { | -- lifetime `'a` defined here 6 | fn foo(&self) -> &'a str { | - let's call the lifetime of this reference `'1` 7 | self.foo | ^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
@rustbot label +A-lifetimes +A-variance
Metadata
Metadata
Assignees
Labels
Area: Non-lexical lifetimes (NLL)Area: The borrow checkerArea: Messages for errors, warnings, and lintsArea: Lifetimes / regionsArea: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)Diagnostics: A diagnostic that is giving misleading or incorrect information.Relevant to the compiler team, which will review and decide on the PR/issue.