Implied lifetime bound of associated types

⚓ rust    📅 2025-05-13    👤 surdeus    👁️ 2      

surdeus

I just hit problem with satisfying the lifetime bound of a generic type parameter that's fed into the GAT of the trait it is implementing. When I write impl <T, CST> CoordsIter for CST where CST: CoordSeqTrait<T = T>, there seems to be no lifetime bound applied to T, but when I instead use CST::T inside the impl, T seems to have a lifetime bound. Here is an example with code that does not compile and a variant that compiles (Playground):

#[derive(Copy, Clone)]
struct Coord<T> {
    x: T,
    y: T,
}

trait CoordsIter {
    type Iter<'a>: Iterator<Item = Coord<Self::Scalar>>
    where
        Self: 'a;

    type Scalar;

    fn coords_iter(&self) -> Self::Iter<'_>;
}

// Same as CoordsIter, but with a different name.
trait CoordsIter2 {
    type Iter<'a>: Iterator<Item = Coord<Self::Scalar>>
    where
        Self: 'a;

    type Scalar;

    fn coords_iter(&self) -> Self::Iter<'_>;
}

trait CoordSeqTrait {
    type T;
}

// This does not compile.
impl<T, CST> CoordsIter for CST
where
    CST: CoordSeqTrait<T = T>,
{
    type Iter<'a> = Box<dyn Iterator<Item = Coord<T>> + 'a>
    where
        Self: 'a;

    type Scalar = T;

    // error[E0311]: the parameter type `T` may not live long enough
    //   --> src/coords_iter.rs:65:9
    //   |
    // 61 |     fn coords_iter(&self) -> Self::Iter<'_> {
    //   |                    ----- the parameter type `T` must be valid for the anonymous lifetime defined here...
    // ...
    // 65 |         Box::new(iter)
    //   |         ^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    //   |
    // help: consider adding an explicit lifetime bound
    //   |
    // 61 -     fn coords_iter(&self) -> Self::Iter<'_> {
    // 61 +     fn coords_iter<'a>(&'a self) -> Self::Iter<'a> where T: 'a {
    //   |
    fn coords_iter(&self) -> Self::Iter<'_> {
        let all_coords: Vec<Coord<T>> = vec![];
        let iter = all_coords.into_iter();
        Box::new(iter)
    }
}

// This compiles.
impl<CST> CoordsIter2 for CST
where
    CST: CoordSeqTrait,
{
    type Iter<'a>
        = Box<dyn Iterator<Item = Coord<CST::T>> + 'a>
    where
        Self: 'a;

    type Scalar = CST::T;

    fn coords_iter(&self) -> Self::Iter<'_> {
        let all_coords: Vec<Coord<CST::T>> = vec![];
        let iter = all_coords.into_iter();
        Box::new(iter)
    }
}

It seems to me that type T in CST::T has some implicit lifetime bound so it is not fully equivalent to defining a generic type parameter T and bound it using CST: CoordSeqTrait<T = T>, but I cannot find any reference to this implicit rule. I'd like to get explanations why these 2 impls are not equivalent, and relevant rules for lifetimes of associated types.

1 post - 1 participant

Read full topic

🏷️ rust_feed