Suggest borrowing on fn argument that is impl AsRef
· rust-lang/rust@2df4f7d (original) (raw)
`@@ -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));
`