Skip to content

Using associated type as struct field causes invariance w.r.t trait #57440

Closed
@philipc

Description

@philipc

The following code:

pub trait Trait {
    type Assoc: 'static;
}

pub struct I<'a>(pub &'a ());

impl<'a> Trait for I<'a> {
    type Assoc = ();
}

pub struct S1<T, A>
where
    T: Trait<Assoc = A>,
    A: 'static,
{
    pub t: T,
    pub a: A,
}

pub struct S2<T>
where
    T: Trait,
    T::Assoc: 'static,
{
    pub t: T,
    pub a: T::Assoc,
}

pub fn assert_covariance_i<'new, 'old: 'new>(i: I<'old>) -> I<'new> { i }
pub fn assert_covariance_s1<'new, 'old: 'new>(s1: S1<I<'old>, ()>) -> S1<I<'new>, ()> { s1 }
pub fn assert_covariance_s2<'new, 'old: 'new>(s2: S2<I<'old>>) -> S2<I<'new>> { s2 }

fails with:

error[E0308]: mismatched types
  --> src/lib.rs:31:81
   |
31 | pub fn assert_covariance_s2<'new, 'old: 'new>(s2: S2<I<'old>>) -> S2<I<'new>> { s2 }
   |                                                                                 ^^ lifetime mismatch
   |
   = note: expected type `S2<I<'new>>`
              found type `S2<I<'old>>`
note: the lifetime 'new as defined on the function body at 31:29...
  --> src/lib.rs:31:29
   |
31 | pub fn assert_covariance_s2<'new, 'old: 'new>(s2: S2<I<'old>>) -> S2<I<'new>> { s2 }
   |                             ^^^^
note: ...does not necessarily outlive the lifetime 'old as defined on the function body at 31:35
  --> src/lib.rs:31:35
   |
31 | pub fn assert_covariance_s2<'new, 'old: 'new>(s2: S2<I<'old>>) -> S2<I<'new>> { s2 }
   |                                   ^^^^

I would expect the variance of S1 and S2 to be the same w.r.t T. And even if this case can't be handled in general for all associated types, shouldn't the Assoc: 'static bound allow it?

I've been using S1 as a workaround for this issue, but the problem with that is the extra type parameter propagates upwards into all containing types, and it gets quite ugly and verbose.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions