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

Change E0369 to give note informations for foreign items. #126925

Merged
merged 1 commit into from
Jun 26, 2024
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
102 changes: 76 additions & 26 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2788,69 +2788,119 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
errors: Vec<FulfillmentError<'tcx>>,
suggest_derive: bool,
) {
let all_local_types_needing_impls =
errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
let preds: Vec<_> = errors
.iter()
.filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
match pred.self_ty().kind() {
ty::Adt(def, _) => def.did().is_local(),
_ => false,
ty::Adt(_, _) => Some(pred),
_ => None,
}
}
_ => false,
});
let mut preds: Vec<_> = errors
.iter()
.filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred),
_ => None,
})
.collect();
preds.sort_by_key(|pred| pred.trait_ref.to_string());
let def_ids = preds

// Note for local items and foreign items respectively.
let (mut local_preds, mut foreign_preds): (Vec<_>, Vec<_>) =
preds.iter().partition(|&pred| {
if let ty::Adt(def, _) = pred.self_ty().kind() {
def.did().is_local()
} else {
false
}
});

local_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string());
let local_def_ids = local_preds
.iter()
.filter_map(|pred| match pred.self_ty().kind() {
ty::Adt(def, _) => Some(def.did()),
_ => None,
})
.collect::<FxIndexSet<_>>();
let mut spans: MultiSpan = def_ids
let mut local_spans: MultiSpan = local_def_ids
.iter()
.filter_map(|def_id| {
let span = self.tcx.def_span(*def_id);
if span.is_dummy() { None } else { Some(span) }
})
.collect::<Vec<_>>()
.into();

for pred in &preds {
for pred in &local_preds {
match pred.self_ty().kind() {
ty::Adt(def, _) if def.did().is_local() => {
spans.push_span_label(
ty::Adt(def, _) => {
local_spans.push_span_label(
self.tcx.def_span(def.did()),
format!("must implement `{}`", pred.trait_ref.print_trait_sugared()),
);
}
_ => {}
}
}

if all_local_types_needing_impls && spans.primary_span().is_some() {
let msg = if preds.len() == 1 {
if local_spans.primary_span().is_some() {
let msg = if local_preds.len() == 1 {
format!(
"an implementation of `{}` might be missing for `{}`",
preds[0].trait_ref.print_trait_sugared(),
preds[0].self_ty()
local_preds[0].trait_ref.print_trait_sugared(),
local_preds[0].self_ty()
)
} else {
format!(
"the following type{} would have to `impl` {} required trait{} for this \
operation to be valid",
pluralize!(def_ids.len()),
if def_ids.len() == 1 { "its" } else { "their" },
pluralize!(preds.len()),
pluralize!(local_def_ids.len()),
if local_def_ids.len() == 1 { "its" } else { "their" },
pluralize!(local_preds.len()),
)
};
err.span_note(local_spans, msg);
}

foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string());
let foreign_def_ids = foreign_preds
.iter()
.filter_map(|pred| match pred.self_ty().kind() {
ty::Adt(def, _) => Some(def.did()),
_ => None,
})
.collect::<FxIndexSet<_>>();
let mut foreign_spans: MultiSpan = foreign_def_ids
.iter()
.filter_map(|def_id| {
let span = self.tcx.def_span(*def_id);
if span.is_dummy() { None } else { Some(span) }
})
.collect::<Vec<_>>()
.into();
for pred in &foreign_preds {
match pred.self_ty().kind() {
ty::Adt(def, _) => {
foreign_spans.push_span_label(
self.tcx.def_span(def.did()),
format!("not implement `{}`", pred.trait_ref.print_trait_sugared()),
);
}
_ => {}
}
}
if foreign_spans.primary_span().is_some() {
let msg = if foreign_preds.len() == 1 {
format!(
"the foreign item type `{}` doesn't implement `{}`",
foreign_preds[0].self_ty(),
foreign_preds[0].trait_ref.print_trait_sugared()
)
} else {
format!(
"the foreign item type{} {} implement required trait{} for this \
operation to be valid",
pluralize!(foreign_def_ids.len()),
if foreign_def_ids.len() > 1 { "don't" } else { "doesn't" },
pluralize!(foreign_preds.len()),
)
};
err.span_note(spans, msg);
err.span_note(foreign_spans, msg);
}

let preds: Vec<_> = errors
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/array-slice-vec/vec-res-add.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ LL | let k = i + j;
| - ^ - Vec<R>
| |
| Vec<R>
|
note: the foreign item type `Vec<R>` doesn't implement `Add`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
= note: not implement `Add`

error: aborting due to 1 previous error

Expand Down
12 changes: 12 additions & 0 deletions tests/ui/autoderef-full-lval.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ LL | let z: isize = a.x + b.y;
| --- ^ --- Box<isize>
| |
| Box<isize>
|
note: the foreign item type `Box<isize>` doesn't implement `Add`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
= note: not implement `Add`

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

error: aborting due to 2 previous errors

Expand Down
16 changes: 16 additions & 0 deletions tests/ui/binop/binary-op-not-allowed-issue-125631.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::io::{Error, ErrorKind};
use std::thread;

struct T1;
struct T2;

fn main() {
(Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2);
//~^ERROR binary operation `==` cannot be applied to type
(Error::new(ErrorKind::Other, "2"), thread::current())
== (Error::new(ErrorKind::Other, "2"), thread::current());
//~^ERROR binary operation `==` cannot be applied to type
(Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2)
== (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2);
//~^ERROR binary operation `==` cannot be applied to type
}
75 changes: 75 additions & 0 deletions tests/ui/binop/binary-op-not-allowed-issue-125631.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, T1, {integer})`
--> $DIR/binary-op-not-allowed-issue-125631.rs:8:48
|
LL | (Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2);
| ------------------------------------------ ^^ ------------------------------------------ (std::io::Error, T1, {integer})
| |
| (std::io::Error, T1, {integer})
|
note: an implementation of `PartialEq` might be missing for `T1`
--> $DIR/binary-op-not-allowed-issue-125631.rs:4:1
|
LL | struct T1;
| ^^^^^^^^^ must implement `PartialEq`
note: the foreign item type `std::io::Error` doesn't implement `PartialEq`
--> $SRC_DIR/std/src/io/error.rs:LL:COL
|
= note: not implement `PartialEq`
help: consider annotating `T1` with `#[derive(PartialEq)]`
|
LL + #[derive(PartialEq)]
LL | struct T1;
|

error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread)`
--> $DIR/binary-op-not-allowed-issue-125631.rs:11:9
|
LL | (Error::new(ErrorKind::Other, "2"), thread::current())
| ------------------------------------------------------ (std::io::Error, Thread)
LL | == (Error::new(ErrorKind::Other, "2"), thread::current());
| ^^ ------------------------------------------------------ (std::io::Error, Thread)
|
note: the foreign item types don't implement required traits for this operation to be valid
--> $SRC_DIR/std/src/io/error.rs:LL:COL
|
= note: not implement `PartialEq`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
|
= note: not implement `PartialEq`

error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread, T1, T2)`
--> $DIR/binary-op-not-allowed-issue-125631.rs:14:9
|
LL | (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2)
| -------------------------------------------------------------- (std::io::Error, Thread, T1, T2)
LL | == (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2);
| ^^ -------------------------------------------------------------- (std::io::Error, Thread, T1, T2)
|
note: the following types would have to `impl` their required traits for this operation to be valid
--> $DIR/binary-op-not-allowed-issue-125631.rs:4:1
|
LL | struct T1;
| ^^^^^^^^^ must implement `PartialEq`
LL | struct T2;
| ^^^^^^^^^ must implement `PartialEq`
note: the foreign item types don't implement required traits for this operation to be valid
--> $SRC_DIR/std/src/io/error.rs:LL:COL
|
= note: not implement `PartialEq`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
|
= note: not implement `PartialEq`
help: consider annotating `T1` with `#[derive(PartialEq)]`
|
LL + #[derive(PartialEq)]
LL | struct T1;
|
help: consider annotating `T2` with `#[derive(PartialEq)]`
|
LL + #[derive(PartialEq)]
LL | struct T2;
|

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0369`.
5 changes: 5 additions & 0 deletions tests/ui/binop/binop-bitxor-str.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); }
| --------------- ^ --------------- String
| |
| String
|
note: the foreign item type `String` doesn't implement `BitXor`
Copy link
Member

Choose a reason for hiding this comment

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

This, and most of the other messages that this PR adds, feels really redundant.

--> $SRC_DIR/alloc/src/string.rs:LL:COL
|
= note: not implement `BitXor`

error: aborting due to 1 previous error

Expand Down
6 changes: 6 additions & 0 deletions tests/ui/error-codes/E0067.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ LL | LinkedList::new() += 1;
| -----------------^^^^^
| |
| cannot use `+=` on type `LinkedList<_>`
|
note: the foreign item type `LinkedList<_>` doesn't implement `AddAssign<{integer}>`
--> $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL
::: $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL
|
= note: not implement `AddAssign<{integer}>`

error[E0067]: invalid left-hand side of assignment
--> $DIR/E0067.rs:4:23
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/issues/issue-14915.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ LL | println!("{}", x + 1);
| - ^ - {integer}
| |
| Box<isize>
|
note: the foreign item type `Box<isize>` doesn't implement `Add<{integer}>`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
= note: not implement `Add<{integer}>`

error: aborting due to 1 previous error

Expand Down
5 changes: 5 additions & 0 deletions tests/ui/minus-string.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ error[E0600]: cannot apply unary operator `-` to type `String`
|
LL | fn main() { -"foo".to_string(); }
| ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
|
note: the foreign item type `String` doesn't implement `Neg`
--> $SRC_DIR/alloc/src/string.rs:LL:COL
|
= note: not implement `Neg`

error: aborting due to 1 previous error

Expand Down
5 changes: 5 additions & 0 deletions tests/ui/pattern/pattern-tyvar-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3;
| - ^ - {integer}
| |
| Vec<isize>
|
note: the foreign item type `Vec<isize>` doesn't implement `Mul<{integer}>`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
= note: not implement `Mul<{integer}>`

error: aborting due to 1 previous error

Expand Down
8 changes: 8 additions & 0 deletions tests/ui/typeck/assign-non-lval-derefmut.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ LL | x.lock().unwrap() += 1;
| |
| cannot use `+=` on type `MutexGuard<'_, usize>`
|
note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
|
= note: not implement `AddAssign<{integer}>`
help: `+=` can be used on `usize` if you dereference the left-hand side
|
LL | *x.lock().unwrap() += 1;
Expand Down Expand Up @@ -47,6 +51,10 @@ LL | y += 1;
| |
| cannot use `+=` on type `MutexGuard<'_, usize>`
|
note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
|
= note: not implement `AddAssign<{integer}>`
help: `+=` can be used on `usize` if you dereference the left-hand side
|
LL | *y += 1;
Expand Down
Loading