]> git.lizzy.rs Git - rust.git/commitdiff
Structured suggestion for `&mut dyn Iterator` when possible
authorEsteban Küber <esteban@kuber.com.ar>
Mon, 2 Jan 2023 05:28:03 +0000 (21:28 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Fri, 6 Jan 2023 21:03:26 +0000 (21:03 +0000)
Fix #37914.

compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
src/test/ui/illegal-sized-bound/mutability-mismatch-arg.fixed [new file with mode: 0644]
src/test/ui/illegal-sized-bound/mutability-mismatch-arg.rs [new file with mode: 0644]
src/test/ui/illegal-sized-bound/mutability-mismatch-arg.stderr [new file with mode: 0644]
src/test/ui/illegal-sized-bound/mutability-mismatch.rs
src/test/ui/illegal-sized-bound/mutability-mismatch.stderr
src/test/ui/suggestions/imm-ref-trait-object.stderr

index b9b27e8627aff7024bd75538500b368ee1e93280..f3c43e3f4973b0ab9bf3ee3b41a7797d51af9fec 100644 (file)
@@ -57,7 +57,7 @@ pub enum MethodError<'tcx> {
     PrivateMatch(DefKind, DefId, Vec<DefId>),
 
     // Found a `Self: Sized` bound where `Self` is a trait object.
-    IllegalSizedBound(Vec<DefId>, bool, Span),
+    IllegalSizedBound(Vec<DefId>, bool, Span, &'tcx hir::Expr<'tcx>),
 
     // Found a match, but the return type is wrong
     BadReturnType,
@@ -236,7 +236,7 @@ pub fn lookup_method(
                     _ => Vec::new(),
                 };
 
-            return Err(IllegalSizedBound(candidates, needs_mut, span));
+            return Err(IllegalSizedBound(candidates, needs_mut, span, self_expr));
         }
 
         Ok(result.callee)
index 1a42f9d07b1820b8d58cb1e77c7f1cfcafe0750f..5a43db69fd4995ac81ad016ff5819a35ebf5da58 100644 (file)
@@ -176,7 +176,7 @@ pub fn report_method_error(
                 err.emit();
             }
 
-            MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
+            MethodError::IllegalSizedBound(candidates, needs_mut, bound_span, self_expr) => {
                 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
                 let mut err = self.sess().struct_span_err(span, &msg);
                 err.span_label(bound_span, "this has a `Sized` requirement");
@@ -197,7 +197,34 @@ pub fn report_method_error(
                             *region,
                             ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
                         );
-                        err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
+                        let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
+                        let mut kind = &self_expr.kind;
+                        while let hir::ExprKind::AddrOf(_, _, expr)
+                        | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
+                        {
+                            kind = &expr.kind;
+                        }
+                        if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
+                            && let hir::def::Res::Local(hir_id) = path.res
+                            && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
+                            && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
+                            && let Some(hir::Node::Param(param)) = self.tcx.hir().find(parent_hir_id)
+                            && let parent_hir_id = self.tcx.hir().get_parent_node(param.hir_id)
+                            && let Some(node) = self.tcx.hir().find(parent_hir_id)
+                            && let Some(decl) = node.fn_decl()
+                            && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == param.ty_span)
+                            && let hir::TyKind::Ref(_, mut_ty) = &ty.kind
+                            && let hir::Mutability::Not = mut_ty.mutbl
+                        {
+                            err.span_suggestion_verbose(
+                                mut_ty.ty.span.shrink_to_lo(),
+                                &msg,
+                                "mut ",
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            err.help(&msg);
+                        }
                     }
                 }
                 err.emit();
diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.fixed b/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.fixed
new file mode 100644 (file)
index 0000000..260ef54
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+     *t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
+}
+
+fn main() {
+     let array = [0u64];
+     test(&mut array.iter());
+}
diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.rs b/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.rs
new file mode 100644 (file)
index 0000000..7a16565
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
+     *t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
+}
+
+fn main() {
+     let array = [0u64];
+     test(&mut array.iter());
+}
diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.stderr b/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.stderr
new file mode 100644 (file)
index 0000000..9b4b9b6
--- /dev/null
@@ -0,0 +1,16 @@
+error: the `min` method cannot be invoked on a trait object
+  --> $DIR/mutability-mismatch-arg.rs:3:9
+   |
+LL |      *t.min().unwrap()
+   |         ^^^
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+   = note: this has a `Sized` requirement
+   |
+help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
+   |
+LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+   |             +++
+
+error: aborting due to previous error
+
index deb84f6fe97cfd5d4d2560ec586c2d16f772847b..aa9b3d0389148c286e4b3be460cbe778effed485 100644 (file)
@@ -27,8 +27,8 @@ fn function(&self) {}
 fn main() {
     (&MutType as &dyn MutTrait).function();
     //~^ ERROR the `function` method cannot be invoked on a trait object
-    //~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+    //~| HELP you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
     (&mut Type as &mut dyn Trait).function();
     //~^ ERROR the `function` method cannot be invoked on a trait object
-    //~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait`
+    //~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
 }
index dbbf79a4f1a034f08b771dc12e1af7b34e0b7532..0120b9f91e94afa9777ef9c33512bbd9bead5bdb 100644 (file)
@@ -7,7 +7,7 @@ LL |         Self: Sized;
 LL |     (&MutType as &dyn MutTrait).function();
    |                                 ^^^^^^^^
    |
-   = note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+   = help: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
 
 error: the `function` method cannot be invoked on a trait object
   --> $DIR/mutability-mismatch.rs:31:35
@@ -18,7 +18,7 @@ LL |         Self: Sized;
 LL |     (&mut Type as &mut dyn Trait).function();
    |                                   ^^^^^^^^
    |
-   = note: you need `&dyn Trait` instead of `&mut dyn Trait`
+   = help: you need `&dyn Trait` instead of `&mut dyn Trait`
 
 error: aborting due to 2 previous errors
 
index 7791b308d5d0e597a4263c6afb85570b07f1158a..02847ed8c4c6e746082596f8a4b66e6041356f2a 100644 (file)
@@ -7,7 +7,10 @@ LL |      t.min().unwrap()
    |
    = note: this has a `Sized` requirement
    |
-   = note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
+help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
+   |
+LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+   |             +++
 
 error: aborting due to previous error