Stream: general

Topic: Unintentional lifetime captures using impl Trait


Jake Goulding (Jul 10 2019 at 18:20, on Zulip):

This code returns an impl Trait that completely owns the value, but the error indicates that the argument's lifetime is being captured as well. Is there a way to avoid the unintended capture?

fn make_debug<T>(_: T) -> impl std::fmt::Debug {
    42u8
}

fn test() -> impl std::fmt::Debug {
    let value = "value".to_string();
    make_debug(&value)
}
error[E0597]: `value` does not live long enough
 --> src/lib.rs:7:16
  |
5 | fn test() -> impl std::fmt::Debug {
  |              -------------------- opaque type requires that `value` is borrowed for `'static`
6 |     let value = "value".to_string();
7 |     make_debug(&value)
  |                ^^^^^^ borrowed value does not live long enough
8 | }
  | - `value` dropped here while still borrowed
RalfJ (Jul 11 2019 at 15:36, on Zulip):

there's at least an issue for this somewhere that maybe contains some hints...

RalfJ (Jul 11 2019 at 15:37, on Zulip):

ah I misremembered, that's not the problem I ran into once

RalfJ (Jul 11 2019 at 15:38, on Zulip):

@Jake Goulding I think changing the return type to impl Debug + 'static should help

RalfJ (Jul 11 2019 at 15:38, on Zulip):

hm, seems like it does not

RalfJ (Jul 11 2019 at 15:38, on Zulip):

that's odd?

Jake Goulding (Jul 11 2019 at 15:39, on Zulip):

Right? :-)

simulacrum (Jul 11 2019 at 15:39, on Zulip):

I would try let v = make_debug(&value); v myself, but not sure

simulacrum (Jul 11 2019 at 15:39, on Zulip):

ah I guess that's a different bug

Jake Goulding (Jul 11 2019 at 15:41, on Zulip):

@RalfJ I'm also pretty sure that the original uses 'static implicitly: opaque type requires that value is borrowed for 'static

RalfJ (Jul 11 2019 at 15:42, on Zulip):

it should say "whatever type actually is behind this impl Trait outlives static"

RalfJ (Jul 11 2019 at 15:42, on Zulip):

aka "didnt capture any non-static references"

RalfJ (Jul 11 2019 at 15:43, on Zulip):

which is what we want here

simulacrum (Jul 11 2019 at 15:45, on Zulip):

I feel like this might actually be intentional in some way, but I'm not sure

simulacrum (Jul 11 2019 at 15:45, on Zulip):

It certainly isn't great from a usability perspective

simulacrum (Jul 11 2019 at 15:45, on Zulip):

but I seem to recall some discussion around impl trait today basically "capturing" all input lifetimes

Jake Goulding (Jul 11 2019 at 15:45, on Zulip):

The original SO question points out that changing to make_debug<T>(_: &T) allows it to work

simulacrum (Jul 11 2019 at 15:46, on Zulip):

right -- I think that's connected to the lifetime becoming "visible"

Jake Goulding (Jul 11 2019 at 15:46, on Zulip):

And fn make_debug<T>(_: T) -> Box<dyn std::fmt::Debug> also works

simulacrum (Jul 11 2019 at 15:47, on Zulip):

neither "hide" the lifetime in T though

Jake Goulding (Jul 11 2019 at 15:48, on Zulip):

Why doesn't the Box version "hide" it?

simulacrum (Jul 11 2019 at 15:48, on Zulip):

#42940

simulacrum (Jul 11 2019 at 15:49, on Zulip):

Yeah, that's definitely the issue I was thinking about

simulacrum (Jul 11 2019 at 15:50, on Zulip):

@RalfJ ^ in case you're interested

Jake Goulding (Jul 11 2019 at 15:53, on Zulip):

Doesn't look like the one workaround mentioned applies here, unless I misunderstood:

trait DebugStatic: std::fmt::Debug + 'static {}
impl<T> DebugStatic for T where T: std::fmt::Debug + 'static {}

fn make_debug<T>(_: T) -> impl DebugStatic {
    Box::new(42u8)
}

fn test() -> impl DebugStatic {
    let value = "value".to_string();
    make_debug(&value)
}
simulacrum (Jul 11 2019 at 15:54, on Zulip):

ah, do you have a link to the comment?

Jake Goulding (Jul 11 2019 at 16:03, on Zulip):

@simulacrum https://github.com/rust-lang/rust/issues/42940#issuecomment-452756105

simulacrum (Jul 11 2019 at 16:04, on Zulip):

hm -- so I think that looks slightly different, since it's nested impl trait

simulacrum (Jul 11 2019 at 16:05, on Zulip):

I suspect that was like, actually a bug, whereas the behavior we're seeing is intentional

simulacrum (Jul 11 2019 at 16:05, on Zulip):

(or, currently intentional, I think)

RalfJ (Jul 11 2019 at 16:44, on Zulip):

but how is it not a bug if a type explicitly marked 'static is not static?

simulacrum (Jul 11 2019 at 17:41, on Zulip):

hm -- yeah, not sure

simulacrum (Jul 11 2019 at 17:41, on Zulip):

that might be abug

simulacrum (Jul 11 2019 at 17:41, on Zulip):

but I think the idea of capturing T's lifetime is probably not one

Last update: Nov 21 2019 at 23:55UTC