I don't understand what the error message means here and why would there be a problem in this code.
Code:
trait A {
fn f(&mut self) -> &mut ();
}
trait B<T>
where
T: A,
{
fn g(&mut self) -> &mut T;
fn h(&mut self) -> &mut (){
let t = self.g();
t.f()
}
}
fn main() {}
Error message :
error[E0311]: the parameter type `T` may not live long enough
--> src/zips.rs:148:17
|
148 | let t = self.g();
| ^^^^^^^^
|
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
--> src/zips.rs:147:10
|
147 | fn h(&mut self) -> &mut (){
| ^^^^^^^^^
note: ...so that the type `T` will meet its required lifetime bounds
--> src/zips.rs:148:17
|
148 | let t = self.g();
| ^^^^^^^^
help: consider adding an explicit lifetime bound...
|
144 | T: A + 'a,
| ++++
A function that takes a &'m mut T has an implicit T: 'm bound which the caller of the function must satisfy (or an error results). And in your trait,
// This method has implicit `Self: 'g` and `T: 'g` bounds
fn g<'g>(&'g mut self) -> &'g mut T;
// This method has an implicit `Self: 'h` bound but no bound for `T`
fn h<'h>(&'h mut self) -> &'h mut () {
// So it can't "prove" that `T: 'h`, because it's possible to
// call `h` with some lifetime `'h` that `T` can't meet
// (even if convoluted to construct)
let t = self.g();
t.f()
}
Well that’s a fun error message. Took me a minute; now, after me figuring out the solution, @quinedot already posted an explanation, too. Anyways, I wanted to acknowledge that there’s also at least one clear issue with the error message itself, namely the suggestion
help: consider adding an explicit lifetime bound...
|
7 | T: A + 'a,
| ++++
which suggests adding a lifetime bound
for a lifetime that doesn’t have a name, without clearly indicating that 'a is not the correct name yet (and perhaps suggesting how to introduce a name)
at a place (top level of the trait) where the lifetime in question (elided lifetime argument of the method) is not even in scope
A clearer msg occurs when annotating the type: Rust Playground
fn h<'h>(&'h mut self) -> &'h mut ()
{
let t: &'h mut T = self.g();
t.f()
}
error[E0309]: the parameter type `T` may not live long enough
--> src/main.rs:18:16
|
18 | let t: &'h mut T = self.g();
| ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
8 | T: A + 'h,
| ++++
error[E0309]: the parameter type `T` may not live long enough
--> src/main.rs:18:28
|
18 | let t: &'h mut T = self.g();
| ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
8 | T: A + 'h,
| ++++
error[E0309]: the parameter type `T` may not live long enough
--> src/main.rs:19:9
|
19 | t.f()
| ^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
8 | T: A + 'h,
| ++++
Since T can potentially be a reference type, it has a lifetime 't. For the function g, we implicitly require that T as a reference type must outlive the elided output lifetime ('g). And since in the function h we call g, the lifetime requirement is not guaranteed to be met. By adding this as assumption, we allow the body then to call g and require explicitly the proof from the caller of h.
From a beginner's perspective, the thing that bugged me was forgetting T can potentially be a reference type AND this results in the 't: 'g. I had always been thinking about the lifetime only of the reference explicitly shown in my code with &.
To nitpick, types other than references can have lifetimes,[1] so "reference type" or "be a reference" is somewhat inaccurate. The phrase "T [...] has a lifetime" (my emphasis) also feels off to me, though I can't exactly pintpoint why.[2] I'd say, every type T can meet or fail to meet a T: 'lifetime bound, or in this case perhaps "T may not be valid for the reference lifetime". But those are just quibbles.