Skip to content

Commit 72e3767

Browse files
authored
Rollup merge of #144201 - estebank:suggest-clone, r=SparrowLii
Mention type that could be `Clone` but isn't in more cases When encountering a moved value of a type that isn't `Clone` because of unmet obligations, but where all the unmet predicates reference crate-local types, mention them and suggest cloning, as we do in other cases already: ``` error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure --> f111.rs:14:25 | 13 | fn do_stuff(foo: Option<Foo>) { | --- captured outer variable 14 | require_fn_trait(|| async { | -- ^^^^^ `foo` is moved here | | | captured by this `Fn` closure 15 | if foo.map_or(false, |f| f.foo()) { | --- | | | variable moved due to use in coroutine | move occurs because `foo` has type `Option<Foo>`, which does not implement the `Copy` trait | note: if `Foo` implemented `Clone`, you could clone the value --> f111.rs:4:1 | 4 | struct Foo; | ^^^^^^^^^^ consider implementing `Clone` for this type ... 15 | if foo.map_or(false, |f| f.foo()) { | --- you could clone this value ``` CC #68119.
2 parents 3f7d497 + 1106183 commit 72e3767

18 files changed

+364
-0
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,58 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12901290
span,
12911291
format!("if `{ty}` implemented `Clone`, you could clone the value"),
12921292
);
1293+
} else if let ty::Adt(_, _) = ty.kind()
1294+
&& let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
1295+
{
1296+
// For cases like `Option<NonClone>`, where `Option<T>: Clone` if `T: Clone`, we point
1297+
// at the types that should be `Clone`.
1298+
let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);
1299+
let cause = ObligationCause::misc(expr.span, self.mir_def_id());
1300+
ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait);
1301+
let errors = ocx.select_all_or_error();
1302+
if errors.iter().all(|error| {
1303+
match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) {
1304+
Some(clause) => match clause.self_ty().skip_binder().kind() {
1305+
ty::Adt(def, _) => def.did().is_local() && clause.def_id() == clone_trait,
1306+
_ => false,
1307+
},
1308+
None => false,
1309+
}
1310+
}) {
1311+
let mut type_spans = vec![];
1312+
let mut types = FxIndexSet::default();
1313+
for clause in errors
1314+
.iter()
1315+
.filter_map(|e| e.obligation.predicate.as_clause())
1316+
.filter_map(|c| c.as_trait_clause())
1317+
{
1318+
let ty::Adt(def, _) = clause.self_ty().skip_binder().kind() else { continue };
1319+
type_spans.push(self.infcx.tcx.def_span(def.did()));
1320+
types.insert(
1321+
self.infcx
1322+
.tcx
1323+
.short_string(clause.self_ty().skip_binder(), &mut err.long_ty_path()),
1324+
);
1325+
}
1326+
let mut span: MultiSpan = type_spans.clone().into();
1327+
for sp in type_spans {
1328+
span.push_span_label(sp, "consider implementing `Clone` for this type");
1329+
}
1330+
span.push_span_label(expr.span, "you could clone this value");
1331+
let types: Vec<_> = types.into_iter().collect();
1332+
let msg = match &types[..] {
1333+
[only] => format!("`{only}`"),
1334+
[head @ .., last] => format!(
1335+
"{} and `{last}`",
1336+
head.iter().map(|t| format!("`{t}`")).collect::<Vec<_>>().join(", ")
1337+
),
1338+
[] => unreachable!(),
1339+
};
1340+
err.span_note(
1341+
span,
1342+
format!("if {msg} implemented `Clone`, you could clone the value"),
1343+
);
1344+
}
12931345
}
12941346
}
12951347

tests/ui/borrowck/borrowck-partial-reinit-1.stderr

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ LL | drop(t);
88
| - value moved here
99
LL | t.b = Some(u);
1010
| ^^^ value assigned here after move
11+
|
12+
note: if `Test2` implemented `Clone`, you could clone the value
13+
--> $DIR/borrowck-partial-reinit-1.rs:3:1
14+
|
15+
LL | struct Test2 {
16+
| ^^^^^^^^^^^^ consider implementing `Clone` for this type
17+
...
18+
LL | drop(t);
19+
| - you could clone this value
1120

1221
error[E0382]: assign of moved value: `t`
1322
--> $DIR/borrowck-partial-reinit-1.rs:33:5
@@ -19,6 +28,15 @@ LL | drop(t);
1928
| - value moved here
2029
LL | t.0 = Some(u);
2130
| ^^^ value assigned here after move
31+
|
32+
note: if `Test3` implemented `Clone`, you could clone the value
33+
--> $DIR/borrowck-partial-reinit-1.rs:7:1
34+
|
35+
LL | struct Test3(Option<Test>);
36+
| ^^^^^^^^^^^^ consider implementing `Clone` for this type
37+
...
38+
LL | drop(t);
39+
| - you could clone this value
2240

2341
error: aborting due to 2 previous errors
2442

tests/ui/borrowck/borrowck-partial-reinit-2.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ LL | let mut u = Test { a: 2, b: Some(Box::new(t))};
77
| - value moved here
88
LL | t.b = Some(Box::new(u));
99
| ^^^ value assigned here after move
10+
|
11+
note: if `Test` implemented `Clone`, you could clone the value
12+
--> $DIR/borrowck-partial-reinit-2.rs:1:1
13+
|
14+
LL | struct Test {
15+
| ^^^^^^^^^^^ consider implementing `Clone` for this type
16+
...
17+
LL | let mut u = Test { a: 2, b: Some(Box::new(t))};
18+
| - you could clone this value
1019

1120
error: aborting due to 1 previous error
1221

tests/ui/borrowck/borrowck-union-move-assign.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ LL | let a = u.a;
77
| --- value moved here
88
LL | let a = u.a;
99
| ^^^ value used here after move
10+
|
11+
note: if `U` implemented `Clone`, you could clone the value
12+
--> $DIR/borrowck-union-move-assign.rs:7:1
13+
|
14+
LL | union U {
15+
| ^^^^^^^ consider implementing `Clone` for this type
16+
...
17+
LL | let a = u.a;
18+
| --- you could clone this value
1019

1120
error: aborting due to 1 previous error
1221

tests/ui/borrowck/borrowck-union-move.stderr

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ LL | let a = u.n1;
77
| ---- value moved here
88
LL | let a = u.n1;
99
| ^^^^ value used here after move
10+
|
11+
note: if `Unn` implemented `Clone`, you could clone the value
12+
--> $DIR/borrowck-union-move.rs:7:1
13+
|
14+
LL | union Unn {
15+
| ^^^^^^^^^ consider implementing `Clone` for this type
16+
...
17+
LL | let a = u.n1;
18+
| ---- you could clone this value
1019

1120
error[E0382]: use of moved value: `u`
1221
--> $DIR/borrowck-union-move.rs:31:21
@@ -17,6 +26,15 @@ LL | let a = u.n1;
1726
| ---- value moved here
1827
LL | let a = u;
1928
| ^ value used here after move
29+
|
30+
note: if `Unn` implemented `Clone`, you could clone the value
31+
--> $DIR/borrowck-union-move.rs:7:1
32+
|
33+
LL | union Unn {
34+
| ^^^^^^^^^ consider implementing `Clone` for this type
35+
...
36+
LL | let a = u.n1;
37+
| ---- you could clone this value
2038

2139
error[E0382]: use of moved value: `u`
2240
--> $DIR/borrowck-union-move.rs:36:21
@@ -27,6 +45,15 @@ LL | let a = u.n1;
2745
| ---- value moved here
2846
LL | let a = u.n2;
2947
| ^^^^ value used here after move
48+
|
49+
note: if `Unn` implemented `Clone`, you could clone the value
50+
--> $DIR/borrowck-union-move.rs:7:1
51+
|
52+
LL | union Unn {
53+
| ^^^^^^^^^ consider implementing `Clone` for this type
54+
...
55+
LL | let a = u.n1;
56+
| ---- you could clone this value
3057

3158
error[E0382]: use of moved value: `u`
3259
--> $DIR/borrowck-union-move.rs:63:21
@@ -37,6 +64,15 @@ LL | let a = u.n;
3764
| --- value moved here
3865
LL | let a = u.n;
3966
| ^^^ value used here after move
67+
|
68+
note: if `Ucn` implemented `Clone`, you could clone the value
69+
--> $DIR/borrowck-union-move.rs:15:1
70+
|
71+
LL | union Ucn {
72+
| ^^^^^^^^^ consider implementing `Clone` for this type
73+
...
74+
LL | let a = u.n;
75+
| --- you could clone this value
4076

4177
error[E0382]: use of moved value: `u`
4278
--> $DIR/borrowck-union-move.rs:68:21
@@ -47,6 +83,15 @@ LL | let a = u.n;
4783
| --- value moved here
4884
LL | let a = u.c;
4985
| ^^^ value used here after move
86+
|
87+
note: if `Ucn` implemented `Clone`, you could clone the value
88+
--> $DIR/borrowck-union-move.rs:15:1
89+
|
90+
LL | union Ucn {
91+
| ^^^^^^^^^ consider implementing `Clone` for this type
92+
...
93+
LL | let a = u.n;
94+
| --- you could clone this value
5095

5196
error[E0382]: use of moved value: `u`
5297
--> $DIR/borrowck-union-move.rs:83:21
@@ -57,6 +102,15 @@ LL | let a = u.n;
57102
| --- value moved here
58103
LL | let a = u;
59104
| ^ value used here after move
105+
|
106+
note: if `Ucn` implemented `Clone`, you could clone the value
107+
--> $DIR/borrowck-union-move.rs:15:1
108+
|
109+
LL | union Ucn {
110+
| ^^^^^^^^^ consider implementing `Clone` for this type
111+
...
112+
LL | let a = u.n;
113+
| --- you could clone this value
60114

61115
error: aborting due to 6 previous errors
62116

tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ LL | drop(u);
1717
| - value moved here
1818
LL | u.0 = S(1);
1919
| ^^^^^^^^^^ value partially assigned here after move
20+
|
21+
note: if `Tpair` implemented `Clone`, you could clone the value
22+
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:6:1
23+
|
24+
LL | struct Tpair(S, i32);
25+
| ^^^^^^^^^^^^ consider implementing `Clone` for this type
26+
...
27+
LL | drop(u);
28+
| - you could clone this value
2029

2130
error[E0382]: assign to part of moved value: `v`
2231
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:31:9
@@ -27,6 +36,15 @@ LL | drop(v);
2736
| - value moved here
2837
LL | v.x = S(1);
2938
| ^^^^^^^^^^ value partially assigned here after move
39+
|
40+
note: if `Spair` implemented `Clone`, you could clone the value
41+
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:7:1
42+
|
43+
LL | struct Spair { x: S, y: i32 }
44+
| ^^^^^^^^^^^^ consider implementing `Clone` for this type
45+
...
46+
LL | drop(v);
47+
| - you could clone this value
3048

3149
error: aborting due to 3 previous errors
3250

tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ LL | drop(u);
5050
| - value moved here
5151
LL | u.0 = S(1);
5252
| ^^^^^^^^^^ value partially assigned here after move
53+
|
54+
note: if `Tpair` implemented `Clone`, you could clone the value
55+
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:6:1
56+
|
57+
LL | struct Tpair(S, i32);
58+
| ^^^^^^^^^^^^ consider implementing `Clone` for this type
59+
...
60+
LL | drop(u);
61+
| - you could clone this value
5362

5463
error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
5564
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
@@ -82,6 +91,15 @@ LL | drop(v);
8291
| - value moved here
8392
LL | v.x = S(1);
8493
| ^^^^^^^^^^ value partially assigned here after move
94+
|
95+
note: if `Spair` implemented `Clone`, you could clone the value
96+
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:7:1
97+
|
98+
LL | struct Spair { x: S, y: i32 }
99+
| ^^^^^^^^^^^^ consider implementing `Clone` for this type
100+
...
101+
LL | drop(v);
102+
| - you could clone this value
85103

86104
error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
87105
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9

tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ error[E0507]: cannot move out of `*array` which is behind a shared reference
44
LL | *array
55
| ^^^^^^ move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait
66
|
7+
note: if `Value` implemented `Clone`, you could clone the value
8+
--> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:4:1
9+
|
10+
LL | struct Value;
11+
| ^^^^^^^^^^^^ consider implementing `Clone` for this type
12+
...
13+
LL | *array
14+
| ------ you could clone this value
715
help: consider removing the dereference here
816
|
917
LL - *array

tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2018.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ LL | E::Number(_) if let E::String(s) = *value => { }
2626
...
2727
LL | let x = value;
2828
| ^^^^^ value used here after move
29+
|
30+
note: if `E` implemented `Clone`, you could clone the value
31+
--> $DIR/if-let-guards-errors.rs:32:1
32+
|
33+
LL | E::Number(_) if let E::String(s) = *value => { }
34+
| ------ you could clone this value
35+
...
36+
LL | enum E {
37+
| ^^^^^^ consider implementing `Clone` for this type
2938

3039
error: aborting due to 2 previous errors
3140

tests/ui/closures/2229_closure_analysis/match/if-let-guards-errors.e2021.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ LL | E::Number(_) if let E::String(s) = *value => { }
2626
...
2727
LL | let x = value;
2828
| ^^^^^ value used here after move
29+
|
30+
note: if `E` implemented `Clone`, you could clone the value
31+
--> $DIR/if-let-guards-errors.rs:32:1
32+
|
33+
LL | E::Number(_) if let E::String(s) = *value => { }
34+
| ------ you could clone this value
35+
...
36+
LL | enum E {
37+
| ^^^^^^ consider implementing `Clone` for this type
2938

3039
error: aborting due to 2 previous errors
3140

0 commit comments

Comments
 (0)