Why PartialEq bound is needed when comparing associated types

Viewed 56

Here is an example. There is a Wrapper struct which is parametrized with a Trait, but has a single element of an associated type (Trait::A).

#[derive(PartialEq)]
pub struct Wrapper<T: Trait>(pub(crate) <T as Trait>::A);

pub trait Trait {
    type A: Eq + PartialEq;

    fn a() -> Self::A;
}

pub fn test<T: Trait>() {
    let wrapper = Wrapper::<T>(T::a());
    let _r = wrapper == wrapper;
}

which gives this compiling error:

error[E0369]: binary operation `==` cannot be applied to type `Wrapper<T>`
  --> src/main.rs:12:22
   |
12 |     let _r = wrapper == wrapper;
   |              ------- ^^ ------- Wrapper<T>
   |              |
   |              Wrapper<T>
   |
help: consider further restricting this bound
   |
10 | pub fn test<T: Trait + std::cmp::PartialEq>() {
   |                      +++++++++++++++++++++

For more information about this error, try `rustc --explain E0369`.

Why is the PartialEq bound required, if no Traits are compared, just Trait::As?

1 Answers
#[derive(PartialEq)]
pub struct Wrapper<T: Trait>(pub(crate) <T as Trait>::A);

expands to something like

pub struct Wrapper<T: Trait>(pub(crate) <T as Trait>::A);

impl<T: PartialEq> PartialEq for Wrapper {
   ...
}

In fn test, you're constructing a Wrapper<T>, but T is only required to implement Trait, not PartialEq. The compiler doesn't assume that you really only care if Trait::A can be compared.

To tell it, you'll need to implement PartialEq manually:

impl<T: Trait> PartialEq for Wrapper<T> {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

You may assume that T: Trait is implied for every trait impl if T: Trait is on the struct definition, but that actually isn't the case.

Related