Suggest .clone()
on method call move errors
This commit is contained in:
parent
c79db9c5e5
commit
a929316aed
@ -3447,6 +3447,7 @@ dependencies = [
|
|||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_graphviz",
|
"rustc_graphviz",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
"rustc_hir_analysis",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
"rustc_lexer",
|
"rustc_lexer",
|
||||||
|
@ -15,6 +15,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
|
|||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_graphviz = { path = "../rustc_graphviz" }
|
rustc_graphviz = { path = "../rustc_graphviz" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
|
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_infer = { path = "../rustc_infer" }
|
rustc_infer = { path = "../rustc_infer" }
|
||||||
rustc_lexer = { path = "../rustc_lexer" }
|
rustc_lexer = { path = "../rustc_lexer" }
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, Namespace};
|
use rustc_hir::def::{CtorKind, Namespace};
|
||||||
use rustc_hir::GeneratorKind;
|
use rustc_hir::GeneratorKind;
|
||||||
|
use rustc_hir_analysis::hir_ty_to_ty;
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
@ -1066,18 +1067,16 @@ fn explain_captures(
|
|||||||
}
|
}
|
||||||
CallKind::Normal { self_arg, desugaring, method_did } => {
|
CallKind::Normal { self_arg, desugaring, method_did } => {
|
||||||
let self_arg = self_arg.unwrap();
|
let self_arg = self_arg.unwrap();
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||||
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
let ty = moved_place.ty(self.body, tcx).ty;
|
||||||
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
|
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
|
||||||
Some(def_id) => {
|
Some(def_id) => {
|
||||||
let infcx = self.infcx.tcx.infer_ctxt().build();
|
let infcx = self.infcx.tcx.infer_ctxt().build();
|
||||||
type_known_to_meet_bound_modulo_regions(
|
type_known_to_meet_bound_modulo_regions(
|
||||||
&infcx,
|
&infcx,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
infcx.tcx.mk_imm_ref(
|
tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
|
||||||
infcx.tcx.lifetimes.re_erased,
|
|
||||||
infcx.tcx.erase_regions(ty),
|
|
||||||
),
|
|
||||||
def_id,
|
def_id,
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
)
|
)
|
||||||
@ -1133,8 +1132,8 @@ fn explain_captures(
|
|||||||
place_name, partially_str, loop_message
|
place_name, partially_str, loop_message
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if let ty::Adt(def, ..)
|
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
||||||
= moved_place.ty(self.body, self.infcx.tcx).ty.kind()
|
if let ty::Adt(def, ..) = ty.kind()
|
||||||
&& Some(def.did()) == self.infcx.tcx.lang_items().pin_type()
|
&& Some(def.did()) == self.infcx.tcx.lang_items().pin_type()
|
||||||
{
|
{
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
@ -1144,8 +1143,34 @@ fn explain_captures(
|
|||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(clone_trait) = tcx.lang_items().clone_trait() {
|
||||||
|
// We can't use `predicate_may_hold` or `can_eq` without ICEs in
|
||||||
|
// borrowck because of the inference context, so we do a poor-man's
|
||||||
|
// version here.
|
||||||
|
for impl_def_id in tcx.all_impls(clone_trait) {
|
||||||
|
if let Some(def_id) = impl_def_id.as_local()
|
||||||
|
&& let hir_id = tcx.hir().local_def_id_to_hir_id(def_id)
|
||||||
|
&& let hir::Node::Item(hir::Item {
|
||||||
|
kind: hir::ItemKind::Impl(hir::Impl {
|
||||||
|
self_ty,
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
..
|
||||||
|
}) = tcx.hir().get(hir_id)
|
||||||
|
{
|
||||||
|
if ty == hir_ty_to_ty(tcx, self_ty) {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
fn_call_span.shrink_to_lo(),
|
||||||
|
"you can `clone` the value and consume it, but this \
|
||||||
|
might not be your desired behavior",
|
||||||
|
"clone().".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let tcx = self.infcx.tcx;
|
|
||||||
// Avoid pointing to the same function in multiple different
|
// Avoid pointing to the same function in multiple different
|
||||||
// error messages.
|
// error messages.
|
||||||
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
|
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
|
||||||
|
11
src/test/ui/moves/suggest-clone.fixed
Normal file
11
src/test/ui/moves/suggest-clone.fixed
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Foo;
|
||||||
|
impl Foo {
|
||||||
|
fn foo(self) {}
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let foo = &Foo;
|
||||||
|
foo.clone().foo(); //~ ERROR cannot move out
|
||||||
|
}
|
11
src/test/ui/moves/suggest-clone.rs
Normal file
11
src/test/ui/moves/suggest-clone.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Foo;
|
||||||
|
impl Foo {
|
||||||
|
fn foo(self) {}
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let foo = &Foo;
|
||||||
|
foo.foo(); //~ ERROR cannot move out
|
||||||
|
}
|
22
src/test/ui/moves/suggest-clone.stderr
Normal file
22
src/test/ui/moves/suggest-clone.stderr
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
error[E0507]: cannot move out of `*foo` which is behind a shared reference
|
||||||
|
--> $DIR/suggest-clone.rs:10:5
|
||||||
|
|
|
||||||
|
LL | foo.foo();
|
||||||
|
| ^^^^-----
|
||||||
|
| | |
|
||||||
|
| | `*foo` moved due to this method call
|
||||||
|
| move occurs because `*foo` has type `Foo`, which does not implement the `Copy` trait
|
||||||
|
|
|
||||||
|
note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo`
|
||||||
|
--> $DIR/suggest-clone.rs:6:12
|
||||||
|
|
|
||||||
|
LL | fn foo(self) {}
|
||||||
|
| ^^^^
|
||||||
|
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
||||||
|
|
|
||||||
|
LL | foo.clone().foo();
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0507`.
|
Loading…
Reference in New Issue
Block a user