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