Skip to content

Commit 95332b8

Browse files
authored
Rollup merge of rust-lang#126925 - surechen:fix_125631, r=compiler-errors
Change E0369 to give note informations for foreign items. Change E0369 to give note informations for foreign items. Make it easy for developers to understand why the binop cannot be applied. fixes rust-lang#125631
2 parents cf22be1 + 2a6a423 commit 95332b8

11 files changed

+219
-26
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+76-26
Original file line numberDiff line numberDiff line change
@@ -2831,69 +2831,119 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28312831
errors: Vec<FulfillmentError<'tcx>>,
28322832
suggest_derive: bool,
28332833
) {
2834-
let all_local_types_needing_impls =
2835-
errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
2834+
let preds: Vec<_> = errors
2835+
.iter()
2836+
.filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
28362837
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
28372838
match pred.self_ty().kind() {
2838-
ty::Adt(def, _) => def.did().is_local(),
2839-
_ => false,
2839+
ty::Adt(_, _) => Some(pred),
2840+
_ => None,
28402841
}
28412842
}
2842-
_ => false,
2843-
});
2844-
let mut preds: Vec<_> = errors
2845-
.iter()
2846-
.filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
2847-
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred),
28482843
_ => None,
28492844
})
28502845
.collect();
2851-
preds.sort_by_key(|pred| pred.trait_ref.to_string());
2852-
let def_ids = preds
2846+
2847+
// Note for local items and foreign items respectively.
2848+
let (mut local_preds, mut foreign_preds): (Vec<_>, Vec<_>) =
2849+
preds.iter().partition(|&pred| {
2850+
if let ty::Adt(def, _) = pred.self_ty().kind() {
2851+
def.did().is_local()
2852+
} else {
2853+
false
2854+
}
2855+
});
2856+
2857+
local_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string());
2858+
let local_def_ids = local_preds
28532859
.iter()
28542860
.filter_map(|pred| match pred.self_ty().kind() {
28552861
ty::Adt(def, _) => Some(def.did()),
28562862
_ => None,
28572863
})
28582864
.collect::<FxIndexSet<_>>();
2859-
let mut spans: MultiSpan = def_ids
2865+
let mut local_spans: MultiSpan = local_def_ids
28602866
.iter()
28612867
.filter_map(|def_id| {
28622868
let span = self.tcx.def_span(*def_id);
28632869
if span.is_dummy() { None } else { Some(span) }
28642870
})
28652871
.collect::<Vec<_>>()
28662872
.into();
2867-
2868-
for pred in &preds {
2873+
for pred in &local_preds {
28692874
match pred.self_ty().kind() {
2870-
ty::Adt(def, _) if def.did().is_local() => {
2871-
spans.push_span_label(
2875+
ty::Adt(def, _) => {
2876+
local_spans.push_span_label(
28722877
self.tcx.def_span(def.did()),
28732878
format!("must implement `{}`", pred.trait_ref.print_trait_sugared()),
28742879
);
28752880
}
28762881
_ => {}
28772882
}
28782883
}
2879-
2880-
if all_local_types_needing_impls && spans.primary_span().is_some() {
2881-
let msg = if preds.len() == 1 {
2884+
if local_spans.primary_span().is_some() {
2885+
let msg = if local_preds.len() == 1 {
28822886
format!(
28832887
"an implementation of `{}` might be missing for `{}`",
2884-
preds[0].trait_ref.print_trait_sugared(),
2885-
preds[0].self_ty()
2888+
local_preds[0].trait_ref.print_trait_sugared(),
2889+
local_preds[0].self_ty()
28862890
)
28872891
} else {
28882892
format!(
28892893
"the following type{} would have to `impl` {} required trait{} for this \
28902894
operation to be valid",
2891-
pluralize!(def_ids.len()),
2892-
if def_ids.len() == 1 { "its" } else { "their" },
2893-
pluralize!(preds.len()),
2895+
pluralize!(local_def_ids.len()),
2896+
if local_def_ids.len() == 1 { "its" } else { "their" },
2897+
pluralize!(local_preds.len()),
2898+
)
2899+
};
2900+
err.span_note(local_spans, msg);
2901+
}
2902+
2903+
foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string());
2904+
let foreign_def_ids = foreign_preds
2905+
.iter()
2906+
.filter_map(|pred| match pred.self_ty().kind() {
2907+
ty::Adt(def, _) => Some(def.did()),
2908+
_ => None,
2909+
})
2910+
.collect::<FxIndexSet<_>>();
2911+
let mut foreign_spans: MultiSpan = foreign_def_ids
2912+
.iter()
2913+
.filter_map(|def_id| {
2914+
let span = self.tcx.def_span(*def_id);
2915+
if span.is_dummy() { None } else { Some(span) }
2916+
})
2917+
.collect::<Vec<_>>()
2918+
.into();
2919+
for pred in &foreign_preds {
2920+
match pred.self_ty().kind() {
2921+
ty::Adt(def, _) => {
2922+
foreign_spans.push_span_label(
2923+
self.tcx.def_span(def.did()),
2924+
format!("not implement `{}`", pred.trait_ref.print_trait_sugared()),
2925+
);
2926+
}
2927+
_ => {}
2928+
}
2929+
}
2930+
if foreign_spans.primary_span().is_some() {
2931+
let msg = if foreign_preds.len() == 1 {
2932+
format!(
2933+
"the foreign item type `{}` doesn't implement `{}`",
2934+
foreign_preds[0].self_ty(),
2935+
foreign_preds[0].trait_ref.print_trait_sugared()
2936+
)
2937+
} else {
2938+
format!(
2939+
"the foreign item type{} {} implement required trait{} for this \
2940+
operation to be valid",
2941+
pluralize!(foreign_def_ids.len()),
2942+
if foreign_def_ids.len() > 1 { "don't" } else { "doesn't" },
2943+
pluralize!(foreign_preds.len()),
28942944
)
28952945
};
2896-
err.span_note(spans, msg);
2946+
err.span_note(foreign_spans, msg);
28972947
}
28982948

28992949
let preds: Vec<_> = errors

tests/ui/array-slice-vec/vec-res-add.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ LL | let k = i + j;
55
| - ^ - Vec<R>
66
| |
77
| Vec<R>
8+
|
9+
note: the foreign item type `Vec<R>` doesn't implement `Add`
10+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
11+
|
12+
= note: not implement `Add`
813

914
error: aborting due to 1 previous error
1015

tests/ui/autoderef-full-lval.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ LL | let z: isize = a.x + b.y;
55
| --- ^ --- Box<isize>
66
| |
77
| Box<isize>
8+
|
9+
note: the foreign item type `Box<isize>` doesn't implement `Add`
10+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
11+
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
12+
|
13+
= note: not implement `Add`
814

915
error[E0369]: cannot add `Box<isize>` to `Box<isize>`
1016
--> $DIR/autoderef-full-lval.rs:21:33
@@ -13,6 +19,12 @@ LL | let answer: isize = forty.a + two.a;
1319
| ------- ^ ----- Box<isize>
1420
| |
1521
| Box<isize>
22+
|
23+
note: the foreign item type `Box<isize>` doesn't implement `Add`
24+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
25+
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
26+
|
27+
= note: not implement `Add`
1628

1729
error: aborting due to 2 previous errors
1830

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::io::{Error, ErrorKind};
2+
use std::thread;
3+
4+
struct T1;
5+
struct T2;
6+
7+
fn main() {
8+
(Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2);
9+
//~^ERROR binary operation `==` cannot be applied to type
10+
(Error::new(ErrorKind::Other, "2"), thread::current())
11+
== (Error::new(ErrorKind::Other, "2"), thread::current());
12+
//~^ERROR binary operation `==` cannot be applied to type
13+
(Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2)
14+
== (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2);
15+
//~^ERROR binary operation `==` cannot be applied to type
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, T1, {integer})`
2+
--> $DIR/binary-op-not-allowed-issue-125631.rs:8:48
3+
|
4+
LL | (Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2);
5+
| ------------------------------------------ ^^ ------------------------------------------ (std::io::Error, T1, {integer})
6+
| |
7+
| (std::io::Error, T1, {integer})
8+
|
9+
note: an implementation of `PartialEq` might be missing for `T1`
10+
--> $DIR/binary-op-not-allowed-issue-125631.rs:4:1
11+
|
12+
LL | struct T1;
13+
| ^^^^^^^^^ must implement `PartialEq`
14+
note: the foreign item type `std::io::Error` doesn't implement `PartialEq`
15+
--> $SRC_DIR/std/src/io/error.rs:LL:COL
16+
|
17+
= note: not implement `PartialEq`
18+
help: consider annotating `T1` with `#[derive(PartialEq)]`
19+
|
20+
LL + #[derive(PartialEq)]
21+
LL | struct T1;
22+
|
23+
24+
error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread)`
25+
--> $DIR/binary-op-not-allowed-issue-125631.rs:11:9
26+
|
27+
LL | (Error::new(ErrorKind::Other, "2"), thread::current())
28+
| ------------------------------------------------------ (std::io::Error, Thread)
29+
LL | == (Error::new(ErrorKind::Other, "2"), thread::current());
30+
| ^^ ------------------------------------------------------ (std::io::Error, Thread)
31+
|
32+
note: the foreign item types don't implement required traits for this operation to be valid
33+
--> $SRC_DIR/std/src/io/error.rs:LL:COL
34+
|
35+
= note: not implement `PartialEq`
36+
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
37+
|
38+
= note: not implement `PartialEq`
39+
40+
error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread, T1, T2)`
41+
--> $DIR/binary-op-not-allowed-issue-125631.rs:14:9
42+
|
43+
LL | (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2)
44+
| -------------------------------------------------------------- (std::io::Error, Thread, T1, T2)
45+
LL | == (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2);
46+
| ^^ -------------------------------------------------------------- (std::io::Error, Thread, T1, T2)
47+
|
48+
note: the following types would have to `impl` their required traits for this operation to be valid
49+
--> $DIR/binary-op-not-allowed-issue-125631.rs:4:1
50+
|
51+
LL | struct T1;
52+
| ^^^^^^^^^ must implement `PartialEq`
53+
LL | struct T2;
54+
| ^^^^^^^^^ must implement `PartialEq`
55+
note: the foreign item types don't implement required traits for this operation to be valid
56+
--> $SRC_DIR/std/src/io/error.rs:LL:COL
57+
|
58+
= note: not implement `PartialEq`
59+
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
60+
|
61+
= note: not implement `PartialEq`
62+
help: consider annotating `T1` with `#[derive(PartialEq)]`
63+
|
64+
LL + #[derive(PartialEq)]
65+
LL | struct T1;
66+
|
67+
help: consider annotating `T2` with `#[derive(PartialEq)]`
68+
|
69+
LL + #[derive(PartialEq)]
70+
LL | struct T2;
71+
|
72+
73+
error: aborting due to 3 previous errors
74+
75+
For more information about this error, try `rustc --explain E0369`.

tests/ui/binop/binop-bitxor-str.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); }
55
| --------------- ^ --------------- String
66
| |
77
| String
8+
|
9+
note: the foreign item type `String` doesn't implement `BitXor`
10+
--> $SRC_DIR/alloc/src/string.rs:LL:COL
11+
|
12+
= note: not implement `BitXor`
813

914
error: aborting due to 1 previous error
1015

tests/ui/error-codes/E0067.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ LL | LinkedList::new() += 1;
55
| -----------------^^^^^
66
| |
77
| cannot use `+=` on type `LinkedList<_>`
8+
|
9+
note: the foreign item type `LinkedList<_>` doesn't implement `AddAssign<{integer}>`
10+
--> $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL
11+
::: $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL
12+
|
13+
= note: not implement `AddAssign<{integer}>`
814

915
error[E0067]: invalid left-hand side of assignment
1016
--> $DIR/E0067.rs:4:23

tests/ui/issues/issue-14915.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ LL | println!("{}", x + 1);
55
| - ^ - {integer}
66
| |
77
| Box<isize>
8+
|
9+
note: the foreign item type `Box<isize>` doesn't implement `Add<{integer}>`
10+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
11+
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
12+
|
13+
= note: not implement `Add<{integer}>`
814

915
error: aborting due to 1 previous error
1016

tests/ui/minus-string.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0600]: cannot apply unary operator `-` to type `String`
33
|
44
LL | fn main() { -"foo".to_string(); }
55
| ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
6+
|
7+
note: the foreign item type `String` doesn't implement `Neg`
8+
--> $SRC_DIR/alloc/src/string.rs:LL:COL
9+
|
10+
= note: not implement `Neg`
611

712
error: aborting due to 1 previous error
813

tests/ui/pattern/pattern-tyvar-2.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3;
55
| - ^ - {integer}
66
| |
77
| Vec<isize>
8+
|
9+
note: the foreign item type `Vec<isize>` doesn't implement `Mul<{integer}>`
10+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
11+
|
12+
= note: not implement `Mul<{integer}>`
813

914
error: aborting due to 1 previous error
1015

tests/ui/typeck/assign-non-lval-derefmut.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ LL | x.lock().unwrap() += 1;
1919
| |
2020
| cannot use `+=` on type `MutexGuard<'_, usize>`
2121
|
22+
note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
23+
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
24+
|
25+
= note: not implement `AddAssign<{integer}>`
2226
help: `+=` can be used on `usize` if you dereference the left-hand side
2327
|
2428
LL | *x.lock().unwrap() += 1;
@@ -47,6 +51,10 @@ LL | y += 1;
4751
| |
4852
| cannot use `+=` on type `MutexGuard<'_, usize>`
4953
|
54+
note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
55+
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
56+
|
57+
= note: not implement `AddAssign<{integer}>`
5058
help: `+=` can be used on `usize` if you dereference the left-hand side
5159
|
5260
LL | *y += 1;

0 commit comments

Comments
 (0)