Skip to content

associated types in generics cause lifetime invariance #115799

Description

@tamird

playground

trait WithAssoc {
    type Assoc;
}

struct ImplsAssoc<'a> {
    phantom: core::marker::PhantomData<&'a ()>,
}

impl WithAssoc for ImplsAssoc<'_> {
    type Assoc = ();
}

struct Holder<W: WithAssoc> {
    foo: W,
    bar: W::Assoc,
}

struct CovariantHolder<W: WithAssoc<Assoc = Assoc>, Assoc = <W as WithAssoc>::Assoc> {
    foo: W,
    bar: Assoc,
}

// This doesn't compile.
fn invariant<'a: 'b, 'b>(x: Holder<ImplsAssoc<'a>>) -> Holder<ImplsAssoc<'b>> {
    x
}

// This compiles.
fn covariant<'a: 'b, 'b>(x: CovariantHolder<ImplsAssoc<'a>>) -> CovariantHolder<ImplsAssoc<'b>> {
    x
}
24 | fn invariant<'a: 'b, 'b>(x: Holder<ImplsAssoc<'a>>) -> Holder<ImplsAssoc<'b>> {
   |              --      -- lifetime `'b` defined here
   |              |
   |              lifetime `'a` defined here
25 |     x
   |     ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
   |
   = help: consider adding the following bound: `'b: 'a`
   = note: requirement occurs because of the type `Holder<ImplsAssoc<'_>>`, which makes the generic argument `ImplsAssoc<'_>` invariant
   = note: the struct `Holder<W>` is invariant over the parameter `W`
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

It's not clear to me why Holder and CovariantHolder are any different. It's not possible construct a CovariantHolder<T, S> where S is anything other than <T as WithAssoc>::Assoc. Why does the compiler treat them differently?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-varianceArea: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)C-bugCategory: This is a bug.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions