I was reading Ownership and impl Trait and I don't fully understand why Rust won't compile this. The (slightly modified) code in question is:
fn make_debug<'a, T: 'a>(_: T) -> impl std::fmt::Debug + 'static {
42u8
}
fn test() -> impl std::fmt::Debug + 'static {
let value = "value".to_string();
make_debug(&value)
}
pub fn main() {
println!("{:?}", test());
}
The compilation fails:
error[E0515]: cannot return value referencing local variable `value`
--> src/main.rs:7:5
|
7 | make_debug(&value)
| ^^^^^^^^^^^------^
| | |
| | `value` is borrowed here
| returns a value referencing data owned by the current function
Why does Rust not rely on the 'static
lifetime in the return value of the function signature of make_debug()
? I would have assumed the correctness of the function signature, including lifetimes, has been established by the compiler and can thus be relied upon.
Is there an example where the return lifetime indicates 'static
but Rust somehow relies on non-'static
data? The blog post suggests this may be the case by stating
The
impl Debug
may rely upon data inside theT
parameter
How?
Concretely, the following does not allow non-'static
data to be returned as 'static
. So why does Rust not rely on the explicitly (and correctly) stated lifetimes associated with make_debug()
at the call site in test()
?
Note: the code below fails to compile if the lifetime on the return values of make_debug()
is changed to 'static
. As written, the code compiles.
struct A<'a> {
s: &'a String,
}
trait Foo {
type Item;
fn get<'a>(&'a self) -> Self::Item;
}
impl<'a> Foo for A<'a> {
type Item = &'a String;
fn get<'b>(&'b self) -> Self::Item {
self.s
}
}
impl<T, U> Foo for &T
where
T: Foo<Item = U>,
{
type Item = U;
fn get<'a>(&'a self) -> Self::Item {
(*self).get()
}
}
// return lifetime 'a works, but does not work with 'static
fn make_debug<'a, T>(x: T) -> impl std::fmt::Debug + 'a
where
T: Foo,
<T as Foo>::Item: std::fmt::Debug + 'a,
{
x.get()
}