Skip to content

Commit ecedf44

Browse files
committed
unary op filter, dereference hint
1 parent 265bc31 commit ecedf44

File tree

8 files changed

+110
-48
lines changed

8 files changed

+110
-48
lines changed

src/librustc_typeck/check/op.rs

Lines changed: 100 additions & 31 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,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
246246
Err(()) => {
247247
// error types are considered "builtin"
248248
if !lhs_ty.references_error() {
249-
let (mut err, missing_trait) = match is_assign{
249+
match is_assign{
250250
IsAssign::Yes => {
251251
let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
252252
"binary assignment operation `{}=` \
@@ -269,7 +269,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
269269
hir::BiShr => Some("std::ops::ShrAssign"),
270270
_ => None
271271
};
272-
(err, missing_trait)
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+
}
317+
}
318+
err.emit();
273319
}
274320
IsAssign::No => {
275321
let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
@@ -292,7 +338,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
292338
Some("std::cmp::PartialOrd"),
293339
_ => None
294340
};
295-
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 {
296343
if {
297344
!self.infcx.type_moves_by_default(self.param_env,
298345
ty_mut.ty,
@@ -302,36 +349,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
302349
Op::Binary(op, is_assign))
303350
.is_ok()
304351
} {
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
305375
err.note(
306-
&format!(
307-
"this is a reference to a type that `{}` can be \
308-
applied to; you need to dereference this variable \
309-
once for this operation to work",
310-
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+
}
311385
}
312386
}
313-
(err, missing_trait)
314-
}
315-
};
316-
if let Some(missing_trait) = missing_trait {
317-
if missing_trait == "std::ops::Add" &&
318-
self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
319-
rhs_ty, &mut err) {
320-
// This has nothing here because it means we did string
321-
// concatenation (e.g. "Hello " + "World!"). This means
322-
// we don't want the note in the else clause to be emitted
323-
} else if let ty::TyParam(_) = lhs_ty.sty {
324-
// FIXME: point to span of param
325-
err.note(
326-
&format!("`{}` might need a bound for `{}`",
327-
lhs_ty, missing_trait));
328-
} else {
329-
err.note(
330-
&format!("an implementation of `{}` might be missing for `{}`",
331-
missing_trait, lhs_ty));
387+
err.emit();
332388
}
333389
}
334-
err.emit();
335390
}
336391
self.tcx.types.err
337392
}
@@ -411,13 +466,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
411466
let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
412467
"cannot apply unary operator `{}` to type `{}`",
413468
op.as_str(), actual);
469+
err.span_label(ex.span, format!("cannot apply unary \
470+
operator `{}`", op.as_str()));
414471
let missing_trait = match op {
415472
hir::UnNeg => "std::ops::Neg",
416473
hir::UnNot => "std::ops::Not",
417474
hir::UnDeref => "std::ops::UnDerf"
418475
};
419-
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 `{}`",
420487
missing_trait, operand_ty));
488+
}
489+
}
421490
err.emit();
422491
}
423492
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)