Trait derivation with associated types

Consider code like the following contrived example:

trait Engine {
    type State;

    fn progress(&self, state: Self::State) -> Self::State;
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct InProgressEngine<E: Engine> {
    engine: E,
    state: E::State,
}

//#[derive(Clone, Debug, Eq, PartialEq)] // Doesn't compile
struct KeyedEngine<K, E: Engine> {
    key: K,
    progress: InProgressEngine<E>,
}

Deriving traits on InProgressEngine works fine, but trying to derive those same traits on KeyedEngine results in a compilation error with messages like "the trait bound <E as Engine>::State: Clone is not satisfied". The only workarounds I can see are (a) manually implement the traits for KeyedEngine (which is tedious) and (b) add where E::State: Clone etc. to the definition of KeyedEngine (which is too restrictive). Is there a better way? Is this an acknowledged shortcoming of the derivation system? Should I not be referring to associated types in structs like this in the first place?

It is a type of shortcoming:[1] the derive only figures out the need to add the E::State: Clone requirement when E::State is used in a field.

Here's another workaround.


  1. though "perfect derive" is a tradeoff due to semver hazards ↩︎

2 Likes