@@ -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