@@ -445,31 +445,81 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
445
445
} else {
446
446
( None , & [ ] [ ..] , 0 )
447
447
} ;
448
+ let mut can_suggest_clone = true ;
448
449
if let Some ( def_id) = def_id
449
450
&& let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
450
451
&& let Some ( fn_sig) = node. fn_sig ( )
451
452
&& let Some ( ident) = node. ident ( )
452
453
&& let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
453
454
&& let Some ( arg) = fn_sig. decl . inputs . get ( pos + offset)
454
455
{
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
+ }
473
523
}
474
524
let place = & self . move_data . move_paths [ mpi] . place ;
475
525
let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
@@ -487,9 +537,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
487
537
ClosureKind :: Coroutine ( CoroutineKind :: Desugared ( _, CoroutineSource :: Block ) ) ,
488
538
..
489
539
} = move_spans
540
+ && can_suggest_clone
490
541
{
491
542
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 {
493
544
// The place where the type moves would be misleading to suggest clone.
494
545
// #121466
495
546
self . suggest_cloning ( err, ty, expr, None , Some ( move_spans) ) ;
0 commit comments