about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/op.rs182
-rw-r--r--src/test/ui/binary-op-on-double-ref.stderr3
-rw-r--r--src/test/ui/codemap_tests/issue-28308.stderr4
-rw-r--r--src/test/ui/error-codes/E0600.stderr4
-rw-r--r--src/test/ui/error-festival.stderr2
-rw-r--r--src/test/ui/feature-gate-negate-unsigned.stderr8
-rw-r--r--src/test/ui/issue-5239-1.stderr2
-rw-r--r--src/test/ui/reachable/expr_unary.stderr4
8 files changed, 131 insertions, 78 deletions
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index de042ae31fb..69b891af663 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -12,8 +12,8 @@
 
 use super::{FnCtxt, Needs};
 use super::method::MethodCallee;
-use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
-use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray};
 use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use errors;
@@ -246,39 +246,76 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Err(()) => {
                 // error types are considered "builtin"
                 if !lhs_ty.references_error() {
-                    if let IsAssign::Yes = is_assign {
-                        struct_span_err!(self.tcx.sess, expr.span, E0368,
-                                         "binary assignment operation `{}=` \
-                                          cannot be applied to type `{}`",
-                                         op.node.as_str(),
-                                         lhs_ty)
-                            .span_label(lhs_expr.span,
-                                        format!("cannot use `{}=` on type `{}`",
-                                        op.node.as_str(), lhs_ty))
-                            .emit();
-                    } else {
-                        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);
-
-                        if let TypeVariants::TyRef(_, rty, _) = lhs_ty.sty {
-                            if {
-                                !self.infcx.type_moves_by_default(self.param_env,
-                                                                  rty,
-                                                                  lhs_expr.span) &&
-                                    self.lookup_op_method(rty,
-                                                          &[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()));
+                    match is_assign{
+                        IsAssign::Yes => {
+                            let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
+                                                "binary assignment operation `{}=` \
+                                                cannot be applied to type `{}`",
+                                                op.node.as_str(),
+                                                lhs_ty);
+                            err.span_label(lhs_expr.span,
+                                    format!("cannot use `{}=` on type `{}`",
+                                    op.node.as_str(), lhs_ty));
+                            let missing_trait = match op.node {
+                                hir::BiAdd    => Some("std::ops::AddAssign"),
+                                hir::BiSub    => Some("std::ops::SubAssign"),
+                                hir::BiMul    => Some("std::ops::MulAssign"),
+                                hir::BiDiv    => Some("std::ops::DivAssign"),
+                                hir::BiRem    => Some("std::ops::RemAssign"),
+                                hir::BiBitAnd => Some("std::ops::BitAndAssign"),
+                                hir::BiBitXor => Some("std::ops::BitXorAssign"),
+                                hir::BiBitOr  => Some("std::ops::BitOrAssign"),
+                                hir::BiShl    => Some("std::ops::ShlAssign"),
+                                hir::BiShr    => Some("std::ops::ShrAssign"),
+                                _             => None
+                            };
+                            let mut suggested_deref = false;
+                            if let 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()
+                                } {
+                                    let codemap = self.tcx.sess.codemap();
+                                    match codemap.span_to_snippet(lhs_expr.span) {
+                                        Ok(lstring) =>{
+                                            let msg = &format!(
+                                                "`{}=` can be used on '{}', you can \
+                                                dereference `{2}`: `*{2}`",
+                                                op.node.as_str(), ty_mut.ty, lstring);
+                                            err.help(msg);
+                                            suggested_deref = true;
+                                        },
+                                        _ => {}
+                                    };
+                                }
+                            }
+                            if let Some(missing_trait) = missing_trait {
+                                if missing_trait == "std::ops::AddAssign" &&
+                                    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 {
+                                    if !suggested_deref{
+                                        err.note(
+                                            &format!("an implementation of `{}` might \
+                                                        be missing for `{}`",
+                                                        missing_trait, lhs_ty));
+                                    }
+                                }
                             }
+                            err.emit();
                         }
                         IsAssign::No => {
                             let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
@@ -301,7 +338,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     Some("std::cmp::PartialOrd"),
                                 _             => None
                             };
-                            if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
+                            let mut suggested_deref = false;
+                            if let TyRef(_, ref ty_mut) = lhs_ty.sty {
                                 if {
                                     !self.infcx.type_moves_by_default(self.param_env,
                                                                         ty_mut.ty,
@@ -311,36 +349,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                 Op::Binary(op, is_assign))
                                             .is_ok()
                                 } {
+                                    let codemap = self.tcx.sess.codemap();
+                                    match codemap.span_to_snippet(lhs_expr.span) {
+                                        Ok(lstring) =>{
+                                            let msg = &format!(
+                                                "`{}` can be used on '{}', you can \
+                                                dereference `{2}`: `*{2}`",
+                                                op.node.as_str(), ty_mut.ty, lstring);
+                                            err.help(msg);
+                                            suggested_deref = true;
+                                        },
+                                        _ =>{}
+                                    }
+                                }
+                            }
+                            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!(
-                                                "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()));
+                                        &format!("`{}` might need a bound for `{}`",
+                                                    lhs_ty, missing_trait));
+                                } else {
+                                    if !suggested_deref{
+                                        err.note(
+                                            &format!("an implementation of `{}` might \
+                                                        be missing for `{}`",
+                                                        missing_trait, lhs_ty));
+                                    }
                                 }
                             }
-                            (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
             }
@@ -420,13 +466,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
                                      "cannot apply unary operator `{}` to type `{}`",
                                      op.as_str(), actual);
+                    err.span_label(ex.span, format!("cannot apply unary \
+                                                    operator `{}`", op.as_str()));
                     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 `{}`",
+                    match actual.sty{
+                        TyUint(_) => {
+                            if op == hir::UnNeg{
+                                err.note(&format!("unsigned values cannot be negated"));
+                            }
+                        },
+                        TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {},
+                        TyRef(_, ref lty) if lty.ty.sty == TyStr => {},
+                        _ => {
+                            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/binary-op-on-double-ref.stderr b/src/test/ui/binary-op-on-double-ref.stderr
index 07aa3bfe40d..020d74bee52 100644
--- a/src/test/ui/binary-op-on-double-ref.stderr
+++ b/src/test/ui/binary-op-on-double-ref.stderr
@@ -4,8 +4,7 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}`
 LL |         x % 2 == 0
    |         ^^^^^
    |
-   = note: this is a reference to a type that `%` can be applied to; you need to dereference this variable once for this operation to work
-   = note: an implementation of `std::ops::Rem` might be missing for `&&{integer}`
+   = help: `%` can be used on '&{integer}', you can dereference `x`: `*x`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr
index b5c2376239d..15c159a3b15 100644
--- a/src/test/ui/codemap_tests/issue-28308.stderr
+++ b/src/test/ui/codemap_tests/issue-28308.stderr
@@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
   --> $DIR/issue-28308.rs:12:5
    |
 LL |     assert!("foo");
-   |     ^^^^^^^^^^^^^^^
-   |
-   = note: an implementation of `std::ops::Not` might be missing for `&'static str`
+   |     ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0600.stderr b/src/test/ui/error-codes/E0600.stderr
index bd79ea79c8b..c29ec4fe6ae 100644
--- a/src/test/ui/error-codes/E0600.stderr
+++ b/src/test/ui/error-codes/E0600.stderr
@@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
   --> $DIR/E0600.rs:12:5
    |
 LL |     !"a"; //~ ERROR E0600
-   |     ^^^^
-   |
-   = note: an implementation of `std::ops::Not` might be missing for `&'static str`
+   |     ^^^^ cannot apply unary operator `!`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 6165806aac9..69f11b4b7c0 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -30,7 +30,7 @@ error[E0600]: cannot apply unary operator `!` to type `Question`
   --> $DIR/error-festival.rs:29:5
    |
 LL |     !Question::Yes;
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ cannot apply unary operator `!`
    |
    = note: an implementation of `std::ops::Not` might be missing for `Question`
 
diff --git a/src/test/ui/feature-gate-negate-unsigned.stderr b/src/test/ui/feature-gate-negate-unsigned.stderr
index 8831e874a20..85e9b56e4af 100644
--- a/src/test/ui/feature-gate-negate-unsigned.stderr
+++ b/src/test/ui/feature-gate-negate-unsigned.stderr
@@ -2,17 +2,17 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
   --> $DIR/feature-gate-negate-unsigned.rs:20:23
    |
 LL |     let _max: usize = -1;
-   |                       ^^
+   |                       ^^ cannot apply unary operator `-`
    |
-   = note: an implementation of `std::ops::Neg` might be missing for `usize`
+   = note: unsigned values cannot be negated
 
 error[E0600]: cannot apply unary operator `-` to type `u8`
   --> $DIR/feature-gate-negate-unsigned.rs:24:14
    |
 LL |     let _y = -x;
-   |              ^^
+   |              ^^ cannot apply unary operator `-`
    |
-   = note: an implementation of `std::ops::Neg` might be missing for `u8`
+   = note: unsigned values cannot be negated
 
 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 adef9848ba7..7ae01fb7d60 100644
--- a/src/test/ui/issue-5239-1.stderr
+++ b/src/test/ui/issue-5239-1.stderr
@@ -6,7 +6,7 @@ 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`
+   = help: `+=` can be used on 'isize', you can dereference `x`: `*x`
 
 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 7ba21efcd51..b889c884fcb 100644
--- a/src/test/ui/reachable/expr_unary.stderr
+++ b/src/test/ui/reachable/expr_unary.stderr
@@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `!`
   --> $DIR/expr_unary.rs:17:16
    |
 LL |     let x: ! = ! { return; }; //~ ERROR unreachable
-   |                ^^^^^^^^^^^^^
-   |
-   = note: an implementation of `std::ops::Not` might be missing for `!`
+   |                ^^^^^^^^^^^^^ cannot apply unary operator `!`
 
 error: unreachable expression
   --> $DIR/expr_unary.rs:17:16