1

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 the T 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()
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
dontarius
  • 99
  • 1
  • 8
  • It looks like your question might be answered by the answers of [“borrowed value does not live long enough” with a generic function that returns impl trait](https://stackoverflow.com/q/57976042/155423) which is really a duplicate of [Impl trait with generic associated type in return position causes lifetime error](https://stackoverflow.com/q/56636442/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Feb 18 '20 at 20:15
  • 1
    Yes, those questions and especially the link to the [github issue](https://github.com/rust-lang/rust/issues/42940) fully answer my questions. Thanks a lot! – dontarius Feb 18 '20 at 21:01

0 Answers0