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 e4a90329108e0..36e94c3dce5ae 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 @@ -683,6 +683,14 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let num_trait_generics_except_self = trait_generics.count() - if trait_generics.has_self { 1 } else { 0 }; + let msg = format!( + "consider moving {these} generic argument{s} to the `{name}` trait, which takes up to {num} argument{s}", + these = pluralize!("this", num_assoc_fn_excess_args), + s = pluralize!(num_assoc_fn_excess_args), + name = self.tcx.item_name(trait_), + num = num_trait_generics_except_self, + ); + if let Some(hir_id) = self.path_segment.hir_id && let Some(parent_node) = self.tcx.hir().find_parent_node(hir_id) && let Some(parent_node) = self.tcx.hir().find(parent_node) @@ -691,14 +699,22 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { hir::ExprKind::Path(ref qpath) => { self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( err, - trait_, qpath, + msg, + num_assoc_fn_excess_args, + num_trait_generics_except_self + ) + }, + hir::ExprKind::MethodCall(..) => { + self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + err, + trait_, + expr, + msg, num_assoc_fn_excess_args, num_trait_generics_except_self ) }, - // FIXME(hkmatsumoto): Emit similar suggestion for "x.()" - hir::ExprKind::MethodCall(..) => return, _ => return, } } @@ -707,8 +723,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( &self, err: &mut Diagnostic, - trait_: DefId, qpath: &'tcx hir::QPath<'tcx>, + msg: String, num_assoc_fn_excess_args: usize, num_trait_generics_except_self: usize, ) { @@ -719,13 +735,6 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if num_assoc_fn_excess_args == num_trait_generics_except_self - num_generic_args_supplied_to_trait { if let Some(span) = self.gen_args.span_ext() && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let msg = format!( - "consider moving {these} generic argument{s} to the `{name}` trait, which takes up to {num} argument{s}", - these = pluralize!("this", num_assoc_fn_excess_args), - s = pluralize!(num_assoc_fn_excess_args), - name = self.tcx.item_name(trait_), - num = num_trait_generics_except_self, - ); let sugg = vec![ (self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)), (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()) @@ -741,6 +750,28 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } + fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + &self, + err: &mut Diagnostic, + trait_: 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(_, args, _) = expr.kind { + assert_eq!(args.len(), 1); + 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(args) = self.tcx.sess.source_map().span_to_snippet(args[0].span) { + let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), args); + err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect); + } + } + } + } + /// Suggests to remove redundant argument(s): /// /// ```text diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr index b1b359619dcfa..d955b4f9651da 100644 --- a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr +++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr @@ -2,15 +2,22 @@ error[E0107]: this associated function takes 0 generic arguments but 1 generic a --> $DIR/invalid-const-arg-for-type-param.rs:6:23 | LL | let _: u32 = 5i32.try_into::<32>().unwrap(); - | ^^^^^^^^------ help: remove these generics - | | - | expected 0 generic arguments + | ^^^^^^^^ expected 0 generic arguments | note: associated function defined here, with 0 generic parameters --> $SRC_DIR/core/src/convert/mod.rs:LL:COL | LL | fn try_into(self) -> Result; | ^^^^^^^^ +help: consider moving this generic argument to the `TryInto` trait, which takes up to 1 argument + | +LL | let _: u32 = TryInto::<32>::try_into(5i32).unwrap(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: remove these generics + | +LL - let _: u32 = 5i32.try_into::<32>().unwrap(); +LL + let _: u32 = 5i32.try_into().unwrap(); + | error[E0599]: no method named `f` found for struct `S` in the current scope --> $DIR/invalid-const-arg-for-type-param.rs:9:7 diff --git a/src/test/ui/suggestions/issue-89064.rs b/src/test/ui/suggestions/issue-89064.rs index 17a3e8b4cf831..fa5fc899dc083 100644 --- a/src/test/ui/suggestions/issue-89064.rs +++ b/src/test/ui/suggestions/issue-89064.rs @@ -27,4 +27,9 @@ fn main() { let _ = A::::foo::(); //~^ ERROR //~| HELP remove these generics + + let _ = 42.into::>(); + //~^ ERROR + //~| HELP remove these generics + //~| HELP consider moving this generic argument } diff --git a/src/test/ui/suggestions/issue-89064.stderr b/src/test/ui/suggestions/issue-89064.stderr index 846cd817505c3..8b2a388162806 100644 --- a/src/test/ui/suggestions/issue-89064.stderr +++ b/src/test/ui/suggestions/issue-89064.stderr @@ -9,15 +9,15 @@ note: associated function defined here, with 0 generic parameters | LL | fn foo() {} | ^^^ -help: remove these generics +help: consider moving this generic argument to the `A` trait, which takes up to 1 argument | LL - let _ = A::foo::(); -LL + let _ = A::foo(); +LL + let _ = A::::foo(); | -help: consider moving this generic argument to the `A` trait, which takes up to 1 argument +help: remove these generics | LL - let _ = A::foo::(); -LL + let _ = A::::foo(); +LL + let _ = A::foo(); | error[E0107]: this associated function takes 0 generic arguments but 2 generic arguments were supplied @@ -31,15 +31,15 @@ note: associated function defined here, with 0 generic parameters | LL | fn bar() {} | ^^^ -help: remove these generics +help: consider moving these generic arguments to the `B` trait, which takes up to 2 arguments | LL - let _ = B::bar::(); -LL + let _ = B::bar(); +LL + let _ = B::::bar(); | -help: consider moving these generic arguments to the `B` trait, which takes up to 2 arguments +help: remove these generics | LL - let _ = B::bar::(); -LL + let _ = B::::bar(); +LL + let _ = B::bar(); | error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied @@ -56,6 +56,27 @@ note: associated function defined here, with 0 generic parameters LL | fn foo() {} | ^^^ -error: aborting due to 3 previous errors +error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/issue-89064.rs:31:16 + | +LL | let _ = 42.into::>(); + | ^^^^ expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL + | +LL | fn into(self) -> T; + | ^^^^ +help: consider moving this generic argument to the `Into` trait, which takes up to 1 argument + | +LL | let _ = Into::>::into(42); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: remove these generics + | +LL - let _ = 42.into::>(); +LL + let _ = 42.into(); + | + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0107`.