Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error message for T <binop> U worsens if T has exactly one implementation of the relevant trait #77304

Open
SNCPlay42 opened this issue Sep 28, 2020 · 3 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system C-enhancement Category: An issue proposing an enhancement or a PR with one. D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@SNCPlay42
Copy link
Contributor

This code

struct S;

fn main() {
    let _ = S == ();
}

Emits the error message

error[E0369]: binary operation `==` cannot be applied to type `S`
 --> src/main.rs:4:15
  |
4 |     let _ = S == ();
  |             - ^^ -- ()
  |             |
  |             S
  |
  = note: an implementation of `std::cmp::PartialEq` might be missing for `S`

However, if the type S has any implementation of PartialEq<T> for a single type T that is not (), the error message becomes less helpful:

#[derive(PartialEq)]
struct S;

fn main() {
    let _ = S == ();
}
error[E0308]: mismatched types
 --> src/main.rs:5:18
  |
5 |     let _ = S == ();
  |                  ^^ expected struct `S`, found `()`

If there are two or more impls of PartialEq, the error message becomes helpful again:

#[derive(PartialEq)]
struct S;

impl PartialEq<u8> for S {
    fn eq(&self, _: &u8) -> bool {
        unimplemented!()
    }
}

fn main() {
    let _ = S == ();
}
error[E0277]: can't compare `S` with `()`
  --> src/main.rs:11:15
   |
11 |     let _ = S == ();
   |               ^^ no implementation for `S == ()`
   |
   = help: the trait `std::cmp::PartialEq<()>` is not implemented for `S`

This also applies to other binary operation traits like PartialOrd and Add.

@SNCPlay42
Copy link
Contributor Author

This is related to #40660 (which concerns &T == T), and is probably the root cause (I think? &T actually has two PartialEq implementations - for &T and for &mut T - but maybe something's going on with coercions), but the problem is more general than described in that issue.

@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Sep 28, 2020
@JohnTitor JohnTitor added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Oct 1, 2020
@SNCPlay42
Copy link
Contributor Author

So what's going on here is that when type-checking a binop, the compiler:

  1. type-checks the LHS, determining its type
  2. creates a type inference variable T1 for the type of the RHS
  3. looks for an impl of Eq<T1> (or Add/PartialOrd/etc.) on the LHS, recording what this allows it to infer about T1
  4. type-checks the RHS and demands that it be coercable to T1

So how exactly this fails depends on how many impls of Eq there are:

  • If there are no impls of Eq for the LHS, step 3 fails
  • If there is exactly one impl of Eq for the LHS, step 3 succeeds and the compiler can now infer exactly what T1 must be (e.g. S in the above case). Step 4 then fails when the RHS does not have the expected type. The compiler only complains that RHS != S without giving its reasoning for why it expected S.
  • If there are more than one impl of Eq, step 3 succeeds but the compiler can't determine exactly what T1 is, only that it must satisfy LHS: Eq<T1>. Step 4 then tries to coerce the RHS to T1 and gives the error that LHS: Eq<RHS> doesn't hold.

Ideally one code path would be responsible for the diagnostics in all three cases.

@nagisa
Copy link
Member

nagisa commented May 12, 2022

See the issue above for a reproduction of this which arguably is much worse. I've also been able to reproduce this without binops too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system C-enhancement Category: An issue proposing an enhancement or a PR with one. D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants