unary op filter, dereference hint

This commit is contained in:
Roman Stoliar 2018-05-08 22:20:41 +03:00
parent 2f6945c776
commit 56fbc63456
8 changed files with 132 additions and 79 deletions

View file

@ -12,8 +12,8 @@
use super::{FnCtxt, Needs}; use super::{FnCtxt, Needs};
use super::method::MethodCallee; use super::method::MethodCallee;
use rustc::ty::{self, Ty, TypeFoldable, TypeVariants}; use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt}; use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray};
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::infer::type_variable::TypeVariableOrigin; use rustc::infer::type_variable::TypeVariableOrigin;
use errors; use errors;
@ -246,40 +246,77 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Err(()) => { Err(()) => {
// error types are considered "builtin" // error types are considered "builtin"
if !lhs_ty.references_error() { if !lhs_ty.references_error() {
if let IsAssign::Yes = is_assign { match is_assign{
struct_span_err!(self.tcx.sess, expr.span, E0368, IsAssign::Yes => {
let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
"binary assignment operation `{}=` \ "binary assignment operation `{}=` \
cannot be applied to type `{}`", cannot be applied to type `{}`",
op.node.as_str(), 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); lhs_ty);
err.span_label(lhs_expr.span,
if let TypeVariants::TyRef(_, rty, _) = lhs_ty.sty { 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 { if {
!self.infcx.type_moves_by_default(self.param_env, !self.infcx.type_moves_by_default(self.param_env,
rty, ty_mut.ty,
lhs_expr.span) && lhs_expr.span) &&
self.lookup_op_method(rty, self.lookup_op_method(ty_mut.ty,
&[rhs_ty], &[rhs_ty],
Op::Binary(op, is_assign)) Op::Binary(op, is_assign))
.is_ok() .is_ok()
} { } {
err.note( let codemap = self.tcx.sess.codemap();
&format!( match codemap.span_to_snippet(lhs_expr.span) {
"this is a reference to a type that `{}` can be applied \ Ok(lstring) =>{
to; you need to dereference this variable once for this \ let msg = &format!(
operation to work", "`{}=` can be used on '{}', you can \
op.node.as_str())); 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 => { IsAssign::No => {
let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369, let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
"binary operation `{}` cannot be applied to type `{}`", "binary operation `{}` cannot be applied to type `{}`",
@ -301,7 +338,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Some("std::cmp::PartialOrd"), Some("std::cmp::PartialOrd"),
_ => None _ => 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 { if {
!self.infcx.type_moves_by_default(self.param_env, !self.infcx.type_moves_by_default(self.param_env,
ty_mut.ty, ty_mut.ty,
@ -311,17 +349,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Op::Binary(op, is_assign)) Op::Binary(op, is_assign))
.is_ok() .is_ok()
} { } {
err.note( let codemap = self.tcx.sess.codemap();
&format!( match codemap.span_to_snippet(lhs_expr.span) {
"this is a reference to a type that `{}` can be \ Ok(lstring) =>{
applied to; you need to dereference this variable \ let msg = &format!(
once for this operation to work", "`{}` can be used on '{}', you can \
op.node.as_str())); dereference `{2}`: `*{2}`",
op.node.as_str(), ty_mut.ty, lstring);
err.help(msg);
suggested_deref = true;
},
_ =>{}
} }
} }
(err, missing_trait)
} }
};
if let Some(missing_trait) = missing_trait { if let Some(missing_trait) = missing_trait {
if missing_trait == "std::ops::Add" && if missing_trait == "std::ops::Add" &&
self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
@ -335,13 +376,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
&format!("`{}` might need a bound for `{}`", &format!("`{}` might need a bound for `{}`",
lhs_ty, missing_trait)); lhs_ty, missing_trait));
} else { } else {
if !suggested_deref{
err.note( err.note(
&format!("an implementation of `{}` might be missing for `{}`", &format!("an implementation of `{}` might \
be missing for `{}`",
missing_trait, lhs_ty)); missing_trait, lhs_ty));
} }
} }
}
err.emit(); err.emit();
} }
}
}
self.tcx.types.err 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, let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
"cannot apply unary operator `{}` to type `{}`", "cannot apply unary operator `{}` to type `{}`",
op.as_str(), actual); op.as_str(), actual);
err.span_label(ex.span, format!("cannot apply unary \
operator `{}`", op.as_str()));
let missing_trait = match op { let missing_trait = match op {
hir::UnNeg => "std::ops::Neg", hir::UnNeg => "std::ops::Neg",
hir::UnNot => "std::ops::Not", hir::UnNot => "std::ops::Not",
hir::UnDeref => "std::ops::UnDerf" 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)); missing_trait, operand_ty));
}
}
err.emit(); err.emit();
} }
self.tcx.types.err self.tcx.types.err

View file

@ -4,8 +4,7 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}`
LL | x % 2 == 0 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 = help: `%` can be used on '&{integer}', you can dereference `x`: `*x`
= note: an implementation of `std::ops::Rem` might be missing for `&&{integer}`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
--> $DIR/issue-28308.rs:12:5 --> $DIR/issue-28308.rs:12:5
| |
LL | assert!("foo"); LL | assert!("foo");
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
|
= note: an implementation of `std::ops::Not` might be missing for `&'static str`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
--> $DIR/E0600.rs:12:5 --> $DIR/E0600.rs:12:5
| |
LL | !"a"; //~ ERROR E0600 LL | !"a"; //~ ERROR E0600
| ^^^^ | ^^^^ cannot apply unary operator `!`
|
= note: an implementation of `std::ops::Not` might be missing for `&'static str`
error: aborting due to previous error error: aborting due to previous error

View file

@ -30,7 +30,7 @@ error[E0600]: cannot apply unary operator `!` to type `Question`
--> $DIR/error-festival.rs:29:5 --> $DIR/error-festival.rs:29:5
| |
LL | !Question::Yes; LL | !Question::Yes;
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ cannot apply unary operator `!`
| |
= note: an implementation of `std::ops::Not` might be missing for `Question` = note: an implementation of `std::ops::Not` might be missing for `Question`

View file

@ -2,17 +2,17 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
--> $DIR/feature-gate-negate-unsigned.rs:20:23 --> $DIR/feature-gate-negate-unsigned.rs:20:23
| |
LL | let _max: usize = -1; 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` error[E0600]: cannot apply unary operator `-` to type `u8`
--> $DIR/feature-gate-negate-unsigned.rs:24:14 --> $DIR/feature-gate-negate-unsigned.rs:24:14
| |
LL | let _y = -x; 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 error: aborting due to 2 previous errors

View file

@ -6,7 +6,7 @@ LL | let x = |ref x: isize| { x += 1; };
| | | |
| cannot use `+=` on type `&isize` | 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 error: aborting due to previous error

View file

@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `!`
--> $DIR/expr_unary.rs:17:16 --> $DIR/expr_unary.rs:17:16
| |
LL | let x: ! = ! { return; }; //~ ERROR unreachable LL | let x: ! = ! { return; }; //~ ERROR unreachable
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^ cannot apply unary operator `!`
|
= note: an implementation of `std::ops::Not` might be missing for `!`
error: unreachable expression error: unreachable expression
--> $DIR/expr_unary.rs:17:16 --> $DIR/expr_unary.rs:17:16