Rollup merge of #124599 - estebank:issue-41708, r=wesleywiser · rust-lang/rust@8de487f

@@ -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));