How should I describe generic types lifetime relationship?

Viewed 74

Assume having a typical example of GAT, referencing iterator:

#![feature(generic_associated_types)]
use std::ops::Deref;

trait MyIterator {
    type Item<'a>
    where
        Self: 'a;
    fn next(&mut self) -> Self::Item<'_>;
}

For example, I can implement this for Box<T>.

// This is OK
impl<U> MyIterator for Box<U> {
    type Item<'a> = &'a U
    where
        Self: 'a;
    fn next(&mut self) -> Self::Item<'_> {
        <Box<T> as Deref>::deref(self)
    }
}

But not when I generalize it with Deref trait:

// error[E0309]: the parameter type `U` may not live long enough
impl<T, U> MyIterator for T
where
    T: Deref<Target = U>,
{
    type Item<'a> = &'a U
    where
        Self: 'a;
    fn next(&mut self) -> Self::Item<'_> {
        <T as Deref>::deref(self)
    }
}

In my understanding, in the Box<T> case compiler somehow knows that the type U is owned by Box<U> so U is assured to live longer than Box<U>. So if Box<U>: 'a then the compiler can say U: 'a.

But this logic is not working for the Deref<Target=U> case even though Deref has deref(&self) -> &Self::Target method, which is implying that for any lifetime T: 'a then U: 'a.

How can I tell the compiler that the latter case is actually safe?

1 Answers

The problem is that you are making both T and U into independent type parameters but in fact U is always uniquely determined by T.

Using the Deref::Target type of T instead is what you really mean, and also makes it easier for the type checker to infer the lifetimes.

impl<T> MyIterator for T
where
    T: Deref,
{
    type Item<'a> = &'a <T as Deref>::Target
    where
        Self: 'a;
    fn next(&mut self) -> Self::Item<'_> {
        <T as Deref>::deref(self)
    }
}
Related