Having trouble understanding lifetime issue

I suspect this is about Bar not being covariant over 'a, so that &'short F::Bar<'long> can't be coerced to &'short F::Bar<'short>.

Is that correct? If so, is there a way to force Bar to be covariant over its lifetime?

trait Foo: 'static {
    type Bar<'a>;
    fn as_bar(&self) -> Self::Bar<'_>;
}

fn foo<F: Foo>(foo: F) {
    let bar = foo.as_bar();
    handle_bar::<F>(&bar);
}

fn handle_bar<'a, F: Foo>(_: &'a F::Bar<'a>) {}
     let bar = foo.as_bar();
         --- binding `bar` declared here
     handle_bar::<F>(&bar);
                     ^^^^ borrowed value does not live long enough
 }
 -
 |
 `bar` dropped here while still borrowed
 borrow might be used here, when `bar` is dropped and runs the destructor for type `<F as Foo>::Bar<'_>`

You can do this:

fn handle_bar<'a, 'b, F: Foo>(_: &'a F::Bar<'b>) {}

I know, but in my code I cant't control the signature of handle_bar.

You can't make F::Bar covariant, unfortunately.

1 Like

If you control Foo, then you can do this:

trait Foo: 'static {
    type Bar<'a>;
    fn as_bar(&self) -> Self::Bar<'_>;

    fn subtype<'a: 'b, 'b>(bar: &'b Self::Bar<'a>) -> &'b Self::Bar<'b>;
}

fn foo<F: Foo>(foo: F) {
    let bar = foo.as_bar();
    handle_bar::<F>(F::subtype(&bar));
}

fn handle_bar<'a, F: Foo>(_: &'a F::Bar<'a>) {}
2 Likes

If you're going to go that route, you should probably declare it like this:

fn subtype<'a: 'b, 'b, 'c>(bar: &'c Self::Bar<'a>) -> &'c Self::Bar<'b>;
2 Likes