@@ -206,7 +206,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
206
206
207
207
if !seen_spans. contains ( & move_span) {
208
208
if !closure {
209
- self . suggest_ref_or_clone ( mpi, & mut err, & mut in_pattern, move_spans) ;
209
+ self . suggest_ref_or_clone (
210
+ mpi,
211
+ & mut err,
212
+ & mut in_pattern,
213
+ move_spans,
214
+ moved_place. as_ref ( ) ,
215
+ ) ;
210
216
}
211
217
212
218
let msg_opt = CapturedMessageOpt {
@@ -258,17 +264,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
258
264
if is_loop_move & !in_pattern && !matches ! ( use_spans, UseSpans :: ClosureUse { .. } ) {
259
265
if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
260
266
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
261
- err. span_suggestion_verbose (
262
- span. shrink_to_lo ( ) ,
263
- format ! (
264
- "consider creating a fresh reborrow of {} here" ,
265
- self . describe_place( moved_place)
266
- . map( |n| format!( "`{n}`" ) )
267
- . unwrap_or_else( || "the mutable reference" . to_string( ) ) ,
268
- ) ,
269
- "&mut *" ,
270
- Applicability :: MachineApplicable ,
271
- ) ;
267
+ self . suggest_reborrow ( & mut err, span, moved_place) ;
272
268
}
273
269
}
274
270
@@ -345,6 +341,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
345
341
err : & mut Diag < ' infcx > ,
346
342
in_pattern : & mut bool ,
347
343
move_spans : UseSpans < ' tcx > ,
344
+ moved_place : PlaceRef < ' tcx > ,
348
345
) {
349
346
let move_span = match move_spans {
350
347
UseSpans :: ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -434,19 +431,48 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
434
431
let parent = self . infcx . tcx . parent_hir_node ( expr. hir_id ) ;
435
432
let ( def_id, args, offset) = if let hir:: Node :: Expr ( parent_expr) = parent
436
433
&& let hir:: ExprKind :: MethodCall ( _, _, args, _) = parent_expr. kind
437
- && let Some ( def_id) = typeck. type_dependent_def_id ( parent_expr. hir_id )
438
434
{
439
- ( def_id . as_local ( ) , args, 1 )
435
+ ( typeck . type_dependent_def_id ( parent_expr . hir_id ) , args, 1 )
440
436
} else if let hir:: Node :: Expr ( parent_expr) = parent
441
437
&& let hir:: ExprKind :: Call ( call, args) = parent_expr. kind
442
438
&& let ty:: FnDef ( def_id, _) = typeck. node_type ( call. hir_id ) . kind ( )
443
439
{
444
- ( def_id . as_local ( ) , args, 0 )
440
+ ( Some ( * def_id ) , args, 0 )
445
441
} else {
446
442
( None , & [ ] [ ..] , 0 )
447
443
} ;
444
+
445
+ // If the moved value is a mut reference, it is used in a
446
+ // generic function and it's type is a generic param, it can be
447
+ // reborrowed to avoid moving.
448
+ // for example:
449
+ // struct Y(u32);
450
+ // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
451
+ let is_sugg_reborrow = || {
452
+ if let Some ( def_id) = def_id
453
+ && let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
454
+ && let ty:: Param ( _) =
455
+ self . infcx . tcx . fn_sig ( def_id) . skip_binder ( ) . skip_binder ( ) . inputs ( )
456
+ [ pos + offset]
457
+ . kind ( )
458
+ {
459
+ let place = & self . move_data . move_paths [ mpi] . place ;
460
+ let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
461
+ if let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = ty. kind ( ) {
462
+ return true ;
463
+ }
464
+ }
465
+ false
466
+ } ;
467
+ let suggest_reborrow = is_sugg_reborrow ( ) ;
468
+ if suggest_reborrow {
469
+ self . suggest_reborrow ( err, expr. span , moved_place) ;
470
+ return ;
471
+ }
472
+
448
473
if let Some ( def_id) = def_id
449
- && let node = self . infcx . tcx . hir_node_by_def_id ( def_id)
474
+ && let Some ( local_def_id) = def_id. as_local ( )
475
+ && let node = self . infcx . tcx . hir_node_by_def_id ( local_def_id)
450
476
&& let Some ( fn_sig) = node. fn_sig ( )
451
477
&& let Some ( ident) = node. ident ( )
452
478
&& let Some ( pos) = args. iter ( ) . position ( |arg| arg. hir_id == expr. hir_id )
@@ -463,13 +489,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
463
489
Some ( hir:: intravisit:: FnKind :: Closure ) => "closure" ,
464
490
} ;
465
491
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
- ) ;
492
+ if !suggest_reborrow {
493
+ err. span_note (
494
+ span,
495
+ format ! (
496
+ "consider changing this parameter type in {descr} `{ident}` to borrow \
497
+ instead if owning the value isn't necessary",
498
+ ) ,
499
+ ) ;
500
+ }
473
501
}
474
502
let place = & self . move_data . move_paths [ mpi] . place ;
475
503
let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
@@ -510,6 +538,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
510
538
}
511
539
}
512
540
541
+ fn suggest_reborrow ( & self , err : & mut Diag < ' infcx > , span : Span , moved_place : PlaceRef < ' tcx > ) {
542
+ err. span_suggestion_verbose (
543
+ span. shrink_to_lo ( ) ,
544
+ format ! (
545
+ "consider creating a fresh reborrow of {} here" ,
546
+ self . describe_place( moved_place)
547
+ . map( |n| format!( "`{n}`" ) )
548
+ . unwrap_or_else( || "the mutable reference" . to_string( ) ) ,
549
+ ) ,
550
+ "&mut *" ,
551
+ Applicability :: MachineApplicable ,
552
+ ) ;
553
+ }
554
+
513
555
fn report_use_of_uninitialized (
514
556
& self ,
515
557
mpi : MovePathIndex ,
0 commit comments