Skip to content

Commit

Permalink
Auto merge of #41559 - GuillaumeGomez:partial-eq-msg, r=estebank
Browse files Browse the repository at this point in the history
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
```
  • Loading branch information
bors committed May 23, 2017
2 parents 81734e0 + 747287a commit 2e91391
Show file tree
Hide file tree
Showing 16 changed files with 72 additions and 57 deletions.
28 changes: 18 additions & 10 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
trait_ref.to_predicate(),
post_message);

let unimplemented_note = self.on_unimplemented_note(trait_ref, obligation);
if let Some(ref s) = unimplemented_note {
// If it has a custom "#[rustc_on_unimplemented]"
// error message, let's display it as the label!
err.span_label(span, s.as_str());
err.help(&format!("{}the trait `{}` is not implemented for `{}`",
pre_message,
trait_ref,
trait_ref.self_ty()));
} else {
err.span_label(span,
&*format!("{}the trait `{}` is not implemented for `{}`",
pre_message,
trait_ref,
trait_ref.self_ty()));
}

// Try to report a help message
if !trait_ref.has_infer_types() &&
self.predicate_can_apply(trait_ref) {
Expand All @@ -571,21 +588,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// which is somewhat confusing.
err.help(&format!("consider adding a `where {}` bound",
trait_ref.to_predicate()));
} else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) {
// If it has a custom "#[rustc_on_unimplemented]"
// error message, let's display it!
err.note(&s);
} else {
} else if unimplemented_note.is_none() {
// Can't show anything else useful, try to find similar impls.
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
self.report_similar_impl_candidates(impl_candidates, &mut err);
}

err.span_label(span,
format!("{}the trait `{}` is not implemented for `{}`",
pre_message,
trait_ref,
trait_ref.self_ty()));
err
}

Expand Down
1 change: 0 additions & 1 deletion src/test/compile-fail/E0277-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ fn is_send<T: Send>() { }
fn main() {
is_send::<Foo>();
//~^ ERROR the trait bound `*const u8: std::marker::Send` is not satisfied in `Foo`
//~| NOTE within `Foo`, the trait `std::marker::Send` is not implemented for `*const u8`
//~| NOTE: `*const u8` cannot be sent between threads safely
//~| NOTE: required because it appears within the type `Baz`
//~| NOTE: required because it appears within the type `Bar`
Expand Down
1 change: 0 additions & 1 deletion src/test/compile-fail/E0277.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ fn some_func<T: Foo>(foo: T) {

fn f(p: Path) { }
//~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied in `std::path::Path`
//~| NOTE within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
//~| NOTE `[u8]` does not have a constant size known at compile-time
//~| NOTE required because it appears within the type `std::path::Path`
//~| NOTE all local variables must have a statically known size
Expand Down
4 changes: 0 additions & 4 deletions src/test/compile-fail/const-unsized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,21 @@ use std::fmt::Debug;

const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync));
//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Syn
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size

const CONST_FOO: str = *"foo";
//~^ ERROR `str: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `str`
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size

static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync));
//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Syn
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size

static STATIC_BAR: str = *"bar";
//~^ ERROR `str: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `str`
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size

Expand Down
2 changes: 0 additions & 2 deletions src/test/compile-fail/impl-trait/auto-trait-leak.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,13 @@ fn send<T: Send>(_: T) {}
fn main() {
send(before());
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
//~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `[closure
//~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
//~| NOTE required by `send`

send(after());
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
//~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `[closure
//~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
Expand Down
3 changes: 0 additions & 3 deletions src/test/compile-fail/on-unimplemented/multiple-impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,14 @@ impl Index<Bar<usize>> for [i32] {
fn main() {
Index::index(&[] as &[i32], 2u32);
//~^ ERROR E0277
//~| NOTE the trait `Index<u32>` is not implemented for `[i32]`
//~| NOTE trait message
//~| NOTE required by
Index::index(&[] as &[i32], Foo(2u32));
//~^ ERROR E0277
//~| NOTE the trait `Index<Foo<u32>>` is not implemented for `[i32]`
//~| NOTE on impl for Foo
//~| NOTE required by
Index::index(&[] as &[i32], Bar(2u32));
//~^ ERROR E0277
//~| NOTE the trait `Index<Bar<u32>>` is not implemented for `[i32]`
//~| NOTE on impl for Bar
//~| NOTE required by
}
1 change: 0 additions & 1 deletion src/test/compile-fail/on-unimplemented/on-impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ impl Index<usize> for [i32] {
fn main() {
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
//~^ ERROR E0277
//~| NOTE the trait `Index<u32>` is not implemented for `[i32]`
//~| NOTE a usize is required
//~| NOTE required by
}
3 changes: 1 addition & 2 deletions src/test/compile-fail/on-unimplemented/on-trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ pub fn main() {
//~^ ERROR
//~^^ NOTE a collection of type `std::option::Option<std::vec::Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
//~^^^ NOTE required by `collect`
//~| NOTE the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option<std::vec::Vec<u8>>`

let x: String = foobar(); //~ ERROR
//~^ NOTE test error `std::string::String` with `u8` `_` `u32`
//~^^ NOTE required by `foobar`
//~| NOTE the trait `Foo<u8, _, u32>` is not implemented for `std::string::String`
}
2 changes: 0 additions & 2 deletions src/test/compile-fail/on-unimplemented/slice-index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ fn main() {
let x = &[1, 2, 3] as &[i32];
x[1i32]; //~ ERROR E0277
//~| NOTE slice indices are of type `usize` or ranges of `usize`
//~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32`
//~| NOTE required because of the requirements on the impl of `std::ops::Index<i32>`
x[..1i32]; //~ ERROR E0277
//~| NOTE slice indices are of type `usize` or ranges of `usize`
//~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo<i32>`
//~| NOTE requirements on the impl of `std::ops::Index<std::ops::RangeTo<i32>>`
}
20 changes: 20 additions & 0 deletions src/test/compile-fail/partialeq_help.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn foo<T: PartialEq>(a: &T, b: T) {
a == b; //~ ERROR E0277
//~| NOTE 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
}

fn main() {
foo(&1, 1);
}
16 changes: 9 additions & 7 deletions src/test/compile-fail/trait-suggest-where-clause.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,53 @@ fn check<T: Iterator, U: ?Sized>() {
// suggest a where-clause, if needed
mem::size_of::<U>();
//~^ ERROR `U: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `U`
//~| HELP consider adding a `where U: std::marker::Sized` bound
//~| NOTE required by `std::mem::size_of`
//~| NOTE `U` does not have a constant size known at compile-time
//~| HELP the trait `std::marker::Sized` is not implemented for `U`

mem::size_of::<Misc<U>>();
//~^ ERROR `U: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `U`
//~| HELP consider adding a `where U: std::marker::Sized` bound
//~| NOTE required because it appears within the type `Misc<U>`
//~| NOTE required by `std::mem::size_of`
//~| NOTE `U` does not have a constant size known at compile-time
//~| HELP within `Misc<U>`, the trait `std::marker::Sized` is not implemented for `U`

// ... even if T occurs as a type parameter

<u64 as From<T>>::from;
//~^ ERROR `u64: std::convert::From<T>` is not satisfied
//~| NOTE the trait `std::convert::From<T>` is not implemented for `u64`
//~| HELP consider adding a `where u64: std::convert::From<T>` bound
//~| NOTE required by `std::convert::From::from`
//~| NOTE the trait `std::convert::From<T>` is not implemented for `u64`

<u64 as From<<T as Iterator>::Item>>::from;
//~^ ERROR `u64: std::convert::From<<T as std::iter::Iterator>::Item>` is not satisfied
//~| NOTE the trait `std::convert::From<<T as std::iter::Iterator>::Item>` is not implemented
//~| HELP consider adding a `where u64:
//~| NOTE required by `std::convert::From::from`
//~| NOTE the trait `std::convert::From<<T as std::iter::Iterator>::Item>` is not implemented

// ... but not if there are inference variables

<Misc<_> as From<T>>::from;
//~^ ERROR `Misc<_>: std::convert::From<T>` is not satisfied
//~| NOTE the trait `std::convert::From<T>` is not implemented for `Misc<_>`
//~| NOTE required by `std::convert::From::from`
//~| NOTE the trait `std::convert::From<T>` is not implemented for `Misc<_>`

// ... and also not if the error is not related to the type

mem::size_of::<[T]>();
//~^ ERROR `[T]: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `[T]`
//~| NOTE `[T]` does not have a constant size
//~| NOTE required by `std::mem::size_of`
//~| HELP the trait `std::marker::Sized` is not implemented for `[T]`

mem::size_of::<[&U]>();
//~^ ERROR `[&U]: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `[&U]`
//~| NOTE `[&U]` does not have a constant size
//~| NOTE required by `std::mem::size_of`
//~| HELP the trait `std::marker::Sized` is not implemented for `[&U]`
}

fn main() {
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/impl-trait/equality.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
--> $DIR/equality.rs:34:9
|
34 | n + sum_to(n - 1)
| ^^^^^^^^^^^^^^^^^ the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
| ^^^^^^^^^^^^^^^^^ no implementation for `u32 + impl Foo`
|
= note: no implementation for `u32 + impl Foo`
= help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32`

error[E0308]: mismatched types
--> $DIR/equality.rs:53:18
Expand Down
28 changes: 14 additions & 14 deletions src/test/ui/mismatched_types/binops.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,57 @@ error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{int
--> $DIR/binops.rs:12:5
|
12 | 1 + Some(1);
| ^^^^^^^^^^^ the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
| ^^^^^^^^^^^ no implementation for `{integer} + std::option::Option<{integer}>`
|
= note: no implementation for `{integer} + std::option::Option<{integer}>`
= help: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`

error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
--> $DIR/binops.rs:13:5
|
13 | 2 as usize - Some(1);
| ^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
| ^^^^^^^^^^^^^^^^^^^^ no implementation for `usize - std::option::Option<{integer}>`
|
= note: no implementation for `usize - std::option::Option<{integer}>`
= help: the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`

error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
--> $DIR/binops.rs:14:5
|
14 | 3 * ();
| ^^^^^^ the trait `std::ops::Mul<()>` is not implemented for `{integer}`
| ^^^^^^ no implementation for `{integer} * ()`
|
= note: no implementation for `{integer} * ()`
= help: the trait `std::ops::Mul<()>` is not implemented for `{integer}`

error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
--> $DIR/binops.rs:15:5
|
15 | 4 / "";
| ^^^^^^ the trait `std::ops::Div<&str>` is not implemented for `{integer}`
| ^^^^^^ no implementation for `{integer} / &str`
|
= note: no implementation for `{integer} / &str`
= help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`

error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
--> $DIR/binops.rs:16:5
|
16 | 5 < String::new();
| ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
| ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String`
|
= note: can't compare `{integer}` with `std::string::String`
= help: the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`

error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
--> $DIR/binops.rs:16:5
|
16 | 5 < String::new();
| ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `{integer}`
| ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String`
|
= note: can't compare `{integer}` with `std::string::String`
= help: the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `{integer}`

error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not satisfied
--> $DIR/binops.rs:17:5
|
17 | 6 == Ok(1);
| ^^^^^^^^^^ the trait `std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not implemented for `{integer}`
| ^^^^^^^^^^ can't compare `{integer}` with `std::result::Result<{integer}, _>`
|
= note: can't compare `{integer}` with `std::result::Result<{integer}, _>`
= help: the trait `std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not implemented for `{integer}`

error: aborting due to 7 previous errors

8 changes: 4 additions & 4 deletions src/test/ui/mismatched_types/cast-rfc0401.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,18 @@ error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
--> $DIR/cast-rfc0401.rs:63:13
|
63 | let _ = fat_v as *const Foo;
| ^^^^^ the trait `std::marker::Sized` is not implemented for `[u8]`
| ^^^^^ `[u8]` does not have a constant size known at compile-time
|
= note: `[u8]` does not have a constant size known at compile-time
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
= note: required for the cast to the object type `Foo`

error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> $DIR/cast-rfc0401.rs:72:13
|
72 | let _ = a as *const Foo;
| ^ the trait `std::marker::Sized` is not implemented for `str`
| ^ `str` does not have a constant size known at compile-time
|
= note: `str` does not have a constant size known at compile-time
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: required for the cast to the object type `Foo`

error: casting `&{float}` as `f32` is invalid
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/resolve/issue-5035-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ error[E0277]: the trait bound `I + 'static: std::marker::Sized` is not satisfied
--> $DIR/issue-5035-2.rs:14:8
|
14 | fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied
| ^^ the trait `std::marker::Sized` is not implemented for `I + 'static`
| ^^ `I + 'static` does not have a constant size known at compile-time
|
= note: `I + 'static` does not have a constant size known at compile-time
= help: the trait `std::marker::Sized` is not implemented for `I + 'static`
= note: all local variables must have a statically known size

error: aborting due to previous error
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/span/multiline-span-simple.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
25 | | bar(x,
26 | |
27 | | y),
| |______________^ the trait `std::ops::Add<()>` is not implemented for `u32`
| |______________^ no implementation for `u32 + ()`
|
= note: no implementation for `u32 + ()`
= help: the trait `std::ops::Add<()>` is not implemented for `u32`

error: aborting due to previous error

0 comments on commit 2e91391

Please sign in to comment.