Change E0369 diagnostic give note information for foreign items.
Make it easy for developers to understand why the binop cannot be applied. fixes #125631
This commit is contained in:
parent
4e63822fc4
commit
2a6a42329f
@ -2788,32 +2788,38 @@ pub(crate) fn note_unmet_impls_on_type(
|
||||
errors: Vec<FulfillmentError<'tcx>>,
|
||||
suggest_derive: bool,
|
||||
) {
|
||||
let all_local_types_needing_impls =
|
||||
errors.iter().all(|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,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
});
|
||||
let mut preds: Vec<_> = errors
|
||||
let preds: Vec<_> = errors
|
||||
.iter()
|
||||
.filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
|
||||
match pred.self_ty().kind() {
|
||||
ty::Adt(_, _) => Some(pred),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => 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);
|
||||
@ -2821,11 +2827,10 @@ pub(crate) fn note_unmet_impls_on_type(
|
||||
})
|
||||
.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()),
|
||||
);
|
||||
@ -2833,24 +2838,69 @@ pub(crate) fn note_unmet_impls_on_type(
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
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(spans, msg);
|
||||
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(foreign_spans, msg);
|
||||
}
|
||||
|
||||
let preds: Vec<_> = errors
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
||||
|
16
tests/ui/binop/binary-op-not-allowed-issue-125631.rs
Normal file
16
tests/ui/binop/binary-op-not-allowed-issue-125631.rs
Normal file
@ -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
tests/ui/binop/binary-op-not-allowed-issue-125631.stderr
Normal file
75
tests/ui/binop/binary-op-not-allowed-issue-125631.stderr
Normal file
@ -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,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`
|
||||
--> $SRC_DIR/alloc/src/string.rs:LL:COL
|
||||
|
|
||||
= note: not implement `BitXor`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user