Use structured suggestion when requiring Copy constraint in type param

This commit is contained in:
Esteban Küber 2019-11-19 16:43:24 -08:00
parent f453d1127d
commit 02bc412d19
10 changed files with 140 additions and 52 deletions

View File

@ -231,12 +231,64 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let ty::Param(param_ty) = ty.kind {
let tcx = self.infcx.tcx;
let generics = tcx.generics_of(self.mir_def_id);
let def_id = generics.type_param(&param_ty, tcx).def_id;
if let Some(sp) = tcx.hir().span_if_local(def_id) {
err.span_label(
sp,
"consider adding a `Copy` constraint to this type argument",
);
let param = generics.type_param(&param_ty, tcx);
let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
let msg = "consider adding a `Copy` constraint to this type argument";
for param in generics.params.iter().filter(|p| {
p.name.ident().as_str() == param.name.as_str()
}) {
let param_name = param.name.ident().as_str();
if param_name.starts_with("impl ") {
// `impl Trait` in argument:
// `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
err.span_suggestion(
param.span,
msg,
// `impl CurrentTrait + MissingTrait`
format!("{} + Copy", param_name),
Applicability::MachineApplicable,
);
} else if generics.where_clause.predicates.is_empty() &&
param.bounds.is_empty()
{
// If there are no bounds whatsoever, suggest adding a constraint
// to the type parameter:
// `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
err.span_suggestion(
param.span,
msg,
format!("{}: Copy", param_name),
Applicability::MachineApplicable,
);
} else if !generics.where_clause.predicates.is_empty() {
// There is a `where` clause, so suggest expanding it:
// `fn foo<T>(t: T) where T: Debug {}` →
// `fn foo<T>(t: T) where T: Debug, T: Trait {}`
err.span_suggestion(
generics.where_clause.span().unwrap().shrink_to_hi(),
msg,
format!(", {}: Copy", param_name),
Applicability::MachineApplicable,
);
} else {
// If there is no `where` clause lean towards constraining to the
// type parameter:
// `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
// `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
let sp = param.span.with_hi(span.hi());
let span = tcx.sess.source_map()
.span_through_char(sp, ':');
if sp != param.span && sp != span {
// Only suggest if we have high certainty that the span
// covers the colon in `foo<T: Trait>`.
err.span_suggestion(span, msg, format!(
"{}: Copy +",
param_name,
), Applicability::MachineApplicable);
} else {
err.span_label(param.span, msg);
}
}
}
}
let span = if let Some(local) = place.as_local() {

View File

@ -2,9 +2,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:7:10
|
LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs + rhs;
| --- value moved here
LL | drop(lhs);
@ -16,7 +16,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs + rhs;
| --- value moved here
LL | drop(lhs);
@ -27,9 +27,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:13:10
|
LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs - rhs;
| --- value moved here
LL | drop(lhs);
@ -41,7 +41,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs - rhs;
| --- value moved here
LL | drop(lhs);
@ -52,9 +52,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:19:10
|
LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs * rhs;
| --- value moved here
LL | drop(lhs);
@ -66,7 +66,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs * rhs;
| --- value moved here
LL | drop(lhs);
@ -77,9 +77,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:25:10
|
LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs / rhs;
| --- value moved here
LL | drop(lhs);
@ -91,7 +91,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs / rhs;
| --- value moved here
LL | drop(lhs);
@ -102,9 +102,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:31:10
|
LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs % rhs;
| --- value moved here
LL | drop(lhs);
@ -116,7 +116,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs % rhs;
| --- value moved here
LL | drop(lhs);
@ -127,9 +127,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:37:10
|
LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs & rhs;
| --- value moved here
LL | drop(lhs);
@ -141,7 +141,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs & rhs;
| --- value moved here
LL | drop(lhs);
@ -152,9 +152,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:43:10
|
LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs | rhs;
| --- value moved here
LL | drop(lhs);
@ -166,7 +166,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs | rhs;
| --- value moved here
LL | drop(lhs);
@ -177,9 +177,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:49:10
|
LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs ^ rhs;
| --- value moved here
LL | drop(lhs);
@ -191,7 +191,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs ^ rhs;
| --- value moved here
LL | drop(lhs);
@ -202,9 +202,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:55:10
|
LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs << rhs;
| --- value moved here
LL | drop(lhs);
@ -216,7 +216,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs << rhs;
| --- value moved here
LL | drop(lhs);
@ -227,9 +227,9 @@ error[E0382]: use of moved value: `lhs`
--> $DIR/binop-consume-args.rs:61:10
|
LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| -- --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `A: Copy +`
LL | lhs >> rhs;
| --- value moved here
LL | drop(lhs);
@ -241,7 +241,7 @@ error[E0382]: use of moved value: `rhs`
LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `B: Copy`
LL | lhs >> rhs;
| --- value moved here
LL | drop(lhs);

View File

@ -2,9 +2,9 @@ error[E0382]: use of moved value: `x`
--> $DIR/binop-move-semantics.rs:8:5
|
LL | fn double_move<T: Add<Output=()>>(x: T) {
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| -- - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `T: Copy +`
LL | x
| - value moved here
LL | +
@ -15,9 +15,9 @@ error[E0382]: borrow of moved value: `x`
--> $DIR/binop-move-semantics.rs:14:5
|
LL | fn move_then_borrow<T: Add<Output=()> + Clone>(x: T) {
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| -- - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `T: Copy +`
LL | x
| - value moved here
LL | +

View File

@ -20,9 +20,9 @@ error[E0382]: use of moved value: `f`
--> $DIR/borrowck-unboxed-closures.rs:12:5
|
LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
| - - move occurs because `f` has type `F`, which does not implement the `Copy` trait
| -- - move occurs because `f` has type `F`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `F: Copy +`
LL | f(1, 2);
| - value moved here
LL | f(1, 2);

View File

@ -0,0 +1,34 @@
// run-rustfix
pub trait Foo {
fn zero(self) -> Self;
}
impl Foo for u32 {
fn zero(self) -> u32 { 0u32 }
}
pub mod bar {
pub use Foo;
pub fn bar<T: Foo>(x: T) -> T {
x.zero()
}
}
mod baz {
use bar;
use Foo;
pub fn baz<T: Copy + Foo>(x: T) -> T {
if 0 == 1 {
bar::bar(x.zero())
} else {
x.zero()
};
x.zero()
//~^ ERROR use of moved value
}
}
fn main() {
let _ = baz::baz(0u32);
}

View File

@ -1,3 +1,5 @@
// run-rustfix
pub trait Foo {
fn zero(self) -> Self;
}

View File

@ -1,10 +1,10 @@
error[E0382]: use of moved value: `x`
--> $DIR/issue-34721.rs:25:9
--> $DIR/issue-34721.rs:27:9
|
LL | pub fn baz<T: Foo>(x: T) -> T {
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| -- - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `T: Copy +`
LL | if 0 == 1 {
LL | bar::bar(x.zero())
| - value moved here

View File

@ -11,9 +11,9 @@ error[E0382]: borrow of moved value: `f`
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5
|
LL | fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) {
| - ----- move occurs because `f` has type `F`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| ----- - help: consider further restricting type parameter `F`: `, F: Copy`
| |
| move occurs because `f` has type `F`, which does not implement the `Copy` trait
LL | let mut r = R {c: Box::new(f)};
| - value moved here
LL | f(&mut r, false)

View File

@ -2,9 +2,9 @@ error[E0382]: use of moved value: `blk`
--> $DIR/once-cant-call-twice-on-heap.rs:9:5
|
LL | fn foo<F:FnOnce()>(blk: F) {
| - --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
| -- --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `F: Copy +`
LL | blk();
| --- value moved here
LL | blk();

View File

@ -2,9 +2,9 @@ error[E0382]: borrow of moved value: `x`
--> $DIR/unop-move-semantics.rs:8:5
|
LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| -- - move occurs because `x` has type `T`, which does not implement the `Copy` trait
| |
| consider adding a `Copy` constraint to this type argument
| help: consider adding a `Copy` constraint to this type argument: `T: Copy +`
LL | !x;
| - value moved here
LL |