Skip to content

Commit 730e5ad

Browse files
committed
Auto merge of #40565 - estebank:binops-help, r=arielb1
Explicit help message for binop type mismatch When trying to do `1 + Some(2)`, or some other binary operation on two types different types without an appropriate trait implementation, provide an explicit help message: ```rust help: `{integer} + std::option::Option<{integer}>` has no implementation ``` Re: #39579, #38564, #37626, #39942, #34698.
2 parents 3b5754e + be8787d commit 730e5ad

File tree

8 files changed

+164
-17
lines changed

8 files changed

+164
-17
lines changed

src/libcore/cmp.rs

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ use self::Ordering::*;
102102
/// ```
103103
#[lang = "eq"]
104104
#[stable(feature = "rust1", since = "1.0.0")]
105+
#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
105106
pub trait PartialEq<Rhs: ?Sized = Self> {
106107
/// This method tests for `self` and `other` values to be equal, and is used
107108
/// by `==`.
@@ -550,6 +551,7 @@ impl PartialOrd for Ordering {
550551
/// ```
551552
#[lang = "ord"]
552553
#[stable(feature = "rust1", since = "1.0.0")]
554+
#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
553555
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
554556
/// This method returns an ordering between `self` and `other` values if one exists.
555557
///

src/libcore/ops.rs

+20
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ pub trait Drop {
242242
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
243243
#[lang = "add"]
244244
#[stable(feature = "rust1", since = "1.0.0")]
245+
#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"]
245246
pub trait Add<RHS=Self> {
246247
/// The resulting type after applying the `+` operator
247248
#[stable(feature = "rust1", since = "1.0.0")]
@@ -315,6 +316,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
315316
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
316317
#[lang = "sub"]
317318
#[stable(feature = "rust1", since = "1.0.0")]
319+
#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"]
318320
pub trait Sub<RHS=Self> {
319321
/// The resulting type after applying the `-` operator
320322
#[stable(feature = "rust1", since = "1.0.0")]
@@ -437,6 +439,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
437439
/// ```
438440
#[lang = "mul"]
439441
#[stable(feature = "rust1", since = "1.0.0")]
442+
#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"]
440443
pub trait Mul<RHS=Self> {
441444
/// The resulting type after applying the `*` operator
442445
#[stable(feature = "rust1", since = "1.0.0")]
@@ -565,6 +568,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
565568
/// ```
566569
#[lang = "div"]
567570
#[stable(feature = "rust1", since = "1.0.0")]
571+
#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"]
568572
pub trait Div<RHS=Self> {
569573
/// The resulting type after applying the `/` operator
570574
#[stable(feature = "rust1", since = "1.0.0")]
@@ -644,6 +648,7 @@ div_impl_float! { f32 f64 }
644648
/// ```
645649
#[lang = "rem"]
646650
#[stable(feature = "rust1", since = "1.0.0")]
651+
#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"]
647652
pub trait Rem<RHS=Self> {
648653
/// The resulting type after applying the `%` operator
649654
#[stable(feature = "rust1", since = "1.0.0")]
@@ -883,6 +888,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
883888
/// ```
884889
#[lang = "bitand"]
885890
#[stable(feature = "rust1", since = "1.0.0")]
891+
#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"]
886892
pub trait BitAnd<RHS=Self> {
887893
/// The resulting type after applying the `&` operator
888894
#[stable(feature = "rust1", since = "1.0.0")]
@@ -966,6 +972,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
966972
/// ```
967973
#[lang = "bitor"]
968974
#[stable(feature = "rust1", since = "1.0.0")]
975+
#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"]
969976
pub trait BitOr<RHS=Self> {
970977
/// The resulting type after applying the `|` operator
971978
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1052,6 +1059,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
10521059
/// ```
10531060
#[lang = "bitxor"]
10541061
#[stable(feature = "rust1", since = "1.0.0")]
1062+
#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"]
10551063
pub trait BitXor<RHS=Self> {
10561064
/// The resulting type after applying the `^` operator
10571065
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1134,6 +1142,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
11341142
/// ```
11351143
#[lang = "shl"]
11361144
#[stable(feature = "rust1", since = "1.0.0")]
1145+
#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"]
11371146
pub trait Shl<RHS> {
11381147
/// The resulting type after applying the `<<` operator
11391148
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1237,6 +1246,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 }
12371246
/// ```
12381247
#[lang = "shr"]
12391248
#[stable(feature = "rust1", since = "1.0.0")]
1249+
#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"]
12401250
pub trait Shr<RHS> {
12411251
/// The resulting type after applying the `>>` operator
12421252
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1321,6 +1331,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
13211331
/// ```
13221332
#[lang = "add_assign"]
13231333
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1334+
#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"]
13241335
pub trait AddAssign<Rhs=Self> {
13251336
/// The method for the `+=` operator
13261337
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1377,6 +1388,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
13771388
/// ```
13781389
#[lang = "sub_assign"]
13791390
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1391+
#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"]
13801392
pub trait SubAssign<Rhs=Self> {
13811393
/// The method for the `-=` operator
13821394
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1422,6 +1434,7 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
14221434
/// ```
14231435
#[lang = "mul_assign"]
14241436
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1437+
#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"]
14251438
pub trait MulAssign<Rhs=Self> {
14261439
/// The method for the `*=` operator
14271440
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1467,6 +1480,7 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
14671480
/// ```
14681481
#[lang = "div_assign"]
14691482
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1483+
#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"]
14701484
pub trait DivAssign<Rhs=Self> {
14711485
/// The method for the `/=` operator
14721486
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1511,6 +1525,7 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
15111525
/// ```
15121526
#[lang = "rem_assign"]
15131527
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1528+
#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"]
15141529
pub trait RemAssign<Rhs=Self> {
15151530
/// The method for the `%=` operator
15161531
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1597,6 +1612,7 @@ rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
15971612
/// ```
15981613
#[lang = "bitand_assign"]
15991614
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1615+
#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"]
16001616
pub trait BitAndAssign<Rhs=Self> {
16011617
/// The method for the `&=` operator
16021618
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1641,6 +1657,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
16411657
/// ```
16421658
#[lang = "bitor_assign"]
16431659
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1660+
#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"]
16441661
pub trait BitOrAssign<Rhs=Self> {
16451662
/// The method for the `|=` operator
16461663
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1685,6 +1702,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
16851702
/// ```
16861703
#[lang = "bitxor_assign"]
16871704
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1705+
#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"]
16881706
pub trait BitXorAssign<Rhs=Self> {
16891707
/// The method for the `^=` operator
16901708
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1729,6 +1747,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
17291747
/// ```
17301748
#[lang = "shl_assign"]
17311749
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1750+
#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"]
17321751
pub trait ShlAssign<Rhs> {
17331752
/// The method for the `<<=` operator
17341753
#[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1794,6 +1813,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
17941813
/// ```
17951814
#[lang = "shr_assign"]
17961815
#[stable(feature = "op_assign_traits", since = "1.8.0")]
1816+
#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"]
17971817
pub trait ShrAssign<Rhs=Self> {
17981818
/// The method for the `>>=` operator
17991819
#[stable(feature = "op_assign_traits", since = "1.8.0")]

src/librustc/traits/error_reporting.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -524,15 +524,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
524524
"the trait bound `{}` is not satisfied{}",
525525
trait_ref.to_predicate(),
526526
post_message);
527-
err.span_label(span,
528-
&format!("{}the trait `{}` is not \
529-
implemented for `{}`",
530-
pre_message,
531-
trait_ref,
532-
trait_ref.self_ty()));
533527

534528
// Try to report a help message
535-
536529
if !trait_ref.has_infer_types() &&
537530
self.predicate_can_apply(trait_ref) {
538531
// If a where-clause may be useful, remind the
@@ -544,17 +537,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
544537
// which is somewhat confusing.
545538
err.help(&format!("consider adding a `where {}` bound",
546539
trait_ref.to_predicate()));
547-
} else if let Some(s) = self.on_unimplemented_note(trait_ref,
548-
obligation) {
540+
} else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) {
549541
// If it has a custom "#[rustc_on_unimplemented]"
550542
// error message, let's display it!
551543
err.note(&s);
552544
} else {
553-
// If we can't show anything useful, try to find
554-
// similar impls.
545+
// Can't show anything else useful, try to find similar impls.
555546
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
556547
self.report_similar_impl_candidates(impl_candidates, &mut err);
557548
}
549+
550+
err.span_label(span,
551+
&format!("{}the trait `{}` is not implemented for `{}`",
552+
pre_message,
553+
trait_ref,
554+
trait_ref.self_ty()));
558555
err
559556
}
560557

@@ -997,3 +994,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
997994
suggested_limit));
998995
}
999996
}
997+

src/test/compile-fail/impl-trait/equality.rs renamed to src/test/ui/impl-trait/equality.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn sum_to(n: u32) -> impl Foo {
3232
0
3333
} else {
3434
n + sum_to(n - 1)
35-
//~^ ERROR the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
35+
//~^ ERROR no implementation for `u32 + impl Foo`
3636
}
3737
}
3838

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/equality.rs:25:5
3+
|
4+
25 | 0_u32
5+
| ^^^^^ expected i32, found u32
6+
|
7+
= note: expected type `i32`
8+
found type `u32`
9+
10+
error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
11+
--> $DIR/equality.rs:34:9
12+
|
13+
34 | n + sum_to(n - 1)
14+
| ^^^^^^^^^^^^^^^^^ the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
15+
|
16+
= note: no implementation for `u32 + impl Foo`
17+
18+
error[E0308]: mismatched types
19+
--> $DIR/equality.rs:53:18
20+
|
21+
53 | let _: u32 = hide(0_u32);
22+
| ^^^^^^^^^^^ expected u32, found anonymized type
23+
|
24+
= note: expected type `u32`
25+
found type `impl Foo`
26+
27+
error[E0308]: mismatched types
28+
--> $DIR/equality.rs:59:18
29+
|
30+
59 | let _: i32 = Leak::leak(hide(0_i32));
31+
| ^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found associated type
32+
|
33+
= note: expected type `i32`
34+
found type `<impl Foo as Leak>::T`
35+
36+
error[E0308]: mismatched types
37+
--> $DIR/equality.rs:66:10
38+
|
39+
66 | x = (x.1,
40+
| ^^^ expected u32, found i32
41+
|
42+
= note: expected type `impl Foo` (u32)
43+
found type `impl Foo` (i32)
44+
45+
error[E0308]: mismatched types
46+
--> $DIR/equality.rs:69:10
47+
|
48+
69 | x.0);
49+
| ^^^ expected i32, found u32
50+
|
51+
= note: expected type `impl Foo` (i32)
52+
found type `impl Foo` (u32)
53+
54+
error: aborting due to 6 previous errors
55+
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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 main() {
12+
1 + Some(1);
13+
2 as usize - Some(1);
14+
3 * ();
15+
4 / "";
16+
5 < String::new();
17+
6 == Ok(1);
18+
}
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
2+
--> $DIR/binops.rs:12:5
3+
|
4+
12 | 1 + Some(1);
5+
| ^^^^^^^^^^^ the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
6+
|
7+
= note: no implementation for `{integer} + std::option::Option<{integer}>`
8+
9+
error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
10+
--> $DIR/binops.rs:13:5
11+
|
12+
13 | 2 as usize - Some(1);
13+
| ^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
14+
|
15+
= note: no implementation for `usize - std::option::Option<{integer}>`
16+
17+
error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
18+
--> $DIR/binops.rs:14:5
19+
|
20+
14 | 3 * ();
21+
| ^^^^^^ the trait `std::ops::Mul<()>` is not implemented for `{integer}`
22+
|
23+
= note: no implementation for `{integer} * ()`
24+
25+
error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
26+
--> $DIR/binops.rs:15:5
27+
|
28+
15 | 4 / "";
29+
| ^^^^^^ the trait `std::ops::Div<&str>` is not implemented for `{integer}`
30+
|
31+
= note: no implementation for `{integer} / &str`
32+
33+
error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
34+
--> $DIR/binops.rs:16:5
35+
|
36+
16 | 5 < String::new();
37+
| ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
38+
|
39+
= note: can't compare `{integer}` with `std::string::String`
40+
41+
error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
42+
--> $DIR/binops.rs:16:5
43+
|
44+
16 | 5 < String::new();
45+
| ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `{integer}`
46+
|
47+
= note: can't compare `{integer}` with `std::string::String`
48+
49+
error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not satisfied
50+
--> $DIR/binops.rs:17:5
51+
|
52+
17 | 6 == Ok(1);
53+
| ^^^^^^^^^^ the trait `std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not implemented for `{integer}`
54+
|
55+
= note: can't compare `{integer}` with `std::result::Result<{integer}, _>`
56+
57+
error: aborting due to 7 previous errors
58+

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
99
27 | | y),
1010
| |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32`
1111
|
12-
= help: the following implementations were found:
13-
<u32 as std::ops::Add>
14-
<&'a u32 as std::ops::Add<u32>>
15-
<u32 as std::ops::Add<&'a u32>>
16-
<&'b u32 as std::ops::Add<&'a u32>>
12+
= note: no implementation for `u32 + ()`
1713

1814
error: aborting due to previous error
1915

0 commit comments

Comments
 (0)