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

Add better error message when == operator is badly used #41559

Merged
merged 1 commit into from
May 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 `{}`",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is &* necessary here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I'm surprised about it but it seems that it fails otherwise because of the From<&str> not matching and auto-dereferencing a String.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should be able to use the format!() directly since #41745

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's since my last rebase that I can't, so not sure...

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}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not prevent the merge of this PR, but reading this file I feel the full output of this error should be:

error[E0277]: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
  --> $DIR/binops.rs:12:5
   |
12 |     1 + Some(1);
   |     ^^^^^^^^^^^ no implementation for `{integer} + std::option::Option<{integer}>`

instead of

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

Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate having both in case the user isn't well aware of the Add and equivalent traits.


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