From 2f6945c77664eb0575de6f016f24c9f6ced1923f Mon Sep 17 00:00:00 2001 From: Roman Stoliar Date: Sun, 22 Apr 2018 20:35:21 +0300 Subject: [PATCH] added missing implementation hint --- src/librustc_typeck/check/op.rs | 104 ++++++++++++------ src/test/ui/codemap_tests/issue-28308.stderr | 2 + src/test/ui/error-codes/E0067.stderr | 2 + src/test/ui/error-codes/E0600.stderr | 2 + src/test/ui/error-festival.stderr | 4 + .../ui/feature-gate-negate-unsigned.stderr | 4 + src/test/ui/issue-5239-1.stderr | 2 + src/test/ui/reachable/expr_unary.stderr | 2 + 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