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::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,40 +246,77 @@ 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,
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)
.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 {
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,
rty,
ty_mut.ty,
lhs_expr.span) &&
self.lookup_op_method(rty,
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()));
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,
"binary operation `{}` cannot be applied to type `{}`",
@ -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,17 +349,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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()));
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;
},
_ =>{}
}
}
(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,
@ -335,13 +376,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
&format!("`{}` might need a bound for `{}`",
lhs_ty, missing_trait));
} else {
if !suggested_deref{
err.note(
&format!("an implementation of `{}` might be missing for `{}`",
&format!("an implementation of `{}` might \
be missing for `{}`",
missing_trait, lhs_ty));
}
}
}
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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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`

View file

@ -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

View file

@ -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

View file

@ -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