Description
I tried this code:
trait Original {
fn f() -> impl Fn();
}
// provide a type-erased helper trait for Original
trait Erased {
fn f(&self) -> Box<dyn Fn()>;
}
impl<T: Original> Erased for T {
fn f(&self) -> Box<dyn Fn()> {
Box::new(<T as Original>::f())
}
}
I expected the code to compile successfully, but it failed on Rust 1.75.0 with the following error:
error[E0310]: the associated type `<T as Original>::{opaque#0}` may not live long enough
--> src/lib.rs:11:9
|
11 | Box::new(<T as Original>::f())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the associated type `<T as Original>::{opaque#0}` must be valid for the static lifetime...
| ...so that the type `impl Fn()` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
10 | fn f(&self) -> Box<dyn Fn()> where <T as Original>::{opaque#0}: 'static {
| ++++++++++++++++++++++++++++++++++++++++++
For more information about this error, try `rustc --explain E0310`.
error: could not compile `playground` (lib) due to previous error
I understand that Box<dyn Fn()>
is sugar for Box<dyn Fn() + 'static>
, but in this case the impl Fn()
return is 'static
. It has to be, because Original::f()
takes no arguments, so the value it returns cannot reference any non-static lifetime.
The workaround is to change the return type of Erased::f()
from Box<dyn Fn()>
to Box<dyn Fn() + '_>
, which is allows the code to compile. (Playground.) (Another workaround is to change the definition of Original::f()
to return impl Fn() + 'static
, but in the original code Original
is provided by a different crate and cannot be modified.)
A second, and minor issue is that the compiler's suggestion is not actionable because the opaque type returned from Original::f()
cannot be named.