The following code produces a compiler error:
pub trait ReturnedTrait {}
impl<T> ReturnedTrait for T {}
pub fn create_trait<'a, T>(_t: T) -> impl ReturnedTrait + 'a {}
pub fn outer<'a>(val: String) -> impl ReturnedTrait + 'a {
create_trait(&val)
}
error[[E0597]](https://doc.rust-lang.org/stable/error_codes/E0597.html): `val` does not live long enough
--> src/lib.rs:8:18
|
7 | pub fn outer<'a>(val: String) -> impl ReturnedTrait + 'a {
| -- lifetime `'a` defined here
8 | create_trait(&val)
| -------------^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `val` is borrowed for `'a`
9 | }
| - `val` dropped here while still borrowed
playground
The reason, as I see it, is that according to RFC 1951, a returned impl captures generic arguments. However, in this case, I do have a lifetime bound 'a which is present on the returned impl but not on the generic T. However, the function still acts as if T has a lifetime bound of 'a.
Okay, so if the returned impl captures T, then I would expect to be able to use T in the return value. But the compiler will not let me:
pub trait ReturnedTrait {}
impl<T> ReturnedTrait for T {}
pub fn create_trait<'a, T>(t: T) -> impl ReturnedTrait + 'a {
t
}
pub fn outer<'a>(val: String) -> impl ReturnedTrait + 'a {
create_trait(val)
}
error[[E0309]](https://doc.rust-lang.org/stable/error_codes/E0309.html): the parameter type `T` may not live long enough
--> src/lib.rs:6:5
|
6 | t
| ^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
5 | pub fn create_trait<'a, T: 'a>(t: T) -> impl ReturnedTrait + 'a {
| ++++
playground
The compiler will not let me use T in the returned impl, but still, it requires that T is borrowed for 'a.
I would expect one of two things to happen:
- The returned
impl captures T, which would allow me to use T in the return value.
- The returned
impl does not capture T, in which case it would be possible for T to not have lifetime 'a.
Instead what happens is that the inner function does not allow the impl to capture T, but the outer function acts as if the impl has captured T.
An additional note
I noticed that by wrapping the returned value in a Box<dyn _>, the code compiles:
pub trait ReturnedTrait {}
impl<T> ReturnedTrait for T {}
pub fn create_trait<'a, T>(_t: T) -> impl ReturnedTrait + 'a {}
pub fn outer<'a>(val: String) -> impl ReturnedTrait + 'a {
let res = create_trait(&val);
let res: Box<dyn ReturnedTrait + 'a> = Box::new(res);
res
}
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 0.76s
playground
This further leads me to believe that this lifetime error is unnecessary. Without any modification to the inner function, the compiler now understands that the returned impl in fact does not capture T.
Solution
Because of the 'a bound on the returned impl, the inner function does not allow the returned impl to capture T. The function outer should therefore be able to know that the parameter T does not have to live for 'a. Therefore, it should be possible to remove the lifetime error in the first code example, at this playground.
The following code produces a compiler error:
playground
The reason, as I see it, is that according to RFC 1951, a returned
implcaptures generic arguments. However, in this case, I do have a lifetime bound'awhich is present on the returnedimplbut not on the genericT. However, the function still acts as ifThas a lifetime bound of'a.Okay, so if the returned
implcapturesT, then I would expect to be able to useTin the return value. But the compiler will not let me:playground
The compiler will not let me use
Tin the returnedimpl, but still, it requires thatTis borrowed for'a.I would expect one of two things to happen:
implcapturesT, which would allow me to useTin the return value.impldoes not captureT, in which case it would be possible forTto not have lifetime'a.Instead what happens is that the inner function does not allow the
implto captureT, but the outer function acts as if theimplhas capturedT.An additional note
I noticed that by wrapping the returned value in a
Box<dyn _>, the code compiles:playground
This further leads me to believe that this lifetime error is unnecessary. Without any modification to the inner function, the compiler now understands that the returned
implin fact does not captureT.Solution
Because of the
'abound on the returnedimpl, the inner function does not allow the returnedimplto captureT. The functionoutershould therefore be able to know that the parameterTdoes not have to live for'a. Therefore, it should be possible to remove the lifetime error in the first code example, at this playground.