diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-06-26 07:50:18 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-26 07:50:18 +0200 |
| commit | 95332b89187bb6a0c910574cfeff1933b619565a (patch) | |
| tree | 6e1e2c51783a5802e1876f050a7d4b836858104b | |
| parent | cf22be186c04900414ff4fb6bd98ad6e38fd6cab (diff) | |
| parent | 2a6a42329f79d3c2a42f23ca9fb68aba511a2bc1 (diff) | |
| download | rust-95332b89187bb6a0c910574cfeff1933b619565a.tar.gz rust-95332b89187bb6a0c910574cfeff1933b619565a.zip | |
Rollup merge of #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 #125631
| -rw-r--r-- | compiler/rustc_hir_typeck/src/method/suggest.rs | 102 | ||||
| -rw-r--r-- | tests/ui/array-slice-vec/vec-res-add.stderr | 5 | ||||
| -rw-r--r-- | tests/ui/autoderef-full-lval.stderr | 12 | ||||
| -rw-r--r-- | tests/ui/binop/binary-op-not-allowed-issue-125631.rs | 16 | ||||
| -rw-r--r-- | tests/ui/binop/binary-op-not-allowed-issue-125631.stderr | 75 | ||||
| -rw-r--r-- | tests/ui/binop/binop-bitxor-str.stderr | 5 | ||||
| -rw-r--r-- | tests/ui/error-codes/E0067.stderr | 6 | ||||
| -rw-r--r-- | tests/ui/issues/issue-14915.stderr | 6 | ||||
| -rw-r--r-- | tests/ui/minus-string.stderr | 5 | ||||
| -rw-r--r-- | tests/ui/pattern/pattern-tyvar-2.stderr | 5 | ||||
| -rw-r--r-- | tests/ui/typeck/assign-non-lval-derefmut.stderr | 8 |
11 files changed, 219 insertions, 26 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4f46320fa02..a385bc70e35 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2831,32 +2831,38 @@ 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); @@ -2864,11 +2870,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .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()), ); @@ -2876,24 +2881,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } } - - 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 diff --git a/tests/ui/array-slice-vec/vec-res-add.stderr b/tests/ui/array-slice-vec/vec-res-add.stderr index cf5796f7e4a..34fd69426a8 100644 --- a/tests/ui/array-slice-vec/vec-res-add.stderr +++ b/tests/ui/array-slice-vec/vec-res-add.stderr @@ -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 diff --git a/tests/ui/autoderef-full-lval.stderr b/tests/ui/autoderef-full-lval.stderr index 9921ce7c154..d90238a7fb2 100644 --- a/tests/ui/autoderef-full-lval.stderr +++ b/tests/ui/autoderef-full-lval.stderr @@ -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 diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.rs b/tests/ui/binop/binary-op-not-allowed-issue-125631.rs new file mode 100644 index 00000000000..8827bbb003b --- /dev/null +++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.rs @@ -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 +} diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr new file mode 100644 index 00000000000..1cf75bbc1a5 --- /dev/null +++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr @@ -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`. diff --git a/tests/ui/binop/binop-bitxor-str.stderr b/tests/ui/binop/binop-bitxor-str.stderr index 20b1ecc5a93..9d9ec6c5af6 100644 --- a/tests/ui/binop/binop-bitxor-str.stderr +++ b/tests/ui/binop/binop-bitxor-str.stderr @@ -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 diff --git a/tests/ui/error-codes/E0067.stderr b/tests/ui/error-codes/E0067.stderr index ec0358cb7df..71b72080544 100644 --- a/tests/ui/error-codes/E0067.stderr +++ b/tests/ui/error-codes/E0067.stderr @@ -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 diff --git a/tests/ui/issues/issue-14915.stderr b/tests/ui/issues/issue-14915.stderr index 279f5772d21..3558bd651c6 100644 --- a/tests/ui/issues/issue-14915.stderr +++ b/tests/ui/issues/issue-14915.stderr @@ -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 diff --git a/tests/ui/minus-string.stderr b/tests/ui/minus-string.stderr index 105274ee7d0..cf63ec24416 100644 --- a/tests/ui/minus-string.stderr +++ b/tests/ui/minus-string.stderr @@ -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 diff --git a/tests/ui/pattern/pattern-tyvar-2.stderr b/tests/ui/pattern/pattern-tyvar-2.stderr index c6540e79558..be52fa8b239 100644 --- a/tests/ui/pattern/pattern-tyvar-2.stderr +++ b/tests/ui/pattern/pattern-tyvar-2.stderr @@ -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 diff --git a/tests/ui/typeck/assign-non-lval-derefmut.stderr b/tests/ui/typeck/assign-non-lval-derefmut.stderr index b26d16da015..ce0ff1d957b 100644 --- a/tests/ui/typeck/assign-non-lval-derefmut.stderr +++ b/tests/ui/typeck/assign-non-lval-derefmut.stderr @@ -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; |
