1212
1313use super :: { FnCtxt , Needs } ;
1414use 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 } ;
1717use rustc:: ty:: adjustment:: { Adjustment , Adjust , AllowTwoPhase , AutoBorrow , AutoBorrowMutability } ;
1818use rustc:: infer:: type_variable:: TypeVariableOrigin ;
1919use 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
0 commit comments