@@ -449,31 +449,81 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
449449                }  else  { 
450450                    ( None ,  & [ ] [ ..] ,  0 ) 
451451                } ; 
452+                 let  mut  can_suggest_clone = true ; 
452453                if  let  Some ( def_id)  = def_id
453454                    && let  node = self . infcx . tcx . hir_node_by_def_id ( def_id) 
454455                    && let  Some ( fn_sig)  = node. fn_sig ( ) 
455456                    && let  Some ( ident)  = node. ident ( ) 
456457                    && let  Some ( pos)  = args. iter ( ) . position ( |arg| arg. hir_id  == expr. hir_id ) 
457458                    && let  Some ( arg)  = fn_sig. decl . inputs . get ( pos + offset) 
458459                { 
459-                     let  mut  span:  MultiSpan  = arg. span . into ( ) ; 
460-                     span. push_span_label ( 
461-                         arg. span , 
462-                         "this parameter takes ownership of the value" . to_string ( ) , 
463-                     ) ; 
464-                     let  descr = match  node. fn_kind ( )  { 
465-                         Some ( hir:: intravisit:: FnKind :: ItemFn ( ..) )  | None  => "function" , 
466-                         Some ( hir:: intravisit:: FnKind :: Method ( ..) )  => "method" , 
467-                         Some ( hir:: intravisit:: FnKind :: Closure )  => "closure" , 
468-                     } ; 
469-                     span. push_span_label ( ident. span ,  format ! ( "in this {descr}" ) ) ; 
470-                     err. span_note ( 
471-                         span, 
472-                         format ! ( 
473-                             "consider changing this parameter type in {descr} `{ident}` to borrow \  
474-                               instead if owning the value isn't necessary", 
475-                         ) , 
476-                     ) ; 
460+                     let  mut  is_mut = false ; 
461+                     if  let  hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None ,  path) )  = arg. kind 
462+                         && let  Res :: Def ( DefKind :: TyParam ,  param_def_id)  = path. res 
463+                         && self 
464+                             . infcx 
465+                             . tcx 
466+                             . predicates_of ( def_id) 
467+                             . instantiate_identity ( self . infcx . tcx ) 
468+                             . predicates 
469+                             . into_iter ( ) 
470+                             . any ( |pred| { 
471+                                 if  let  ty:: ClauseKind :: Trait ( predicate)  = pred. kind ( ) . skip_binder ( ) 
472+                                     && [ 
473+                                         self . infcx . tcx . get_diagnostic_item ( sym:: AsRef ) , 
474+                                         self . infcx . tcx . get_diagnostic_item ( sym:: AsMut ) , 
475+                                         self . infcx . tcx . get_diagnostic_item ( sym:: Borrow ) , 
476+                                         self . infcx . tcx . get_diagnostic_item ( sym:: BorrowMut ) , 
477+                                     ] 
478+                                     . contains ( & Some ( predicate. def_id ( ) ) ) 
479+                                     && let  ty:: Param ( param)  = predicate. self_ty ( ) . kind ( ) 
480+                                     && let  generics = self . infcx . tcx . generics_of ( def_id) 
481+                                     && let  param = generics. type_param ( * param,  self . infcx . tcx ) 
482+                                     && param. def_id  == param_def_id
483+                                 { 
484+                                     if  [ 
485+                                         self . infcx . tcx . get_diagnostic_item ( sym:: AsMut ) , 
486+                                         self . infcx . tcx . get_diagnostic_item ( sym:: BorrowMut ) , 
487+                                     ] 
488+                                     . contains ( & Some ( predicate. def_id ( ) ) ) 
489+                                     { 
490+                                         is_mut = true ; 
491+                                     } 
492+                                     true 
493+                                 }  else  { 
494+                                     false 
495+                                 } 
496+                             } ) 
497+                     { 
498+                         // The type of the argument corresponding to the expression that got moved 
499+                         // is a type parameter `T`, which is has a `T: AsRef` obligation. 
500+                         err. span_suggestion_verbose ( 
501+                             expr. span . shrink_to_lo ( ) , 
502+                             "borrow the value to avoid moving it" , 
503+                             format ! ( "&{}" ,  if  is_mut {  "mut "  }  else {  ""  } ) , 
504+                             Applicability :: MachineApplicable , 
505+                         ) ; 
506+                         can_suggest_clone = is_mut; 
507+                     }  else  { 
508+                         let  mut  span:  MultiSpan  = arg. span . into ( ) ; 
509+                         span. push_span_label ( 
510+                             arg. span , 
511+                             "this parameter takes ownership of the value" . to_string ( ) , 
512+                         ) ; 
513+                         let  descr = match  node. fn_kind ( )  { 
514+                             Some ( hir:: intravisit:: FnKind :: ItemFn ( ..) )  | None  => "function" , 
515+                             Some ( hir:: intravisit:: FnKind :: Method ( ..) )  => "method" , 
516+                             Some ( hir:: intravisit:: FnKind :: Closure )  => "closure" , 
517+                         } ; 
518+                         span. push_span_label ( ident. span ,  format ! ( "in this {descr}" ) ) ; 
519+                         err. span_note ( 
520+                             span, 
521+                             format ! ( 
522+                                 "consider changing this parameter type in {descr} `{ident}` to \  
523+                                   borrow instead if owning the value isn't necessary", 
524+                             ) , 
525+                         ) ; 
526+                     } 
477527                } 
478528                let  place = & self . move_data . move_paths [ mpi] . place ; 
479529                let  ty = place. ty ( self . body ,  self . infcx . tcx ) . ty ; 
@@ -491,9 +541,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
491541                        ClosureKind :: Coroutine ( CoroutineKind :: Desugared ( _,  CoroutineSource :: Block ) ) , 
492542                    ..
493543                }  = move_spans
544+                     && can_suggest_clone
494545                { 
495546                    self . suggest_cloning ( err,  ty,  expr,  None ,  Some ( move_spans) ) ; 
496-                 }  else  if  self . suggest_hoisting_call_outside_loop ( err,  expr)  { 
547+                 }  else  if  self . suggest_hoisting_call_outside_loop ( err,  expr)  && can_suggest_clone  { 
497548                    // The place where the type moves would be misleading to suggest clone. 
498549                    // #121466 
499550                    self . suggest_cloning ( err,  ty,  expr,  None ,  Some ( move_spans) ) ; 
0 commit comments