Suggest `.clone()` when moved while borrowed

This commit is contained in:
Esteban Küber 2024-03-13 01:51:08 +00:00
parent ccae456863
commit fa2fc3ab96
29 changed files with 246 additions and 19 deletions

View File

@ -987,6 +987,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
can_suggest_clone
}
pub(crate) fn suggest_cloning(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
span: Span,
) {
if let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()
&& self
.infcx
.type_implements_trait(clone_trait_def, [ty], self.param_env)
.must_apply_modulo_regions()
{
self.suggest_cloning_inner(err, ty, expr, span);
}
}
pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind
@ -1002,7 +1019,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) {
fn suggest_cloning_inner(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
span: Span,
) {
let tcx = self.infcx.tcx;
// Try to find predicates on *generic params* that would allow copying `ty`
let suggestion =
@ -1136,6 +1159,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
);
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
if let Some(expr) = self.find_expr(borrow_span)
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
{
self.suggest_cloning(&mut err, ty, expr, borrow_span);
}
self.buffer_error(err);
}
@ -1553,22 +1582,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
for ty in types_to_constrain {
self.suggest_adding_bounds(err, ty, clone, body.span);
if let ty::Adt(..) = ty.kind() {
// The type doesn't implement Clone.
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
let obligation = Obligation::new(
self.infcx.tcx,
ObligationCause::dummy(),
self.param_env,
trait_ref,
);
self.infcx.err_ctxt().suggest_derive(
&obligation,
err,
trait_ref.to_predicate(self.infcx.tcx),
);
}
self.suggest_adding_bounds_or_derive(err, ty, clone, body.span);
}
}
pub(crate) fn suggest_adding_bounds_or_derive(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
def_id: DefId,
span: Span,
) {
self.suggest_adding_bounds(err, ty, def_id, span);
if let ty::Adt(..) = ty.kind() {
// The type doesn't implement DefId.
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, def_id, [ty]));
let obligation = Obligation::new(
self.infcx.tcx,
ObligationCause::dummy(),
self.param_env,
trait_ref,
);
self.infcx.err_ctxt().suggest_derive(
&obligation,
err,
trait_ref.to_predicate(self.infcx.tcx),
);
}
}

View File

@ -10,6 +10,11 @@ LL | drop(x);
| ^ move out of `x` occurs here
LL | return f(y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | 's: loop { y = denormalise(&x.clone()); break }
| ++++++++
error: aborting due to 1 previous error

View File

@ -51,6 +51,11 @@ LL | x
...
LL | use_mut(n); use_imm(m);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let m = &x.clone();
| ++++++++
error[E0505]: cannot move out of `y` because it is borrowed
--> $DIR/binop-move-semantics.rs:23:5

View File

@ -10,6 +10,11 @@ LL | let y = x;
LL |
LL | r.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let r = &x.0.clone();
| ++++++++
error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
--> $DIR/borrow-tuple-fields.rs:18:13
@ -42,6 +47,11 @@ LL | let y = x;
| ^ move out of `x` occurs here
LL | r.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let r = &x.0.clone();
| ++++++++
error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable
--> $DIR/borrow-tuple-fields.rs:33:13

View File

@ -10,6 +10,11 @@ LL | &*a,
| --- borrow of `*a` occurs here
LL | a);
| ^ move out of `a` occurs here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | &*a.clone(),
| ++++++++
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/borrowck-bad-nested-calls-move.rs:32:9
@ -22,6 +27,11 @@ LL | &*a,
| --- borrow of `*a` occurs here
LL | a);
| ^ move out of `a` occurs here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | &*a.clone(),
| ++++++++
error: aborting due to 2 previous errors

View File

@ -49,6 +49,11 @@ LL | drop(x.b);
| ^^^ move out of `x.b` occurs here
LL | drop(**p);
| --- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let p = &x.b.clone();
| ++++++++
error[E0505]: cannot move out of `x.b` because it is borrowed
--> $DIR/borrowck-field-sensitivity.rs:41:14
@ -61,6 +66,11 @@ LL | let _y = A { a: 3, .. x };
| ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here
LL | drop(**p);
| --- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let p = &x.b.clone();
| ++++++++
error[E0499]: cannot borrow `x.a` as mutable more than once at a time
--> $DIR/borrowck-field-sensitivity.rs:48:13

View File

@ -13,6 +13,11 @@ LL | println!("v={}", *v);
LL | });
LL | w.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let w = &v.clone();
| ++++++++
error[E0505]: cannot move out of `v` because it is borrowed
--> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
@ -29,6 +34,11 @@ LL | println!("v={}", *v);
LL | });
LL | w.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let w = &v.clone();
| ++++++++
error: aborting due to 2 previous errors

View File

@ -9,6 +9,11 @@ LL | take(v);
| ^ move out of `v` occurs here
LL | w.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let w = &v.clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -10,6 +10,11 @@ LL | let z = *a;
| ^^ move out of `*a` occurs here
LL | b.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let b = &a.clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -10,6 +10,11 @@ LL | let t1 = t0;
LL | *t1 = 22;
LL | p.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let p: &isize = &*t0.clone(); // Freezes `*t0`
| ++++++++
error: aborting due to 1 previous error

View File

@ -9,6 +9,11 @@ LL | let S { x: ax } = a;
| ^^ move out of `a.x` occurs here
LL | f(pb);
| -- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let pb = &a.clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -14,6 +14,11 @@ LL | drop(x1);
...
LL | borrow(&*p1);
| ---- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let p1 = &x1.clone();
| ++++++++
error[E0505]: cannot move out of `x2` because it is borrowed
--> $DIR/borrowck-multiple-captures.rs:12:19
@ -30,6 +35,11 @@ LL | drop(x2);
...
LL | borrow(&*p2);
| ---- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let p2 = &x2.clone();
| ++++++++
error[E0382]: use of moved value: `x1`
--> $DIR/borrowck-multiple-captures.rs:27:19
@ -93,6 +103,11 @@ LL | drop(x);
...
LL | borrow(&*p);
| --- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let p = &x.clone();
| ++++++++
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-multiple-captures.rs:52:14

View File

@ -9,6 +9,11 @@ LL | free(x);
| ^ move out of `x` occurs here
LL | *y
| -- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let y = &*x.clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -9,7 +9,7 @@ fn foo<T: Default + Clone>(list: &mut Vec<T>) {
drop(cloned_items);
}
fn bar<T: std::fmt::Display + Clone>(x: T) {
let a = &x;
let a = &x.clone();
let b = a.clone();
drop(x);
//~^ ERROR cannot move out of `x` because it is borrowed
@ -19,7 +19,7 @@ fn bar<T: std::fmt::Display + Clone>(x: T) {
#[derive(Clone)]
struct A;
fn qux(x: A) {
let a = &x;
let a = &x.clone();
let b = a.clone();
drop(x);
//~^ ERROR cannot move out of `x` because it is borrowed

View File

@ -36,6 +36,10 @@ help: consider further restricting this bound
|
LL | fn bar<T: std::fmt::Display + Clone>(x: T) {
| +++++++
help: consider cloning the value if the performance cost is acceptable
|
LL | let a = &x.clone();
| ++++++++
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/clone-on-ref.rs:23:10
@ -57,6 +61,10 @@ help: consider annotating `A` with `#[derive(Clone)]`
LL + #[derive(Clone)]
LL | struct A;
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let a = &x.clone();
| ++++++++
error: aborting due to 3 previous errors

View File

@ -9,6 +9,11 @@ LL | drop(s);
| ^ move out of `s` occurs here
LL | }
| - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap`
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let _map = BTreeMap::from_iter([((), PrintOnDrop(&s.clone()))]);
| ++++++++
error: aborting due to 1 previous error

View File

@ -9,6 +9,11 @@ LL | drop(a);
| ^ move out of `a` occurs here
LL | for s in &b {
| -- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let b: Vec<&str> = a.clone().lines().collect();
| ++++++++
error: aborting due to 1 previous error

View File

@ -13,6 +13,11 @@ LL | println!("child function: {}", fancy_num.num);
...
LL | println!("main function: {}", fancy_ref.num);
| ------------- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let fancy_ref = &fancy_num.clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -10,6 +10,11 @@ LL | eat(x);
| ^ move out of `x` occurs here
LL | _ref_to_val.use_ref();
| ----------- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let _ref_to_val: &Value = &x.clone();
| ++++++++
error: aborting due to 1 previous error

View File

@ -10,6 +10,11 @@ LL | drop(x);
LL |
LL | println!("{}", y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let y = f(&x.clone(), ());
| ++++++++
error: aborting due to 1 previous error

View File

@ -27,6 +27,11 @@ LL | drop(x);
| ^ move out of `x` occurs here
LL | println!("{}", y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let y = f(&x.clone(), ());
| ++++++++
error: aborting due to 2 previous errors

View File

@ -10,6 +10,11 @@ LL | drop(x);
LL |
LL | println!("{}", y);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let y = f(&x.clone(), ());
| ++++++++
error: aborting due to 1 previous error

View File

@ -57,6 +57,11 @@ LL | || x;
| move out of `x` occurs here
LL | r.use_ref();
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let r = &x.clone();
| ++++++++
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-access-spans.rs:35:5

View File

@ -10,6 +10,11 @@ LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
LL | _x1 = U;
LL | drop(hold_all);
| -------- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let hold_all = &arr.clone();
| ++++++++
error[E0384]: cannot assign twice to immutable variable `_x1`
--> $DIR/borrowck-move-ref-pattern.rs:9:5

View File

@ -57,6 +57,11 @@ LL | f(Box::new(|a| {
LL |
LL | foo(f);
| - move occurs due to use in closure
|
help: consider cloning the value if the performance cost is acceptable
|
LL | f.clone()(Box::new(|a| {
| ++++++++
error: aborting due to 5 previous errors

View File

@ -11,6 +11,11 @@ LL | drop(y);
...
LL | *lock.lock().unwrap() = &z;
| ---- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | *lock.lock().unwrap() = &*y.clone();
| ++++++++
error[E0597]: `z` does not live long enough
--> $DIR/send-is-not-static-std-sync.rs:16:33
@ -38,6 +43,11 @@ LL | drop(y);
...
LL | *lock.write().unwrap() = &z;
| ---- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | *lock.write().unwrap() = &*y.clone();
| ++++++++
error[E0597]: `z` does not live long enough
--> $DIR/send-is-not-static-std-sync.rs:30:34
@ -65,6 +75,11 @@ LL | drop(y);
...
LL | tx.send(&z).unwrap();
| -- borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | tx.send(&*y.clone());
| ++++++++
error[E0597]: `z` does not live long enough
--> $DIR/send-is-not-static-std-sync.rs:46:17

View File

@ -7,6 +7,11 @@ LL | for i in &a {
| -- borrow of `a` occurs here
LL | for j in a {
| ^ move out of `a` occurs here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | for i in &a.clone() {
| ++++++++
error[E0382]: use of moved value: `a`
--> $DIR/borrow-for-loop-head.rs:4:18

View File

@ -33,6 +33,11 @@ LL | !x;
...
LL | use_mut(n); use_imm(m);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let m = &x.clone();
| ++++++++
error[E0505]: cannot move out of `y` because it is borrowed
--> $DIR/unop-move-semantics.rs:17:6

View File

@ -9,6 +9,11 @@ LL | drop(a);
| ^ move out of `a` occurs here
LL | drop(x);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = foo(&a.clone());
| ++++++++
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:34:14
@ -21,6 +26,11 @@ LL | drop(a);
| ^ move out of `a` occurs here
LL | drop(x);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = bar(&a.clone());
| ++++++++
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:40:14
@ -33,6 +43,11 @@ LL | drop(a);
| ^ move out of `a` occurs here
LL | drop(x);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = baz(&a.clone());
| ++++++++
error: aborting due to 3 previous errors