Skip to content

Commit 2e91391

Browse files
committed
Auto merge of #41559 - GuillaumeGomez:partial-eq-msg, r=estebank
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 ```
2 parents 81734e0 + 747287a commit 2e91391

16 files changed

+72
-57
lines changed

src/librustc/traits/error_reporting.rs

+18-10
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
559559
trait_ref.to_predicate(),
560560
post_message);
561561

562+
let unimplemented_note = self.on_unimplemented_note(trait_ref, obligation);
563+
if let Some(ref s) = unimplemented_note {
564+
// If it has a custom "#[rustc_on_unimplemented]"
565+
// error message, let's display it as the label!
566+
err.span_label(span, s.as_str());
567+
err.help(&format!("{}the trait `{}` is not implemented for `{}`",
568+
pre_message,
569+
trait_ref,
570+
trait_ref.self_ty()));
571+
} else {
572+
err.span_label(span,
573+
&*format!("{}the trait `{}` is not implemented for `{}`",
574+
pre_message,
575+
trait_ref,
576+
trait_ref.self_ty()));
577+
}
578+
562579
// Try to report a help message
563580
if !trait_ref.has_infer_types() &&
564581
self.predicate_can_apply(trait_ref) {
@@ -571,21 +588,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
571588
// which is somewhat confusing.
572589
err.help(&format!("consider adding a `where {}` bound",
573590
trait_ref.to_predicate()));
574-
} else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) {
575-
// If it has a custom "#[rustc_on_unimplemented]"
576-
// error message, let's display it!
577-
err.note(&s);
578-
} else {
591+
} else if unimplemented_note.is_none() {
579592
// Can't show anything else useful, try to find similar impls.
580593
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
581594
self.report_similar_impl_candidates(impl_candidates, &mut err);
582595
}
583596

584-
err.span_label(span,
585-
format!("{}the trait `{}` is not implemented for `{}`",
586-
pre_message,
587-
trait_ref,
588-
trait_ref.self_ty()));
589597
err
590598
}
591599

src/test/compile-fail/E0277-2.rs

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ fn is_send<T: Send>() { }
2525
fn main() {
2626
is_send::<Foo>();
2727
//~^ ERROR the trait bound `*const u8: std::marker::Send` is not satisfied in `Foo`
28-
//~| NOTE within `Foo`, the trait `std::marker::Send` is not implemented for `*const u8`
2928
//~| NOTE: `*const u8` cannot be sent between threads safely
3029
//~| NOTE: required because it appears within the type `Baz`
3130
//~| NOTE: required because it appears within the type `Bar`

src/test/compile-fail/E0277.rs

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ fn some_func<T: Foo>(foo: T) {
2020

2121
fn f(p: Path) { }
2222
//~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied in `std::path::Path`
23-
//~| NOTE within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
2423
//~| NOTE `[u8]` does not have a constant size known at compile-time
2524
//~| NOTE required because it appears within the type `std::path::Path`
2625
//~| NOTE all local variables must have a statically known size

src/test/compile-fail/const-unsized.rs

-4
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,21 @@ use std::fmt::Debug;
1212

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

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

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

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

src/test/compile-fail/impl-trait/auto-trait-leak.rs

-2
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,13 @@ fn send<T: Send>(_: T) {}
2626
fn main() {
2727
send(before());
2828
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
29-
//~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
3029
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
3130
//~| NOTE required because it appears within the type `[closure
3231
//~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
3332
//~| NOTE required by `send`
3433

3534
send(after());
3635
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
37-
//~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
3836
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
3937
//~| NOTE required because it appears within the type `[closure
4038
//~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`

src/test/compile-fail/on-unimplemented/multiple-impls.rs

-3
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,14 @@ impl Index<Bar<usize>> for [i32] {
4242
fn main() {
4343
Index::index(&[] as &[i32], 2u32);
4444
//~^ ERROR E0277
45-
//~| NOTE the trait `Index<u32>` is not implemented for `[i32]`
4645
//~| NOTE trait message
4746
//~| NOTE required by
4847
Index::index(&[] as &[i32], Foo(2u32));
4948
//~^ ERROR E0277
50-
//~| NOTE the trait `Index<Foo<u32>>` is not implemented for `[i32]`
5149
//~| NOTE on impl for Foo
5250
//~| NOTE required by
5351
Index::index(&[] as &[i32], Bar(2u32));
5452
//~^ ERROR E0277
55-
//~| NOTE the trait `Index<Bar<u32>>` is not implemented for `[i32]`
5653
//~| NOTE on impl for Bar
5754
//~| NOTE required by
5855
}

src/test/compile-fail/on-unimplemented/on-impl.rs

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ impl Index<usize> for [i32] {
3131
fn main() {
3232
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
3333
//~^ ERROR E0277
34-
//~| NOTE the trait `Index<u32>` is not implemented for `[i32]`
3534
//~| NOTE a usize is required
3635
//~| NOTE required by
3736
}

src/test/compile-fail/on-unimplemented/on-trait.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ pub fn main() {
3535
//~^ ERROR
3636
//~^^ NOTE a collection of type `std::option::Option<std::vec::Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
3737
//~^^^ NOTE required by `collect`
38-
//~| NOTE the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option<std::vec::Vec<u8>>`
38+
3939
let x: String = foobar(); //~ ERROR
4040
//~^ NOTE test error `std::string::String` with `u8` `_` `u32`
4141
//~^^ NOTE required by `foobar`
42-
//~| NOTE the trait `Foo<u8, _, u32>` is not implemented for `std::string::String`
4342
}

src/test/compile-fail/on-unimplemented/slice-index.rs

-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ fn main() {
2020
let x = &[1, 2, 3] as &[i32];
2121
x[1i32]; //~ ERROR E0277
2222
//~| NOTE slice indices are of type `usize` or ranges of `usize`
23-
//~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32`
2423
//~| NOTE required because of the requirements on the impl of `std::ops::Index<i32>`
2524
x[..1i32]; //~ ERROR E0277
2625
//~| NOTE slice indices are of type `usize` or ranges of `usize`
27-
//~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo<i32>`
2826
//~| NOTE requirements on the impl of `std::ops::Index<std::ops::RangeTo<i32>>`
2927
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn foo<T: PartialEq>(a: &T, b: T) {
12+
a == b; //~ ERROR E0277
13+
//~| NOTE can't compare `&T` with `T`
14+
//~| HELP the trait `std::cmp::PartialEq<T>` is not implemented for `&T`
15+
//~| HELP consider adding a `where &T: std::cmp::PartialEq<T>` bound
16+
}
17+
18+
fn main() {
19+
foo(&1, 1);
20+
}

src/test/compile-fail/trait-suggest-where-clause.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,53 @@ fn check<T: Iterator, U: ?Sized>() {
1616
// suggest a where-clause, if needed
1717
mem::size_of::<U>();
1818
//~^ ERROR `U: std::marker::Sized` is not satisfied
19-
//~| NOTE the trait `std::marker::Sized` is not implemented for `U`
2019
//~| HELP consider adding a `where U: std::marker::Sized` bound
2120
//~| NOTE required by `std::mem::size_of`
21+
//~| NOTE `U` does not have a constant size known at compile-time
22+
//~| HELP the trait `std::marker::Sized` is not implemented for `U`
2223

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

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

3234
<u64 as From<T>>::from;
3335
//~^ ERROR `u64: std::convert::From<T>` is not satisfied
34-
//~| NOTE the trait `std::convert::From<T>` is not implemented for `u64`
3536
//~| HELP consider adding a `where u64: std::convert::From<T>` bound
3637
//~| NOTE required by `std::convert::From::from`
38+
//~| NOTE the trait `std::convert::From<T>` is not implemented for `u64`
3739

3840
<u64 as From<<T as Iterator>::Item>>::from;
3941
//~^ ERROR `u64: std::convert::From<<T as std::iter::Iterator>::Item>` is not satisfied
40-
//~| NOTE the trait `std::convert::From<<T as std::iter::Iterator>::Item>` is not implemented
4142
//~| HELP consider adding a `where u64:
4243
//~| NOTE required by `std::convert::From::from`
44+
//~| NOTE the trait `std::convert::From<<T as std::iter::Iterator>::Item>` is not implemented
4345

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

4648
<Misc<_> as From<T>>::from;
4749
//~^ ERROR `Misc<_>: std::convert::From<T>` is not satisfied
48-
//~| NOTE the trait `std::convert::From<T>` is not implemented for `Misc<_>`
4950
//~| NOTE required by `std::convert::From::from`
51+
//~| NOTE the trait `std::convert::From<T>` is not implemented for `Misc<_>`
5052

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

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

5961
mem::size_of::<[&U]>();
6062
//~^ ERROR `[&U]: std::marker::Sized` is not satisfied
61-
//~| NOTE the trait `std::marker::Sized` is not implemented for `[&U]`
6263
//~| NOTE `[&U]` does not have a constant size
6364
//~| NOTE required by `std::mem::size_of`
65+
//~| HELP the trait `std::marker::Sized` is not implemented for `[&U]`
6466
}
6567

6668
fn main() {

src/test/ui/impl-trait/equality.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
1111
--> $DIR/equality.rs:34:9
1212
|
1313
34 | n + sum_to(n - 1)
14-
| ^^^^^^^^^^^^^^^^^ the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
14+
| ^^^^^^^^^^^^^^^^^ no implementation for `u32 + impl Foo`
1515
|
16-
= note: no implementation for `u32 + impl Foo`
16+
= help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
1717

1818
error[E0308]: mismatched types
1919
--> $DIR/equality.rs:53:18

src/test/ui/mismatched_types/binops.stderr

+14-14
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,57 @@ error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{int
22
--> $DIR/binops.rs:12:5
33
|
44
12 | 1 + Some(1);
5-
| ^^^^^^^^^^^ the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
5+
| ^^^^^^^^^^^ no implementation for `{integer} + std::option::Option<{integer}>`
66
|
7-
= note: no implementation for `{integer} + std::option::Option<{integer}>`
7+
= help: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
88

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

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

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

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

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

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

5757
error: aborting due to 7 previous errors
5858

src/test/ui/mismatched_types/cast-rfc0401.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -210,18 +210,18 @@ error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
210210
--> $DIR/cast-rfc0401.rs:63:13
211211
|
212212
63 | let _ = fat_v as *const Foo;
213-
| ^^^^^ the trait `std::marker::Sized` is not implemented for `[u8]`
213+
| ^^^^^ `[u8]` does not have a constant size known at compile-time
214214
|
215-
= note: `[u8]` does not have a constant size known at compile-time
215+
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
216216
= note: required for the cast to the object type `Foo`
217217

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

227227
error: casting `&{float}` as `f32` is invalid

src/test/ui/resolve/issue-5035-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ error[E0277]: the trait bound `I + 'static: std::marker::Sized` is not satisfied
22
--> $DIR/issue-5035-2.rs:14:8
33
|
44
14 | fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied
5-
| ^^ the trait `std::marker::Sized` is not implemented for `I + 'static`
5+
| ^^ `I + 'static` does not have a constant size known at compile-time
66
|
7-
= note: `I + 'static` does not have a constant size known at compile-time
7+
= help: the trait `std::marker::Sized` is not implemented for `I + 'static`
88
= note: all local variables must have a statically known size
99

1010
error: aborting due to previous error

src/test/ui/span/multiline-span-simple.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
77
25 | | bar(x,
88
26 | |
99
27 | | y),
10-
| |______________^ the trait `std::ops::Add<()>` is not implemented for `u32`
10+
| |______________^ no implementation for `u32 + ()`
1111
|
12-
= note: no implementation for `u32 + ()`
12+
= help: the trait `std::ops::Add<()>` is not implemented for `u32`
1313

1414
error: aborting due to previous error
1515

0 commit comments

Comments
 (0)