]> git.lizzy.rs Git - rust.git/commitdiff
Use structured suggestion when requiring `Copy` constraint in type param
authorEsteban Küber <esteban@kuber.com.ar>
Wed, 20 Nov 2019 00:43:24 +0000 (16:43 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Thu, 28 Nov 2019 20:20:28 +0000 (12:20 -0800)
src/librustc_mir/borrow_check/conflict_errors.rs
src/test/ui/binop/binop-consume-args.stderr
src/test/ui/binop/binop-move-semantics.stderr
src/test/ui/borrowck/borrowck-unboxed-closures.stderr
src/test/ui/issues/issue-34721.fixed [new file with mode: 0644]
src/test/ui/issues/issue-34721.rs
src/test/ui/issues/issue-34721.stderr
src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
src/test/ui/once-cant-call-twice-on-heap.stderr
src/test/ui/unop-move-semantics.stderr

index 8508bf62d8f60e5a9c5b0f305d2715a15b9fb7d1..e3da090a62d30f17e091fa866c1f03ed5c29a191 100644 (file)
@@ -231,12 +231,64 @@ pub(super) fn report_use_of_moved_or_uninitialized(
                 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() {
index 5751af27fcb424109c7bb739b9e928a09d1d1f78..5a6a2f9258393f1ffe0935d066dac4481195ff61 100644 (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);
index 897607dc2d8d52b59457c21d528386af02670093..8efb73657fa81978f9628046171b1dfd96a93e2d 100644 (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 |     +
index 40b8e3134847071719089eb4832add1796a23e5a..5a0afda013ee6970e7bdcd559ad58feb2f8380fc 100644 (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);
diff --git a/src/test/ui/issues/issue-34721.fixed b/src/test/ui/issues/issue-34721.fixed
new file mode 100644 (file)
index 0000000..88f0345
--- /dev/null
@@ -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);
+}
index bdc9fe43a8bd961fc33dfbda3e8fe56574dfe353..14dd01766aa4475b1b4dc6bb8b26b1d88dd23add 100644 (file)
@@ -1,3 +1,5 @@
+// run-rustfix
+
 pub trait Foo {
     fn zero(self) -> Self;
 }
index d5cede990a335116a3d8f631ae19745d6da8c0b7..abf65afd7ed9846e0df1073d3a018d88f10fa061 100644 (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
index 483c364752b7b7b0c8923eb60da66d33bea1a269..ead2cceebf857293567757b1c0245c7c4fba5cec 100644 (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)
index f98d3d83845377b0d3f0f37765d4a89b907fd4d5..22f98c2a979b1e1cc538f71d1bd4b1ca4ae8675f 100644 (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();
index 6aa3d0b09896b6b77444ea3e7600a7c10897e435..0dbd3b8cd0d5ace1e51b36212d195dc6214e8b84 100644 (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 |