From f28d8b13dffc372b099aa9a0e906b21962569076 Mon Sep 17 00:00:00 2001
From: Frank King <frankking1729@gmail.com>
Date: Tue, 22 Mar 2022 12:17:30 +0800
Subject: [PATCH] suggest constraining param for unary ops when missing trait
 impl

---
 compiler/rustc_typeck/src/check/op.rs         | 21 ++++++++++++
 .../ui/type/type-check/missing_trait_impl.rs  |  6 ++++
 .../type/type-check/missing_trait_impl.stderr | 32 +++++++++++++++++--
 3 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index af154e62a1e16..e0dbe027aefe9 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -672,6 +672,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ex.span,
                         format!("cannot apply unary operator `{}`", op.as_str()),
                     );
+                    let missing_trait = match op {
+                        hir::UnOp::Deref => unreachable!("check unary op `-` or `!` only"),
+                        hir::UnOp::Not => "std::ops::Not",
+                        hir::UnOp::Neg => "std::ops::Neg",
+                    };
+                    let mut visitor = TypeParamVisitor(vec![]);
+                    visitor.visit_ty(operand_ty);
+                    if let [ty] = &visitor.0[..] {
+                        if let ty::Param(p) = *operand_ty.kind() {
+                            suggest_constraining_param(
+                                self.tcx,
+                                self.body_id,
+                                &mut err,
+                                *ty,
+                                operand_ty,
+                                missing_trait,
+                                p,
+                                true,
+                            );
+                        }
+                    }
 
                     let sp = self.tcx.sess.source_map().start_point(ex.span);
                     if let Some(sp) =
diff --git a/src/test/ui/type/type-check/missing_trait_impl.rs b/src/test/ui/type/type-check/missing_trait_impl.rs
index f61ada3f63ff9..0e3e703a2f5ac 100644
--- a/src/test/ui/type/type-check/missing_trait_impl.rs
+++ b/src/test/ui/type/type-check/missing_trait_impl.rs
@@ -8,3 +8,9 @@ fn foo<T>(x: T, y: T) {
 fn bar<T>(x: T) {
     x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
 }
+
+fn baz<T>(x: T) {
+    let y = -x; //~ ERROR cannot apply unary operator `-` to type `T`
+    let y = !x; //~ ERROR cannot apply unary operator `!` to type `T`
+    let y = *x; //~ ERROR type `T` cannot be dereferenced
+}
diff --git a/src/test/ui/type/type-check/missing_trait_impl.stderr b/src/test/ui/type/type-check/missing_trait_impl.stderr
index 45f2e845735ea..59b8692dd4d1a 100644
--- a/src/test/ui/type/type-check/missing_trait_impl.stderr
+++ b/src/test/ui/type/type-check/missing_trait_impl.stderr
@@ -24,7 +24,35 @@ help: consider restricting type parameter `T`
 LL | fn bar<T: std::ops::AddAssign>(x: T) {
    |         +++++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error[E0600]: cannot apply unary operator `-` to type `T`
+  --> $DIR/missing_trait_impl.rs:13:13
+   |
+LL |     let y = -x;
+   |             ^^ cannot apply unary operator `-`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | fn baz<T: std::ops::Neg<Output = T>>(x: T) {
+   |         +++++++++++++++++++++++++++
+
+error[E0600]: cannot apply unary operator `!` to type `T`
+  --> $DIR/missing_trait_impl.rs:14:13
+   |
+LL |     let y = !x;
+   |             ^^ cannot apply unary operator `!`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | fn baz<T: std::ops::Not<Output = T>>(x: T) {
+   |         +++++++++++++++++++++++++++
+
+error[E0614]: type `T` cannot be dereferenced
+  --> $DIR/missing_trait_impl.rs:15:13
+   |
+LL |     let y = *x;
+   |             ^^
+
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0368, E0369.
+Some errors have detailed explanations: E0368, E0369, E0600, E0614.
 For more information about an error, try `rustc --explain E0368`.