12
12
13
13
use super :: { FnCtxt , Needs } ;
14
14
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 } ;
17
17
use rustc:: ty:: adjustment:: { Adjustment , Adjust , AllowTwoPhase , AutoBorrow , AutoBorrowMutability } ;
18
18
use rustc:: infer:: type_variable:: TypeVariableOrigin ;
19
19
use errors;
@@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
246
246
Err ( ( ) ) => {
247
247
// error types are considered "builtin"
248
248
if !lhs_ty. references_error ( ) {
249
- let ( mut err , missing_trait ) = match is_assign{
249
+ match is_assign{
250
250
IsAssign :: Yes => {
251
251
let mut err = struct_span_err ! ( self . tcx. sess, expr. span, E0368 ,
252
252
"binary assignment operation `{}=` \
@@ -269,7 +269,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
269
269
hir:: BiShr => Some ( "std::ops::ShrAssign" ) ,
270
270
_ => None
271
271
} ;
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 ( ) ;
273
319
}
274
320
IsAssign :: No => {
275
321
let mut err = struct_span_err ! ( self . tcx. sess, expr. span, E0369 ,
@@ -292,7 +338,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
292
338
Some ( "std::cmp::PartialOrd" ) ,
293
339
_ => None
294
340
} ;
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 {
296
343
if {
297
344
!self . infcx . type_moves_by_default ( self . param_env ,
298
345
ty_mut. ty ,
@@ -302,36 +349,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
302
349
Op :: Binary ( op, is_assign) )
303
350
. is_ok ( )
304
351
} {
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
305
375
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
+ }
311
385
}
312
386
}
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 ( ) ;
332
388
}
333
389
}
334
- err. emit ( ) ;
335
390
}
336
391
self . tcx . types . err
337
392
}
@@ -411,13 +466,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
411
466
let mut err = struct_span_err ! ( self . tcx. sess, ex. span, E0600 ,
412
467
"cannot apply unary operator `{}` to type `{}`" ,
413
468
op. as_str( ) , actual) ;
469
+ err. span_label ( ex. span , format ! ( "cannot apply unary \
470
+ operator `{}`", op. as_str( ) ) ) ;
414
471
let missing_trait = match op {
415
472
hir:: UnNeg => "std::ops::Neg" ,
416
473
hir:: UnNot => "std::ops::Not" ,
417
474
hir:: UnDeref => "std::ops::UnDerf"
418
475
} ;
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 `{}`",
420
487
missing_trait, operand_ty) ) ;
488
+ }
489
+ }
421
490
err. emit ( ) ;
422
491
}
423
492
self . tcx . types . err
0 commit comments