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

Better error messages for &T == T #40660

Closed
iqualfragile opened this issue Mar 20, 2017 · 13 comments · Fixed by #118431
Closed

Better error messages for &T == T #40660

iqualfragile opened this issue Mar 20, 2017 · 13 comments · Fixed by #118431
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-diagnostics Working group: Diagnostics

Comments

@iqualfragile
Copy link

iqualfragile commented Mar 20, 2017

Something along the lines of "you are trying to compare a refference to to Type, try dereferencing first" would be nice, right now it just has the usual PartialEq not implemented.

@GuillaumeGomez GuillaumeGomez added A-frontend Area: Compiler frontend (errors, parsing and HIR) A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools labels Mar 20, 2017
@estebank
Copy link
Contributor

Would the following output (as proposed in #40565) be enough to make the situation a bit more clear?

error[E0277]: the trait bound `&T: std::cmp::PartialEq<T>>` is not satisfied
  --> $DIR/file.rs:14:5
   |
14 |     &t == t;
   |     ^^^^^^^ can't compare `&T` with `T`

@iqualfragile
Copy link
Author

that would certainly improve things, but in this case the error message could be even more specific and thereby helpful by providing the information about deref-ing, so i would keep it as a separate issue, i think

@steveklabnik steveklabnik added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools labels Apr 25, 2017
@Mark-Simulacrum Mark-Simulacrum added A-diagnostics Area: Messages for errors, warnings, and lints and removed A-frontend Area: Compiler frontend (errors, parsing and HIR) labels May 7, 2017
bors added a commit that referenced this issue May 23, 2017
Add better error message when == operator is badly used

Part of #40660.

With the following code:

```rust
fn foo<T: PartialEq>(a: &T, b: T) {
    a == b;
}

fn main() {
    foo(&1, 1);
}
```

It prints:

```
error[E0277]: the trait bound `&T: std::cmp::PartialEq<T>` is not satisfied
 --> test.rs:2:5
  |
2 |     a == b;
  |     ^^^^^^ can't compare `&T` with `T`
  |
  = help: the trait `std::cmp::PartialEq<T>` is not implemented for `&T`
  = help: consider adding a `where &T: std::cmp::PartialEq<T>` bound

error: aborting due to previous error
```
@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 26, 2017
@estebank
Copy link
Contributor

estebank commented Dec 6, 2017

Current output for:

fn main() {
    let x: usize = 3;
    let y: &usize = &3;
    if x == y {
        println!("asdf");
    }
    if y == x {
        println!("asdf");
    }
    if 3 == &3 {
        println!("asdf");
    }
    if &3 == 3 {
        println!("asdf");
    }
}
error[E0308]: mismatched types
 --> src/main.rs:4:13
  |
4 |     if x == y {
  |             ^
  |             |
  |             expected usize, found &usize
  |             help: consider dereferencing the borrow: `*y`
  |
  = note: expected type `usize`
             found type `&usize`

error[E0277]: the trait bound `&usize: std::cmp::PartialEq<usize>` is not satisfied
 --> src/main.rs:7:10
  |
7 |     if y == x {
  |          ^^ can't compare `&usize` with `usize`
  |
  = help: the trait `std::cmp::PartialEq<usize>` is not implemented for `&usize`

error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<&{integer}>` is not satisfied
  --> src/main.rs:10:10
   |
10 |     if 3 == &3 {
   |          ^^ can't compare `{integer}` with `&{integer}`
   |
   = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for `{integer}`

error[E0277]: the trait bound `&{integer}: std::cmp::PartialEq<{integer}>` is not satisfied
  --> src/main.rs:13:11
   |
13 |     if &3 == 3 {
   |           ^^ can't compare `&{integer}` with `{integer}`
   |
   = help: the trait `std::cmp::PartialEq<{integer}>` is not implemented for `&{integer}`

There's room for improvement.

@estebank estebank added E-needs-mentor WG-diagnostics Working group: Diagnostics labels Dec 6, 2017
@estebank
Copy link
Contributor

estebank commented Mar 8, 2019

Current output

error[E0308]: mismatched types
 --> src/main.rs:4:13
  |
4 |     if x == y {
  |             ^
  |             |
  |             expected usize, found &usize
  |             help: consider dereferencing the borrow: `*y`
  |
  = note: expected type `usize`
             found type `&usize`

error[E0277]: can't compare `&usize` with `usize`
 --> src/main.rs:7:10
  |
7 |     if y == x {
  |          ^^ no implementation for `&usize == usize`
  |
  = help: the trait `std::cmp::PartialEq<usize>` is not implemented for `&usize`

error[E0277]: can't compare `{integer}` with `&{integer}`
  --> src/main.rs:10:10
   |
10 |     if 3 == &3 {
   |          ^^ no implementation for `{integer} == &{integer}`
   |
   = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for `{integer}`

error[E0277]: can't compare `&{integer}` with `{integer}`
  --> src/main.rs:13:11
   |
13 |     if &3 == 3 {
   |           ^^ no implementation for `&{integer} == {integer}`
   |
   = help: the trait `std::cmp::PartialEq<{integer}>` is not implemented for `&{integer}`

@estebank
Copy link
Contributor

estebank commented Sep 26, 2019

CC #45109, #60497, #57621, #52544, #39942, #44695.

@rylev
Copy link
Member

rylev commented Dec 9, 2020

Triage: current output is only slightly improved over previous output.

error[E0308]: mismatched types
 --> src/main.rs:4:13
  |
4 |     if x == y {
  |             ^
  |             |
  |             expected `usize`, found `&usize`
  |             help: consider dereferencing the borrow: `*y`

error[E0277]: can't compare `&usize` with `usize`
 --> src/main.rs:7:10
  |
7 |     if y == x {
  |          ^^ no implementation for `&usize == usize`
  |
  = help: the trait `PartialEq<usize>` is not implemented for `&usize`

error[E0277]: can't compare `{integer}` with `&{integer}`
  --> src/main.rs:10:10
   |
10 |     if 3 == &3 {
   |          ^^ no implementation for `{integer} == &{integer}`
   |
   = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`

error[E0277]: can't compare `&{integer}` with `{integer}`
  --> src/main.rs:13:11
   |
13 |     if &3 == 3 {
   |           ^^ no implementation for `&{integer} == {integer}`
   |
   = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`

It's not clear what should improve to make this better. Should we try to detect if T implements the trait and if so, suggest dereferencing &T?

@estebank
Copy link
Contributor

Should we try to detect if T implements the trait and if so, suggest dereferencing &T?

Yes, I think we should do exactly that. I think that #57621, #52544 and #44695 cover that requirement as well (but lets keep them open and close in one sweep once we fix this).

@estebank
Copy link
Contributor

Output with #90006:

error[E0308]: mismatched types
  --> f16.rs:18:13
   |
18 |     if x == y {
   |             ^ expected `usize`, found `&usize`
   |
help: consider dereferencing the borrow
   |
18 |     if x == *y {
   |             +

error[E0369]: can't compare `&usize` with `usize`
  --> f16.rs:21:10
   |
21 |     if y == x {
   |        - ^^ - usize
   |        |
   |        &usize
   |
help: `==` can be applied on `&usize`
   |
21 |     if y == &x {
   |             +
help: `==` can be used on `usize`, you can dereference `y`
   |
21 |     if *y == x {
   |        +

error[E0277]: can't compare `{integer}` with `&{integer}`
  --> f16.rs:24:10
   |
24 |     if 3 == &3 {
   |          ^^ no implementation for `{integer} == &{integer}`
   |
   = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`

error[E0277]: can't compare `&{integer}` with `{integer}`
  --> f16.rs:27:11
   |
27 |     if &3 == 3 {
   |           ^^ no implementation for `&{integer} == {integer}`
   |
   = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`

@estebank estebank added the D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. label Jan 5, 2023
@estebank
Copy link
Contributor

Another case that should be accounted for (from #67571):

struct MyType<T>
    where T: PartialEq,
{
    data: T,
}

impl<T> MyType<T>
    where T: PartialEq,
{
    fn write(&mut self, data: T) {
        self.data = data;
    }

    fn matches(&self, data: &T) -> bool {
        data == self.data
    }
}

fn main() {
    let foo: MyType<String> = MyType { data: String::from("ABC") };
    let bar = String::from("XYZ");

    if foo.matches(&bar) {
         println!("{:?}", bar);
    }    
}

@estebank
Copy link
Contributor

Triage, few changes:

error[E0308]: mismatched types
 --> src/main.rs:4:13
  |
4 |     if x == y {
  |        -    ^ expected `usize`, found `&usize`
  |        |
  |        expected because this is `usize`
  |
help: consider dereferencing the borrow
  |
4 |     if x == *y {
  |             +

error[E0277]: can't compare `&usize` with `usize`
 --> src/main.rs:7:10
  |
7 |     if y == x {
  |          ^^ no implementation for `&usize == usize`
  |
  = help: the trait `PartialEq<usize>` is not implemented for `&usize`
  = help: the trait `PartialEq` is implemented for `usize`
  = help: for that trait implementation, expected `usize`, found `&usize`

error[E0277]: can't compare `{integer}` with `&{integer}`
  --> src/main.rs:10:10
   |
10 |     if 3 == &3 {
   |          ^^ no implementation for `{integer} == &{integer}`
   |
   = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
   = help: the following other types implement trait `PartialEq<Rhs>`:
             isize
             i8
             i16
             i32
             i64
             i128
             usize
             u8
           and 6 others

error[E0277]: can't compare `&{integer}` with `{integer}`
  --> src/main.rs:13:11
   |
13 |     if &3 == 3 {
   |           ^^ no implementation for `&{integer} == {integer}`
   |
   = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`
   = help: the following other types implement trait `PartialEq<Rhs>`:
             isize
             i8
             i16
             i32
             i64
             i128
             usize
             u8
           and 6 others

@sjwang05
Copy link
Contributor

sjwang05 commented Nov 28, 2023

I've gotten the output to look like this:

fn main() {
    let x: usize = 3;
    let y: &usize = &3;
    _ = y == x;
    _ = &y == x;
    _ = &&y == x;
    _ = 3 == &3;
    _ = &3 == 3;
}
error[E0277]: can't compare `&usize` with `usize`
 --> foo.rs:6:11
  |
6 |     _ = y == x;
  |           ^^ no implementation for `&usize == usize`
  |
  = help: the trait `PartialEq<usize>` is not implemented for `&usize`
help: consider dereferencing here
  |
6 |     _ = *y == x;
  |         +

error[E0277]: can't compare `&&usize` with `usize`        
 --> foo.rs:7:12
  |
7 |     _ = &y == x;
  |            ^^ no implementation for `&&usize == usize`
  |
  = help: the trait `PartialEq<usize>` is not implemented for `&&usize`
help: consider removing the borrow and dereferencing instead
  |
7 -     _ = &y == x;
7 +     _ = *y == x;
  |

error[E0277]: can't compare `&&&usize` with `usize`
 --> foo.rs:8:13
  |
8 |     _ = &&y == x;
  |             ^^ no implementation for `&&&usize == usize`
  |
  = help: the trait `PartialEq<usize>` is not implemented for `&&&usize`
help: consider removing the borrows and dereferencing instead
  |
8 -     _ = &&y == x;
8 +     _ = *y == x;
  |

error[E0277]: can't compare `{integer}` with `&{integer}`
 --> foo.rs:9:11
  |
9 |     _ = 3 == &3;
  |           ^^ no implementation for `{integer} == &{integer}`
  |
  = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
  = help: the following other types implement trait `PartialEq<Rhs>`:
            isize
            i8
            i16
            i32
            i64
            i128
            usize
            u8
          and 6 others

error[E0277]: can't compare `&{integer}` with `{integer}`
  --> foo.rs:10:12
   |
10 |     _ = &3 == 3;
   |            ^^ no implementation for `&{integer} == {integer}`
   |
   = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`
help: consider removing the borrow
   |
10 -     _ = &3 == 3;
10 +     _ = 3 == 3;
   |

error: aborting due to 5 previous errors

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

I'll see if I can get Rhs suggestions working.

@rustbot claim

@estebank
Copy link
Contributor

@sjwang05 if you make a new ObligationCauseCode you should be able to keep both lhs and rhs in it to do this.

@sjwang05
Copy link
Contributor

Storing the lhs and rhs HirIds in ObligationCauseCode::BinOp did the trick. Thanks!

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 C-enhancement Category: An issue proposing an enhancement or a PR with one. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-diagnostics Working group: Diagnostics
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants