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,39 +246,76 @@ 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
- 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
+ }
281
317
}
318
+ err. emit ( ) ;
282
319
}
283
320
IsAssign :: No => {
284
321
let mut err = struct_span_err ! ( self . tcx. sess, expr. span, E0369 ,
@@ -301,7 +338,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
301
338
Some ( "std::cmp::PartialOrd" ) ,
302
339
_ => None
303
340
} ;
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 {
305
343
if {
306
344
!self . infcx . type_moves_by_default ( self . param_env ,
307
345
ty_mut. ty ,
@@ -311,36 +349,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
311
349
Op :: Binary ( op, is_assign) )
312
350
. is_ok ( )
313
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
314
375
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
+ }
320
385
}
321
386
}
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 ( ) ;
341
388
}
342
389
}
343
- err. emit ( ) ;
344
390
}
345
391
self . tcx . types . err
346
392
}
@@ -420,13 +466,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
420
466
let mut err = struct_span_err ! ( self . tcx. sess, ex. span, E0600 ,
421
467
"cannot apply unary operator `{}` to type `{}`" ,
422
468
op. as_str( ) , actual) ;
469
+ err. span_label ( ex. span , format ! ( "cannot apply unary \
470
+ operator `{}`", op. as_str( ) ) ) ;
423
471
let missing_trait = match op {
424
472
hir:: UnNeg => "std::ops::Neg" ,
425
473
hir:: UnNot => "std::ops::Not" ,
426
474
hir:: UnDeref => "std::ops::UnDerf"
427
475
} ;
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 `{}`",
429
487
missing_trait, operand_ty) ) ;
488
+ }
489
+ }
430
490
err. emit ( ) ;
431
491
}
432
492
self . tcx . types . err
0 commit comments