about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoman Stoliar <rizakrko@rambler.ru>2018-04-22 20:35:21 +0300
committerRoman Stoliar <rizakrko@rambler.ru>2018-05-11 15:12:30 +0300
commit2f6945c77664eb0575de6f016f24c9f6ced1923f (patch)
treebec29631fc46bd5771ad5c306a99d1d7ec5ec379
parent4e5a155a93d21d17fc62fff3d61dc33b90880820 (diff)
downloadrust-2f6945c77664eb0575de6f016f24c9f6ced1923f.tar.gz
rust-2f6945c77664eb0575de6f016f24c9f6ced1923f.zip
added missing implementation hint
-rw-r--r--src/librustc_typeck/check/op.rs104
-rw-r--r--src/test/ui/codemap_tests/issue-28308.stderr2
-rw-r--r--src/test/ui/error-codes/E0067.stderr2
-rw-r--r--src/test/ui/error-codes/E0600.stderr2
-rw-r--r--src/test/ui/error-festival.stderr4
-rw-r--r--src/test/ui/feature-gate-negate-unsigned.stderr4
-rw-r--r--src/test/ui/issue-5239-1.stderr2
-rw-r--r--src/test/ui/reachable/expr_unary.stderr2
8 files changed, 86 insertions, 36 deletions
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 9e8e00594e6..de042ae31fb 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -280,43 +280,67 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     op.node.as_str()));
                             }
                         }
-
-                        let missing_trait = match op.node {
-                            hir::BiAdd    => Some("std::ops::Add"),
-                            hir::BiSub    => Some("std::ops::Sub"),
-                            hir::BiMul    => Some("std::ops::Mul"),
-                            hir::BiDiv    => Some("std::ops::Div"),
-                            hir::BiRem    => Some("std::ops::Rem"),
-                            hir::BiBitAnd => Some("std::ops::BitAnd"),
-                            hir::BiBitOr  => Some("std::ops::BitOr"),
-                            hir::BiShl    => Some("std::ops::Shl"),
-                            hir::BiShr    => Some("std::ops::Shr"),
-                            hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
-                            hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
-                                Some("std::cmp::PartialOrd"),
-                            _             => None
-                        };
-
-                        if let Some(missing_trait) = missing_trait {
-                            if missing_trait == "std::ops::Add" &&
-                                self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
-                                                        rhs_ty, &mut err) {
-                                // This has nothing here because it means we did string
-                                // concatenation (e.g. "Hello " + "World!"). This means
-                                // we don't want the note in the else clause to be emitted
-                            } else if let ty::TyParam(_) = lhs_ty.sty {
-                                // FIXME: point to span of param
-                                err.note(
-                                    &format!("`{}` might need a bound for `{}`",
-                                             lhs_ty, missing_trait));
-                            } else {
-                                err.note(
-                                    &format!("an implementation of `{}` might be missing for `{}`",
-                                             missing_trait, lhs_ty));
+                        IsAssign::No => {
+                            let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
+                                            "binary operation `{}` cannot be applied to type `{}`",
+                                            op.node.as_str(),
+                                            lhs_ty);
+                            let missing_trait = match op.node {
+                                hir::BiAdd    => Some("std::ops::Add"),
+                                hir::BiSub    => Some("std::ops::Sub"),
+                                hir::BiMul    => Some("std::ops::Mul"),
+                                hir::BiDiv    => Some("std::ops::Div"),
+                                hir::BiRem    => Some("std::ops::Rem"),
+                                hir::BiBitAnd => Some("std::ops::BitAnd"),
+                                hir::BiBitXor => Some("std::ops::BitXor"),
+                                hir::BiBitOr  => Some("std::ops::BitOr"),
+                                hir::BiShl    => Some("std::ops::Shl"),
+                                hir::BiShr    => Some("std::ops::Shr"),
+                                hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+                                hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+                                    Some("std::cmp::PartialOrd"),
+                                _             => None
+                            };
+                            if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
+                                if {
+                                    !self.infcx.type_moves_by_default(self.param_env,
+                                                                        ty_mut.ty,
+                                                                        lhs_expr.span) &&
+                                        self.lookup_op_method(ty_mut.ty,
+                                                                &[rhs_ty],
+                                                                Op::Binary(op, is_assign))
+                                            .is_ok()
+                                } {
+                                    err.note(
+                                        &format!(
+                                                "this is a reference to a type that `{}` can be \
+                                                applied to; you need to dereference this variable \
+                                                once for this operation to work",
+                                        op.node.as_str()));
+                                }
                             }
+                            (err, missing_trait)
+                        }
+                    };
+                    if let Some(missing_trait) = missing_trait {
+                        if missing_trait == "std::ops::Add" &&
+                            self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+                                                    rhs_ty, &mut err) {
+                            // This has nothing here because it means we did string
+                            // concatenation (e.g. "Hello " + "World!"). This means
+                            // we don't want the note in the else clause to be emitted
+                        } else if let ty::TyParam(_) = lhs_ty.sty {
+                            // FIXME: point to span of param
+                            err.note(
+                                &format!("`{}` might need a bound for `{}`",
+                                            lhs_ty, missing_trait));
+                        } else {
+                            err.note(
+                                &format!("an implementation of `{}` might be missing for `{}`",
+                                            missing_trait, lhs_ty));
                         }
-                        err.emit();
                     }
+                    err.emit();
                 }
                 self.tcx.types.err
             }
@@ -393,9 +417,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Err(()) => {
                 let actual = self.resolve_type_vars_if_possible(&operand_ty);
                 if !actual.references_error() {
-                    struct_span_err!(self.tcx.sess, ex.span, E0600,
+                    let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
                                      "cannot apply unary operator `{}` to type `{}`",
-                                     op.as_str(), actual).emit();
+                                     op.as_str(), actual);
+                    let missing_trait = match op {
+                        hir::UnNeg => "std::ops::Neg",
+                        hir::UnNot => "std::ops::Not",
+                        hir::UnDeref => "std::ops::UnDerf"
+                    };
+                    err.note(&format!("an implementation of `{}` might be missing for `{}`",
+                                             missing_trait, operand_ty));
+                    err.emit();
                 }
                 self.tcx.types.err
             }
diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr
index 2c8a33d95c0..b5c2376239d 100644
--- a/src/test/ui/codemap_tests/issue-28308.stderr
+++ b/src/test/ui/codemap_tests/issue-28308.stderr
@@ -3,6 +3,8 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
    |
 LL |     assert!("foo");
    |     ^^^^^^^^^^^^^^^
+   |
+   = note: an implementation of `std::ops::Not` might be missing for `&'static str`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr
index 76f06c7c463..43e1ca4096c 100644
--- a/src/test/ui/error-codes/E0067.stderr
+++ b/src/test/ui/error-codes/E0067.stderr
@@ -5,6 +5,8 @@ LL |     LinkedList::new() += 1; //~ ERROR E0368
    |     -----------------^^^^^
    |     |
    |     cannot use `+=` on type `std::collections::LinkedList<_>`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>`
 
 error[E0067]: invalid left-hand side expression
   --> $DIR/E0067.rs:14:5
diff --git a/src/test/ui/error-codes/E0600.stderr b/src/test/ui/error-codes/E0600.stderr
index 500feb39f5e..bd79ea79c8b 100644
--- a/src/test/ui/error-codes/E0600.stderr
+++ b/src/test/ui/error-codes/E0600.stderr
@@ -3,6 +3,8 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
    |
 LL |     !"a"; //~ ERROR E0600
    |     ^^^^
+   |
+   = note: an implementation of `std::ops::Not` might be missing for `&'static str`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 345691352b4..6165806aac9 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -17,6 +17,8 @@ LL |     x += 2;
    |     -^^^^^
    |     |
    |     cannot use `+=` on type `&str`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `&str`
 
 error[E0599]: no method named `z` found for type `&str` in the current scope
   --> $DIR/error-festival.rs:26:7
@@ -29,6 +31,8 @@ error[E0600]: cannot apply unary operator `!` to type `Question`
    |
 LL |     !Question::Yes;
    |     ^^^^^^^^^^^^^^
+   |
+   = note: an implementation of `std::ops::Not` might be missing for `Question`
 
 error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/error-festival.rs:35:5
diff --git a/src/test/ui/feature-gate-negate-unsigned.stderr b/src/test/ui/feature-gate-negate-unsigned.stderr
index 1025b56f55b..8831e874a20 100644
--- a/src/test/ui/feature-gate-negate-unsigned.stderr
+++ b/src/test/ui/feature-gate-negate-unsigned.stderr
@@ -3,12 +3,16 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
    |
 LL |     let _max: usize = -1;
    |                       ^^
+   |
+   = note: an implementation of `std::ops::Neg` might be missing for `usize`
 
 error[E0600]: cannot apply unary operator `-` to type `u8`
   --> $DIR/feature-gate-negate-unsigned.rs:24:14
    |
 LL |     let _y = -x;
    |              ^^
+   |
+   = note: an implementation of `std::ops::Neg` might be missing for `u8`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issue-5239-1.stderr b/src/test/ui/issue-5239-1.stderr
index 2f9204e72d3..adef9848ba7 100644
--- a/src/test/ui/issue-5239-1.stderr
+++ b/src/test/ui/issue-5239-1.stderr
@@ -5,6 +5,8 @@ LL |     let x = |ref x: isize| { x += 1; };
    |                              -^^^^^
    |                              |
    |                              cannot use `+=` on type `&isize`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `&isize`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr
index 165eccd4239..7ba21efcd51 100644
--- a/src/test/ui/reachable/expr_unary.stderr
+++ b/src/test/ui/reachable/expr_unary.stderr
@@ -3,6 +3,8 @@ error[E0600]: cannot apply unary operator `!` to type `!`
    |
 LL |     let x: ! = ! { return; }; //~ ERROR unreachable
    |                ^^^^^^^^^^^^^
+   |
+   = note: an implementation of `std::ops::Not` might be missing for `!`
 
 error: unreachable expression
   --> $DIR/expr_unary.rs:17:16