@@ -524,8 +524,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
524524 if self . not_enough_args_provided ( ) {
525525 self . suggest_adding_args ( err) ;
526526 } else if self . too_many_args_provided ( ) {
527+ self . suggest_moving_args_from_assoc_fn_to_trait ( err) ;
527528 self . suggest_removing_args_or_generics ( err) ;
528- self . suggest_moving_args ( err) ;
529529 } else {
530530 unreachable ! ( ) ;
531531 }
@@ -661,34 +661,62 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
661661 /// ```compile_fail
662662 /// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)`
663663 /// ```
664- fn suggest_moving_args ( & self , err : & mut Diagnostic ) {
665- if let Some ( trait_) = self . tcx . trait_of_item ( self . def_id ) {
666- // HACK(hkmatsumoto): Ugly way to tell "<trait>::<assoc fn>()" from "x.<assoc fn>()";
667- // we don't care the latter (for now).
668- if self . path_segment . res == Some ( hir:: def:: Res :: Err ) {
669- return ;
670- }
671-
672- // Say, if the assoc fn takes `A`, `B` and `C` as generic arguments while expecting 1
673- // argument, and its trait expects 2 arguments. It is hard to "split" them right as
674- // there are too many cases to handle: `A` `B` | `C`, `A` `B` | `C`, `A` `C` | `B`, ...
675- let num_assoc_fn_expected_args =
676- self . num_expected_type_or_const_args ( ) + self . num_expected_lifetime_args ( ) ;
677- if num_assoc_fn_expected_args > 0 {
678- return ;
679- }
664+ fn suggest_moving_args_from_assoc_fn_to_trait ( & self , err : & mut Diagnostic ) {
665+ let trait_ = match self . tcx . trait_of_item ( self . def_id ) {
666+ Some ( def_id) => def_id,
667+ None => return ,
668+ } ;
680669
681- let num_assoc_fn_excess_args =
682- self . num_excess_type_or_const_args ( ) + self . num_excess_lifetime_args ( ) ;
670+ // Skip suggestion when the associated function is itself generic, it is unclear
671+ // how to split the provided parameters between those to suggest to the trait and
672+ // those to remain on the associated type.
673+ let num_assoc_fn_expected_args =
674+ self . num_expected_type_or_const_args ( ) + self . num_expected_lifetime_args ( ) ;
675+ if num_assoc_fn_expected_args > 0 {
676+ return ;
677+ }
683678
684- let trait_generics = self . tcx . generics_of ( trait_) ;
685- let num_trait_generics_except_self =
686- trait_generics. count ( ) - if trait_generics. has_self { 1 } else { 0 } ;
679+ let num_assoc_fn_excess_args =
680+ self . num_excess_type_or_const_args ( ) + self . num_excess_lifetime_args ( ) ;
681+
682+ let trait_generics = self . tcx . generics_of ( trait_) ;
683+ let num_trait_generics_except_self =
684+ trait_generics. count ( ) - if trait_generics. has_self { 1 } else { 0 } ;
685+
686+ if let Some ( hir_id) = self . path_segment . hir_id
687+ && let Some ( parent_node) = self . tcx . hir ( ) . find_parent_node ( hir_id)
688+ && let Some ( parent_node) = self . tcx . hir ( ) . find ( parent_node)
689+ && let hir:: Node :: Expr ( expr) = parent_node {
690+ match expr. kind {
691+ hir:: ExprKind :: Path ( ref qpath) => {
692+ self . suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path (
693+ err,
694+ trait_,
695+ qpath,
696+ num_assoc_fn_excess_args,
697+ num_trait_generics_except_self
698+ )
699+ } ,
700+ // TODO(hkmatsumoto): Emit similar suggestion for "x.<assoc fn>()"
701+ hir:: ExprKind :: MethodCall ( ..) => return ,
702+ _ => return ,
703+ }
704+ }
705+ }
687706
688- // FIXME(hkmatsumoto): RHS of this condition ideally should be
689- // `num_trait_generics_except_self` - "# of generic args already provided to trait"
690- // but unable to get that information with `self.def_id`.
691- if num_assoc_fn_excess_args == num_trait_generics_except_self {
707+ fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path (
708+ & self ,
709+ err : & mut Diagnostic ,
710+ trait_ : DefId ,
711+ qpath : & ' tcx hir:: QPath < ' tcx > ,
712+ num_assoc_fn_excess_args : usize ,
713+ num_trait_generics_except_self : usize ,
714+ ) {
715+ if let hir:: QPath :: Resolved ( _, path) = qpath
716+ && let Some ( trait_path_segment) = path. segments . get ( 0 ) {
717+ let num_generic_args_supplied_to_trait = trait_path_segment. args ( ) . num_generic_params ( ) ;
718+
719+ if num_assoc_fn_excess_args == num_trait_generics_except_self - num_generic_args_supplied_to_trait {
692720 if let Some ( span) = self . gen_args . span_ext ( )
693721 && let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
694722 let msg = format ! (
0 commit comments