about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-06-26 07:50:18 +0200
committerGitHub <noreply@github.com>2024-06-26 07:50:18 +0200
commit95332b89187bb6a0c910574cfeff1933b619565a (patch)
tree6e1e2c51783a5802e1876f050a7d4b836858104b
parentcf22be186c04900414ff4fb6bd98ad6e38fd6cab (diff)
parent2a6a42329f79d3c2a42f23ca9fb68aba511a2bc1 (diff)
downloadrust-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.rs102
-rw-r--r--tests/ui/array-slice-vec/vec-res-add.stderr5
-rw-r--r--tests/ui/autoderef-full-lval.stderr12
-rw-r--r--tests/ui/binop/binary-op-not-allowed-issue-125631.rs16
-rw-r--r--tests/ui/binop/binary-op-not-allowed-issue-125631.stderr75
-rw-r--r--tests/ui/binop/binop-bitxor-str.stderr5
-rw-r--r--tests/ui/error-codes/E0067.stderr6
-rw-r--r--tests/ui/issues/issue-14915.stderr6
-rw-r--r--tests/ui/minus-string.stderr5
-rw-r--r--tests/ui/pattern/pattern-tyvar-2.stderr5
-rw-r--r--tests/ui/typeck/assign-non-lval-derefmut.stderr8
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;