Why doesn't `T` live long enough here?

playground full context

I’m having trouble figuring out why the borrow checker is complaining about this seemingly simple generalization of an impl on &T:

Works:

unsafe impl<T: TrustedContainer + ?Sized> TrustedContainer for &T {
    type Item = T::Item;

    unsafe fn get_unchecked(&self, i: usize) -> &Self::Item {
        T::get_unchecked(self, i)
    }
}

Errors:

unsafe impl<'a, T: ?Sized, D> TrustedContainer for D
where
    T: TrustedContainer,
    D: ops::Deref<Target = T>,
{
    type Item = T::Item;

    unsafe fn get_unchecked(&self, i: usize) -> &Self::Item {
        T::get_unchecked(self, i)
    }
}

The error in question is

error[E0311]: the parameter type `T` may not live long enough
the parameter type `T` must be valid for the anonymous lifetime defined on the method body
...so that the reference type `&T` does not outlive the data it points at

playground link

In the &T implementation, the T may be bounded by any potentially short lived lifetime. Why does the Deref option seem to require a lifetime bound that the specific version doesn’t? (Borrow would be a more correct bound here, I believe, except that it doesn’t constrain T.)

I’m trying to avoid having to write a TrustedContainer impl for every container type (String, Vec, Box, etc.), especially because I’d like the library not to have to contain any std flag (because it’s otherwise no_std compatible). The terminal implementations are [T] and str, and both work perfectly.

Rust doesn’t do a good job of projecting associated types, don’t try and name Deref::Target with a new type.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9a8781d10cb5562317a5aa9fe4f7da4b

I would also file this a bug in the type system

2 Likes

Thanks, that solves it perfectly!

Bug filed: https://github.com/rust-lang/rust/issues/60871

1 Like