about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-09-05 00:23:02 +0000
committerMichael Goulet <michael@errs.io>2022-09-05 20:47:20 +0000
commitbee48e3fdc44d8c322fb6b86b7c18dc0faf76beb (patch)
treef99302a856fd0cdbb57798c3d0f1e804a09ad4c8
parentb44197abb0b3ffe4908892e1e08ab1cd721ff3b9 (diff)
downloadrust-bee48e3fdc44d8c322fb6b86b7c18dc0faf76beb.tar.gz
rust-bee48e3fdc44d8c322fb6b86b7c18dc0faf76beb.zip
Fix ICE, generalize 'move generics to trait' suggestion for >0 non-rcvr arguments
-rw-r--r--compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs44
-rw-r--r--src/test/ui/suggestions/issue-101421.rs12
-rw-r--r--src/test/ui/suggestions/issue-101421.stderr17
-rw-r--r--src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs18
-rw-r--r--src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr24
5 files changed, 104 insertions, 11 deletions
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index cddb0ce2346..4359124646d 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -749,23 +749,45 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
         &self,
         err: &mut Diagnostic,
-        trait_: DefId,
+        trait_def_id: DefId,
         expr: &'tcx hir::Expr<'tcx>,
         msg: String,
         num_assoc_fn_excess_args: usize,
         num_trait_generics_except_self: usize,
     ) {
-        if let hir::ExprKind::MethodCall(_, receiver, args, ..) = expr.kind {
-            assert_eq!(args.len(), 0);
-            if num_assoc_fn_excess_args == num_trait_generics_except_self {
-                if let Some(gen_args) = self.gen_args.span_ext()
-                && let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args)
-                && let Ok(receiver) = self.tcx.sess.source_map().span_to_snippet(receiver.span) {
-                    let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), receiver);
-                    err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect);
-                }
-            }
+        let sm = self.tcx.sess.source_map();
+        let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return; };
+        if num_assoc_fn_excess_args != num_trait_generics_except_self {
+            return;
         }
+        let Some(gen_args) = self.gen_args.span_ext() else { return; };
+        let Ok(generics) = sm.span_to_snippet(gen_args) else { return; };
+        let Ok(rcvr) = sm.span_to_snippet(
+            rcvr.span.find_ancestor_inside(expr.span).unwrap_or(rcvr.span)
+        ) else { return; };
+        let Ok(rest) =
+            (match args {
+                [] => Ok(String::new()),
+                [arg] => sm.span_to_snippet(
+                    arg.span.find_ancestor_inside(expr.span).unwrap_or(arg.span),
+                ),
+                [first, .., last] => {
+                    let first_span =
+                        first.span.find_ancestor_inside(expr.span).unwrap_or(first.span);
+                    let last_span =
+                        last.span.find_ancestor_inside(expr.span).unwrap_or(last.span);
+                    sm.span_to_snippet(first_span.to(last_span))
+                }
+            }) else { return; };
+        let comma = if args.len() > 0 { ", " } else { "" };
+        let trait_path = self.tcx.def_path_str(trait_def_id);
+        let method_name = self.tcx.item_name(self.def_id);
+        err.span_suggestion(
+            expr.span,
+            msg,
+            format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"),
+            Applicability::MaybeIncorrect,
+        );
     }
 
     /// Suggests to remove redundant argument(s):
diff --git a/src/test/ui/suggestions/issue-101421.rs b/src/test/ui/suggestions/issue-101421.rs
new file mode 100644
index 00000000000..b615997d1a9
--- /dev/null
+++ b/src/test/ui/suggestions/issue-101421.rs
@@ -0,0 +1,12 @@
+pub trait Ice {
+    fn f(&self, _: ());
+}
+
+impl Ice for () {
+    fn f(&self, _: ()) {}
+}
+
+fn main() {
+    ().f::<()>(());
+    //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied
+}
diff --git a/src/test/ui/suggestions/issue-101421.stderr b/src/test/ui/suggestions/issue-101421.stderr
new file mode 100644
index 00000000000..f8e1efb8820
--- /dev/null
+++ b/src/test/ui/suggestions/issue-101421.stderr
@@ -0,0 +1,17 @@
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-101421.rs:10:8
+   |
+LL |     ().f::<()>(());
+   |        ^------ help: remove these generics
+   |        |
+   |        expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/issue-101421.rs:2:8
+   |
+LL |     fn f(&self, _: ());
+   |        ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
new file mode 100644
index 00000000000..2f540060a34
--- /dev/null
+++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
@@ -0,0 +1,18 @@
+// Generalizes the suggestion introduced in #100838
+
+trait Foo<T> {
+    fn bar(&self, _: T);
+}
+
+impl Foo<i32> for i32 {
+    fn bar(&self, x: i32) {
+        println!("{}", self + x);
+    }
+}
+
+fn main() {
+    1.bar::<i32>(0);
+    //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied
+    //~| HELP consider moving this generic argument to the `Foo` trait, which takes up to 1 argument
+    //~| HELP remove these generics
+}
diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
new file mode 100644
index 00000000000..9557220f6bb
--- /dev/null
+++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
@@ -0,0 +1,24 @@
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/move-generic-to-trait-in-method-with-params.rs:14:7
+   |
+LL |     1.bar::<i32>(0);
+   |       ^^^ expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/move-generic-to-trait-in-method-with-params.rs:4:8
+   |
+LL |     fn bar(&self, _: T);
+   |        ^^^
+help: consider moving this generic argument to the `Foo` trait, which takes up to 1 argument
+   |
+LL |     Foo::<i32>::bar(1, 0);
+   |     ~~~~~~~~~~~~~~~~~~~~~
+help: remove these generics
+   |
+LL -     1.bar::<i32>(0);
+LL +     1.bar(0);
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.