Skip to content

Commit 02bc412

Browse files
committed
Use structured suggestion when requiring Copy constraint in type param
1 parent f453d11 commit 02bc412

10 files changed

+140
-52
lines changed

src/librustc_mir/borrow_check/conflict_errors.rs

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,64 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
231231
if let ty::Param(param_ty) = ty.kind {
232232
let tcx = self.infcx.tcx;
233233
let generics = tcx.generics_of(self.mir_def_id);
234-
let def_id = generics.type_param(&param_ty, tcx).def_id;
235-
if let Some(sp) = tcx.hir().span_if_local(def_id) {
236-
err.span_label(
237-
sp,
238-
"consider adding a `Copy` constraint to this type argument",
239-
);
234+
let param = generics.type_param(&param_ty, tcx);
235+
let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
236+
let msg = "consider adding a `Copy` constraint to this type argument";
237+
for param in generics.params.iter().filter(|p| {
238+
p.name.ident().as_str() == param.name.as_str()
239+
}) {
240+
let param_name = param.name.ident().as_str();
241+
if param_name.starts_with("impl ") {
242+
// `impl Trait` in argument:
243+
// `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
244+
err.span_suggestion(
245+
param.span,
246+
msg,
247+
// `impl CurrentTrait + MissingTrait`
248+
format!("{} + Copy", param_name),
249+
Applicability::MachineApplicable,
250+
);
251+
} else if generics.where_clause.predicates.is_empty() &&
252+
param.bounds.is_empty()
253+
{
254+
// If there are no bounds whatsoever, suggest adding a constraint
255+
// to the type parameter:
256+
// `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
257+
err.span_suggestion(
258+
param.span,
259+
msg,
260+
format!("{}: Copy", param_name),
261+
Applicability::MachineApplicable,
262+
);
263+
} else if !generics.where_clause.predicates.is_empty() {
264+
// There is a `where` clause, so suggest expanding it:
265+
// `fn foo<T>(t: T) where T: Debug {}` →
266+
// `fn foo<T>(t: T) where T: Debug, T: Trait {}`
267+
err.span_suggestion(
268+
generics.where_clause.span().unwrap().shrink_to_hi(),
269+
msg,
270+
format!(", {}: Copy", param_name),
271+
Applicability::MachineApplicable,
272+
);
273+
} else {
274+
// If there is no `where` clause lean towards constraining to the
275+
// type parameter:
276+
// `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
277+
// `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
278+
let sp = param.span.with_hi(span.hi());
279+
let span = tcx.sess.source_map()
280+
.span_through_char(sp, ':');
281+
if sp != param.span && sp != span {
282+
// Only suggest if we have high certainty that the span
283+
// covers the colon in `foo<T: Trait>`.
284+
err.span_suggestion(span, msg, format!(
285+
"{}: Copy +",
286+
param_name,
287+
), Applicability::MachineApplicable);
288+
} else {
289+
err.span_label(param.span, msg);
290+
}
291+
}
240292
}
241293
}
242294
let span = if let Some(local) = place.as_local() {

src/test/ui/binop/binop-consume-args.stderr

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ error[E0382]: use of moved value: `lhs`
22
--> $DIR/binop-consume-args.rs:7:10
33
|
44
LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
5-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
5+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
66
| |
7-
| consider adding a `Copy` constraint to this type argument
7+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
88
LL | lhs + rhs;
99
| --- value moved here
1010
LL | drop(lhs);
@@ -16,7 +16,7 @@ error[E0382]: use of moved value: `rhs`
1616
LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
1717
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
1818
| |
19-
| consider adding a `Copy` constraint to this type argument
19+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
2020
LL | lhs + rhs;
2121
| --- value moved here
2222
LL | drop(lhs);
@@ -27,9 +27,9 @@ error[E0382]: use of moved value: `lhs`
2727
--> $DIR/binop-consume-args.rs:13:10
2828
|
2929
LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
30-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
30+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
3131
| |
32-
| consider adding a `Copy` constraint to this type argument
32+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
3333
LL | lhs - rhs;
3434
| --- value moved here
3535
LL | drop(lhs);
@@ -41,7 +41,7 @@ error[E0382]: use of moved value: `rhs`
4141
LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
4242
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
4343
| |
44-
| consider adding a `Copy` constraint to this type argument
44+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
4545
LL | lhs - rhs;
4646
| --- value moved here
4747
LL | drop(lhs);
@@ -52,9 +52,9 @@ error[E0382]: use of moved value: `lhs`
5252
--> $DIR/binop-consume-args.rs:19:10
5353
|
5454
LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
55-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
55+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
5656
| |
57-
| consider adding a `Copy` constraint to this type argument
57+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
5858
LL | lhs * rhs;
5959
| --- value moved here
6060
LL | drop(lhs);
@@ -66,7 +66,7 @@ error[E0382]: use of moved value: `rhs`
6666
LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
6767
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
6868
| |
69-
| consider adding a `Copy` constraint to this type argument
69+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
7070
LL | lhs * rhs;
7171
| --- value moved here
7272
LL | drop(lhs);
@@ -77,9 +77,9 @@ error[E0382]: use of moved value: `lhs`
7777
--> $DIR/binop-consume-args.rs:25:10
7878
|
7979
LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
80-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
80+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
8181
| |
82-
| consider adding a `Copy` constraint to this type argument
82+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
8383
LL | lhs / rhs;
8484
| --- value moved here
8585
LL | drop(lhs);
@@ -91,7 +91,7 @@ error[E0382]: use of moved value: `rhs`
9191
LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
9292
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
9393
| |
94-
| consider adding a `Copy` constraint to this type argument
94+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
9595
LL | lhs / rhs;
9696
| --- value moved here
9797
LL | drop(lhs);
@@ -102,9 +102,9 @@ error[E0382]: use of moved value: `lhs`
102102
--> $DIR/binop-consume-args.rs:31:10
103103
|
104104
LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
105-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
105+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
106106
| |
107-
| consider adding a `Copy` constraint to this type argument
107+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
108108
LL | lhs % rhs;
109109
| --- value moved here
110110
LL | drop(lhs);
@@ -116,7 +116,7 @@ error[E0382]: use of moved value: `rhs`
116116
LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
117117
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
118118
| |
119-
| consider adding a `Copy` constraint to this type argument
119+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
120120
LL | lhs % rhs;
121121
| --- value moved here
122122
LL | drop(lhs);
@@ -127,9 +127,9 @@ error[E0382]: use of moved value: `lhs`
127127
--> $DIR/binop-consume-args.rs:37:10
128128
|
129129
LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
130-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
130+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
131131
| |
132-
| consider adding a `Copy` constraint to this type argument
132+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
133133
LL | lhs & rhs;
134134
| --- value moved here
135135
LL | drop(lhs);
@@ -141,7 +141,7 @@ error[E0382]: use of moved value: `rhs`
141141
LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
142142
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
143143
| |
144-
| consider adding a `Copy` constraint to this type argument
144+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
145145
LL | lhs & rhs;
146146
| --- value moved here
147147
LL | drop(lhs);
@@ -152,9 +152,9 @@ error[E0382]: use of moved value: `lhs`
152152
--> $DIR/binop-consume-args.rs:43:10
153153
|
154154
LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
155-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
155+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
156156
| |
157-
| consider adding a `Copy` constraint to this type argument
157+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
158158
LL | lhs | rhs;
159159
| --- value moved here
160160
LL | drop(lhs);
@@ -166,7 +166,7 @@ error[E0382]: use of moved value: `rhs`
166166
LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
167167
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
168168
| |
169-
| consider adding a `Copy` constraint to this type argument
169+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
170170
LL | lhs | rhs;
171171
| --- value moved here
172172
LL | drop(lhs);
@@ -177,9 +177,9 @@ error[E0382]: use of moved value: `lhs`
177177
--> $DIR/binop-consume-args.rs:49:10
178178
|
179179
LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
180-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
180+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
181181
| |
182-
| consider adding a `Copy` constraint to this type argument
182+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
183183
LL | lhs ^ rhs;
184184
| --- value moved here
185185
LL | drop(lhs);
@@ -191,7 +191,7 @@ error[E0382]: use of moved value: `rhs`
191191
LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
192192
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
193193
| |
194-
| consider adding a `Copy` constraint to this type argument
194+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
195195
LL | lhs ^ rhs;
196196
| --- value moved here
197197
LL | drop(lhs);
@@ -202,9 +202,9 @@ error[E0382]: use of moved value: `lhs`
202202
--> $DIR/binop-consume-args.rs:55:10
203203
|
204204
LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
205-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
205+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
206206
| |
207-
| consider adding a `Copy` constraint to this type argument
207+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
208208
LL | lhs << rhs;
209209
| --- value moved here
210210
LL | drop(lhs);
@@ -216,7 +216,7 @@ error[E0382]: use of moved value: `rhs`
216216
LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
217217
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
218218
| |
219-
| consider adding a `Copy` constraint to this type argument
219+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
220220
LL | lhs << rhs;
221221
| --- value moved here
222222
LL | drop(lhs);
@@ -227,9 +227,9 @@ error[E0382]: use of moved value: `lhs`
227227
--> $DIR/binop-consume-args.rs:61:10
228228
|
229229
LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
230-
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
230+
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
231231
| |
232-
| consider adding a `Copy` constraint to this type argument
232+
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
233233
LL | lhs >> rhs;
234234
| --- value moved here
235235
LL | drop(lhs);
@@ -241,7 +241,7 @@ error[E0382]: use of moved value: `rhs`
241241
LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
242242
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
243243
| |
244-
| consider adding a `Copy` constraint to this type argument
244+
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
245245
LL | lhs >> rhs;
246246
| --- value moved here
247247
LL | drop(lhs);

src/test/ui/binop/binop-move-semantics.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ error[E0382]: use of moved value: `x`
22
--> $DIR/binop-move-semantics.rs:8:5
33
|
44
LL | fn double_move<T: Add<Output=()>>(x: T) {
5-
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
5+
| -- - move occurs because `x` has type `T`, which does not implement the `Copy` trait
66
| |
7-
| consider adding a `Copy` constraint to this type argument
7+
| help: consider adding a `Copy` constraint to this type argument: `T: Copy +`
88
LL | x
99
| - value moved here
1010
LL | +
@@ -15,9 +15,9 @@ error[E0382]: borrow of moved value: `x`
1515
--> $DIR/binop-move-semantics.rs:14:5
1616
|
1717
LL | fn move_then_borrow<T: Add<Output=()> + Clone>(x: T) {
18-
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
18+
| -- - move occurs because `x` has type `T`, which does not implement the `Copy` trait
1919
| |
20-
| consider adding a `Copy` constraint to this type argument
20+
| help: consider adding a `Copy` constraint to this type argument: `T: Copy +`
2121
LL | x
2222
| - value moved here
2323
LL | +

src/test/ui/borrowck/borrowck-unboxed-closures.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ error[E0382]: use of moved value: `f`
2020
--> $DIR/borrowck-unboxed-closures.rs:12:5
2121
|
2222
LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
23-
| - - move occurs because `f` has type `F`, which does not implement the `Copy` trait
23+
| -- - move occurs because `f` has type `F`, which does not implement the `Copy` trait
2424
| |
25-
| consider adding a `Copy` constraint to this type argument
25+
| help: consider adding a `Copy` constraint to this type argument: `F: Copy +`
2626
LL | f(1, 2);
2727
| - value moved here
2828
LL | f(1, 2);

src/test/ui/issues/issue-34721.fixed

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// run-rustfix
2+
3+
pub trait Foo {
4+
fn zero(self) -> Self;
5+
}
6+
7+
impl Foo for u32 {
8+
fn zero(self) -> u32 { 0u32 }
9+
}
10+
11+
pub mod bar {
12+
pub use Foo;
13+
pub fn bar<T: Foo>(x: T) -> T {
14+
x.zero()
15+
}
16+
}
17+
18+
mod baz {
19+
use bar;
20+
use Foo;
21+
pub fn baz<T: Copy + Foo>(x: T) -> T {
22+
if 0 == 1 {
23+
bar::bar(x.zero())
24+
} else {
25+
x.zero()
26+
};
27+
x.zero()
28+
//~^ ERROR use of moved value
29+
}
30+
}
31+
32+
fn main() {
33+
let _ = baz::baz(0u32);
34+
}

src/test/ui/issues/issue-34721.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
13
pub trait Foo {
24
fn zero(self) -> Self;
35
}

src/test/ui/issues/issue-34721.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0382]: use of moved value: `x`
2-
--> $DIR/issue-34721.rs:25:9
2+
--> $DIR/issue-34721.rs:27:9
33
|
44
LL | pub fn baz<T: Foo>(x: T) -> T {
5-
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
5+
| -- - move occurs because `x` has type `T`, which does not implement the `Copy` trait
66
| |
7-
| consider adding a `Copy` constraint to this type argument
7+
| help: consider adding a `Copy` constraint to this type argument: `T: Copy +`
88
LL | if 0 == 1 {
99
LL | bar::bar(x.zero())
1010
| - value moved here

0 commit comments

Comments
 (0)