Why does the compiler say a trait bound isn't satisfied here?

Here is a simplified version of something real I'm trying to work on, where there are two traits with associated types, and the second one accepts an implementation of the first that is parameterized on the second one's associated type. Further, I need the first one's associated type to be Send:

trait T1<U> {
    type AssocType1;
}

trait T2 {
    type AssocType2;

    fn accept<A>(_: A)
    where
        A: T1<Self::AssocType2>,
        A::AssocType1: Send;
}

impl T2 for () {
    type AssocType2 = ();

    fn accept<A>(_: A)
    where
        A: T1<Self::AssocType2>,
        A::AssocType1: Send,
    {
    }
}

(Playground)

This doesn't compile, with what seems to be a nonsense error about how T1 isn't implemented for A when the bound above clearly requires it to be:

error[E0277]: the trait bound `A: T1<()>` is not satisfied
  --> src/lib.rs:19:5
   |
19 | /     fn accept<A>(_: A)
20 | |     where
21 | |         A: T1<Self::AssocType2>,
22 | |         A::AssocType1: Send,
   | |____________________________^ the trait `T1<()>` is not implemented for `A`

What's going on here? Is this some limitation in the constraint solver, or have I done something wrong? Note that it works fine if T1 is not generic and also if I remove the Send bound.

Is there a workaround?

This is a known bug in the compiler.

1 Like

Thanks. Is there a standard workaround?

None that I'm aware of other than redesigning your traits.
Maybe somebody else knows more about the finer details behind this and possible workarounds.

Thanks. It seems I can redirect through a helper trait, like this, although it kind of stinks and is a lot of boilerplate:

trait T1<U> {
    type AssocType1;
    fn do_foo();
}

trait Helper<AssocType2>: T1<AssocType2> {
    type HelperAssoc: Send;
}

impl<AssocType2, A> Helper<AssocType2> for A
where
    A: T1<AssocType2>,
    A::AssocType1: Send,
{
    type HelperAssoc = A::AssocType1;
}

trait T2 {
    type AssocType2;

    fn accept<A>(_: A)
    where
        A: Helper<Self::AssocType2>;
}

fn check_send<T: Send>() {}

impl T2 for () {
    type AssocType2 = ();

    fn accept<A>(_: A)
    where
        A: Helper<Self::AssocType2>,
    {
        A::do_foo();
        check_send::<A::HelperAssoc>();
    }
}
1 Like