Skip to content

Commit 56fbc63

Browse files
committed
unary op filter, dereference hint
1 parent 2f6945c commit 56fbc63

File tree

8 files changed

+131
-78
lines changed

8 files changed

+131
-78
lines changed

src/librustc_typeck/check/op.rs

Lines changed: 121 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
1313
use super::{FnCtxt, Needs};
1414
use super::method::MethodCallee;
15-
use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
16-
use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
15+
use rustc::ty::{self, Ty, TypeFoldable};
16+
use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray};
1717
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
1818
use rustc::infer::type_variable::TypeVariableOrigin;
1919
use errors;
@@ -246,39 +246,76 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
246246
Err(()) => {
247247
// error types are considered "builtin"
248248
if !lhs_ty.references_error() {
249-
if let IsAssign::Yes = is_assign {
250-
struct_span_err!(self.tcx.sess, expr.span, E0368,
251-
"binary assignment operation `{}=` \
252-
cannot be applied to type `{}`",
253-
op.node.as_str(),
254-
lhs_ty)
255-
.span_label(lhs_expr.span,
256-
format!("cannot use `{}=` on type `{}`",
257-
op.node.as_str(), lhs_ty))
258-
.emit();
259-
} else {
260-
let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
261-
"binary operation `{}` cannot be applied to type `{}`",
262-
op.node.as_str(),
263-
lhs_ty);
264-
265-
if let TypeVariants::TyRef(_, rty, _) = lhs_ty.sty {
266-
if {
267-
!self.infcx.type_moves_by_default(self.param_env,
268-
rty,
269-
lhs_expr.span) &&
270-
self.lookup_op_method(rty,
271-
&[rhs_ty],
272-
Op::Binary(op, is_assign))
273-
.is_ok()
274-
} {
275-
err.note(
276-
&format!(
277-
"this is a reference to a type that `{}` can be applied \
278-
to; you need to dereference this variable once for this \
279-
operation to work",
280-
op.node.as_str()));
249+
match is_assign{
250+
IsAssign::Yes => {
251+
let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
252+
"binary assignment operation `{}=` \
253+
cannot be applied to type `{}`",
254+
op.node.as_str(),
255+
lhs_ty);
256+
err.span_label(lhs_expr.span,
257+
format!("cannot use `{}=` on type `{}`",
258+
op.node.as_str(), lhs_ty));
259+
let missing_trait = match op.node {
260+
hir::BiAdd => Some("std::ops::AddAssign"),
261+
hir::BiSub => Some("std::ops::SubAssign"),
262+
hir::BiMul => Some("std::ops::MulAssign"),
263+
hir::BiDiv => Some("std::ops::DivAssign"),
264+
hir::BiRem => Some("std::ops::RemAssign"),
265+
hir::BiBitAnd => Some("std::ops::BitAndAssign"),
266+
hir::BiBitXor => Some("std::ops::BitXorAssign"),
267+
hir::BiBitOr => Some("std::ops::BitOrAssign"),
268+
hir::BiShl => Some("std::ops::ShlAssign"),
269+
hir::BiShr => Some("std::ops::ShrAssign"),
270+
_ => None
271+
};
272+
let mut suggested_deref = false;
273+
if let TyRef(_, ref ty_mut) = lhs_ty.sty {
274+
if {
275+
!self.infcx.type_moves_by_default(self.param_env,
276+
ty_mut.ty,
277+
lhs_expr.span) &&
278+
self.lookup_op_method(ty_mut.ty,
279+
&[rhs_ty],
280+
Op::Binary(op, is_assign))
281+
.is_ok()
282+
} {
283+
let codemap = self.tcx.sess.codemap();
284+
match codemap.span_to_snippet(lhs_expr.span) {
285+
Ok(lstring) =>{
286+
let msg = &format!(
287+
"`{}=` can be used on '{}', you can \
288+
dereference `{2}`: `*{2}`",
289+
op.node.as_str(), ty_mut.ty, lstring);
290+
err.help(msg);
291+
suggested_deref = true;
292+
},
293+
_ => {}
294+
};
295+
}
296+
}
297+
if let Some(missing_trait) = missing_trait {
298+
if missing_trait == "std::ops::AddAssign" &&
299+
self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
300+
rhs_ty, &mut err) {
301+
// This has nothing here because it means we did string
302+
// concatenation (e.g. "Hello " + "World!"). This means
303+
// we don't want the note in the else clause to be emitted
304+
} else if let ty::TyParam(_) = lhs_ty.sty {
305+
// FIXME: point to span of param
306+
err.note(
307+
&format!("`{}` might need a bound for `{}`",
308+
lhs_ty, missing_trait));
309+
} else {
310+
if !suggested_deref{
311+
err.note(
312+
&format!("an implementation of `{}` might \
313+
be missing for `{}`",
314+
missing_trait, lhs_ty));
315+
}
316+
}
281317
}
318+
err.emit();
282319
}
283320
IsAssign::No => {
284321
let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
@@ -301,7 +338,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
301338
Some("std::cmp::PartialOrd"),
302339
_ => None
303340
};
304-
if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
341+
let mut suggested_deref = false;
342+
if let TyRef(_, ref ty_mut) = lhs_ty.sty {
305343
if {
306344
!self.infcx.type_moves_by_default(self.param_env,
307345
ty_mut.ty,
@@ -311,36 +349,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
311349
Op::Binary(op, is_assign))
312350
.is_ok()
313351
} {
352+
let codemap = self.tcx.sess.codemap();
353+
match codemap.span_to_snippet(lhs_expr.span) {
354+
Ok(lstring) =>{
355+
let msg = &format!(
356+
"`{}` can be used on '{}', you can \
357+
dereference `{2}`: `*{2}`",
358+
op.node.as_str(), ty_mut.ty, lstring);
359+
err.help(msg);
360+
suggested_deref = true;
361+
},
362+
_ =>{}
363+
}
364+
}
365+
}
366+
if let Some(missing_trait) = missing_trait {
367+
if missing_trait == "std::ops::Add" &&
368+
self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
369+
rhs_ty, &mut err) {
370+
// This has nothing here because it means we did string
371+
// concatenation (e.g. "Hello " + "World!"). This means
372+
// we don't want the note in the else clause to be emitted
373+
} else if let ty::TyParam(_) = lhs_ty.sty {
374+
// FIXME: point to span of param
314375
err.note(
315-
&format!(
316-
"this is a reference to a type that `{}` can be \
317-
applied to; you need to dereference this variable \
318-
once for this operation to work",
319-
op.node.as_str()));
376+
&format!("`{}` might need a bound for `{}`",
377+
lhs_ty, missing_trait));
378+
} else {
379+
if !suggested_deref{
380+
err.note(
381+
&format!("an implementation of `{}` might \
382+
be missing for `{}`",
383+
missing_trait, lhs_ty));
384+
}
320385
}
321386
}
322-
(err, missing_trait)
323-
}
324-
};
325-
if let Some(missing_trait) = missing_trait {
326-
if missing_trait == "std::ops::Add" &&
327-
self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
328-
rhs_ty, &mut err) {
329-
// This has nothing here because it means we did string
330-
// concatenation (e.g. "Hello " + "World!"). This means
331-
// we don't want the note in the else clause to be emitted
332-
} else if let ty::TyParam(_) = lhs_ty.sty {
333-
// FIXME: point to span of param
334-
err.note(
335-
&format!("`{}` might need a bound for `{}`",
336-
lhs_ty, missing_trait));
337-
} else {
338-
err.note(
339-
&format!("an implementation of `{}` might be missing for `{}`",
340-
missing_trait, lhs_ty));
387+
err.emit();
341388
}
342389
}
343-
err.emit();
344390
}
345391
self.tcx.types.err
346392
}
@@ -420,13 +466,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
420466
let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
421467
"cannot apply unary operator `{}` to type `{}`",
422468
op.as_str(), actual);
469+
err.span_label(ex.span, format!("cannot apply unary \
470+
operator `{}`", op.as_str()));
423471
let missing_trait = match op {
424472
hir::UnNeg => "std::ops::Neg",
425473
hir::UnNot => "std::ops::Not",
426474
hir::UnDeref => "std::ops::UnDerf"
427475
};
428-
err.note(&format!("an implementation of `{}` might be missing for `{}`",
476+
match actual.sty{
477+
TyUint(_) => {
478+
if op == hir::UnNeg{
479+
err.note(&format!("unsigned values cannot be negated"));
480+
}
481+
},
482+
TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {},
483+
TyRef(_, ref lty) if lty.ty.sty == TyStr => {},
484+
_ => {
485+
err.note(&format!("an implementation of `{}` might \
486+
be missing for `{}`",
429487
missing_trait, operand_ty));
488+
}
489+
}
430490
err.emit();
431491
}
432492
self.tcx.types.err

src/test/ui/binary-op-on-double-ref.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}`
44
LL | x % 2 == 0
55
| ^^^^^
66
|
7-
= 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
8-
= note: an implementation of `std::ops::Rem` might be missing for `&&{integer}`
7+
= help: `%` can be used on '&{integer}', you can dereference `x`: `*x`
98

109
error: aborting due to previous error
1110

src/test/ui/codemap_tests/issue-28308.stderr

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
22
--> $DIR/issue-28308.rs:12:5
33
|
44
LL | assert!("foo");
5-
| ^^^^^^^^^^^^^^^
6-
|
7-
= note: an implementation of `std::ops::Not` might be missing for `&'static str`
5+
| ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
86

97
error: aborting due to previous error
108

src/test/ui/error-codes/E0600.stderr

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
22
--> $DIR/E0600.rs:12:5
33
|
44
LL | !"a"; //~ ERROR E0600
5-
| ^^^^
6-
|
7-
= note: an implementation of `std::ops::Not` might be missing for `&'static str`
5+
| ^^^^ cannot apply unary operator `!`
86

97
error: aborting due to previous error
108

src/test/ui/error-festival.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ error[E0600]: cannot apply unary operator `!` to type `Question`
3030
--> $DIR/error-festival.rs:29:5
3131
|
3232
LL | !Question::Yes;
33-
| ^^^^^^^^^^^^^^
33+
| ^^^^^^^^^^^^^^ cannot apply unary operator `!`
3434
|
3535
= note: an implementation of `std::ops::Not` might be missing for `Question`
3636

src/test/ui/feature-gate-negate-unsigned.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
22
--> $DIR/feature-gate-negate-unsigned.rs:20:23
33
|
44
LL | let _max: usize = -1;
5-
| ^^
5+
| ^^ cannot apply unary operator `-`
66
|
7-
= note: an implementation of `std::ops::Neg` might be missing for `usize`
7+
= note: unsigned values cannot be negated
88

99
error[E0600]: cannot apply unary operator `-` to type `u8`
1010
--> $DIR/feature-gate-negate-unsigned.rs:24:14
1111
|
1212
LL | let _y = -x;
13-
| ^^
13+
| ^^ cannot apply unary operator `-`
1414
|
15-
= note: an implementation of `std::ops::Neg` might be missing for `u8`
15+
= note: unsigned values cannot be negated
1616

1717
error: aborting due to 2 previous errors
1818

src/test/ui/issue-5239-1.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | let x = |ref x: isize| { x += 1; };
66
| |
77
| cannot use `+=` on type `&isize`
88
|
9-
= note: an implementation of `std::ops::AddAssign` might be missing for `&isize`
9+
= help: `+=` can be used on 'isize', you can dereference `x`: `*x`
1010

1111
error: aborting due to previous error
1212

src/test/ui/reachable/expr_unary.stderr

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `!`
22
--> $DIR/expr_unary.rs:17:16
33
|
44
LL | let x: ! = ! { return; }; //~ ERROR unreachable
5-
| ^^^^^^^^^^^^^
6-
|
7-
= note: an implementation of `std::ops::Not` might be missing for `!`
5+
| ^^^^^^^^^^^^^ cannot apply unary operator `!`
86

97
error: unreachable expression
108
--> $DIR/expr_unary.rs:17:16

0 commit comments

Comments
 (0)