@@ -449,31 +449,81 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
449
449
} else {
450
450
( None , & [ ] [ ..] , 0 )
451
451
} ;
452
+ let mut can_suggest_clone = true ;
452
453
if let Some ( def_id) = def_id
453
454
&& let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
454
455
&& let Some ( fn_sig) = node. fn_sig ( )
455
456
&& let Some ( ident) = node. ident ( )
456
457
&& let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
457
458
&& let Some ( arg) = fn_sig. decl . inputs . get ( pos + offset)
458
459
{
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
+ }
477
527
}
478
528
let place = & self . move_data . move_paths [ mpi] . place ;
479
529
let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
@@ -491,9 +541,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
491
541
ClosureKind :: Coroutine ( CoroutineKind :: Desugared ( _, CoroutineSource :: Block ) ) ,
492
542
..
493
543
} = move_spans
544
+ && can_suggest_clone
494
545
{
495
546
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 {
497
548
// The place where the type moves would be misleading to suggest clone.
498
549
// #121466
499
550
self . suggest_cloning ( err, ty, expr, None , Some ( move_spans) ) ;
0 commit comments