Skip to content

The PartialEq implementation for tuples isn't general enough #105092

Open
@Michael-F-Bryan

Description

@Michael-F-Bryan

A coworker recently ran into a situation where tuples aren't comparable even when their individual elements are. I was able to boil it down to the following code snippet:

fn main() {
    assert_partial_eq::<A, B>();
    assert_partial_eq::<C, D>();
    assert_partial_eq::<(A, C), (B, D)>();
}

fn assert_partial_eq<A, B>() where A: PartialEq<B> {}

#[derive(Debug, PartialEq)] struct A;
#[derive(Debug, PartialEq)] struct B;
#[derive(Debug, PartialEq)] struct C;
#[derive(Debug, PartialEq)] struct D;

impl PartialEq<A> for B { fn eq(&self, other: &A) -> bool { true } }
impl PartialEq<B> for A { fn eq(&self, other: &B) -> bool { true } }

impl PartialEq<C> for D { fn eq(&self, other: &C) -> bool { true } }
impl PartialEq<D> for C { fn eq(&self, other: &D) -> bool { true } }

(playground)

I expected the above snippet to compile and run successfully, but the code fails to compile.

Compiling playground v0.0.1 (/playground)
error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): can't compare `(A, C)` with `(B, D)`
  --> src/main.rs:19:25
   |
19 |     assert_partial_eq::<(A, C), (B, D)>();
   |                         ^^^^^^ no implementation for `(A, C) == (B, D)`
   |
   = help: the trait `PartialEq<(B, D)>` is not implemented for `(A, C)`
   = help: the following other types implement trait `PartialEq<Rhs>`:
             ()
             (A, Z, Y, X, W, V, U, T)
             (B, A, Z, Y, X, W, V, U, T)
             (C, B, A, Z, Y, X, W, V, U, T)
             (D, C, B, A, Z, Y, X, W, V, U, T)
             (E, D, C, B, A, Z, Y, X, W, V, U, T)
             (T,)
             (U, T)
           and 5 others
note: required by a bound in `assert_partial_eq`
  --> src/main.rs:22:39
   |
22 | fn assert_partial_eq<A, B>() where A: PartialEq<B> {}
   |                                       ^^^^^^^^^^^^ required by this bound in `assert_partial_eq`

I always thought the standard library would have something like this:

impl<LHS1, LHS2, RHS1, RHS2> PartialEq<(RHS1, RHS2)> for (LHS1, LHS2)
where 
  LHS1: PartialEq<RHS1>,
  LHS2: PartialEq<RHS2>,
{
  ...
}

But it seems like it only implements PartialEq when the left-hand side tuple and right-hand side tuple have the exact same type.

Meta

This is reproducible on the Rust playground using stable (1.65.0).

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-libs-apiRelevant to the library API 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