@@ -524,8 +524,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
524
524
if self . not_enough_args_provided ( ) {
525
525
self . suggest_adding_args ( err) ;
526
526
} else if self . too_many_args_provided ( ) {
527
+ self . suggest_moving_args_from_assoc_fn_to_trait ( err) ;
527
528
self . suggest_removing_args_or_generics ( err) ;
528
- self . suggest_moving_args ( err) ;
529
529
} else {
530
530
unreachable ! ( ) ;
531
531
}
@@ -661,34 +661,62 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
661
661
/// ```compile_fail
662
662
/// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)`
663
663
/// ```
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
+ } ;
680
669
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
+ }
683
678
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
+ }
687
706
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 {
692
720
if let Some ( span) = self . gen_args . span_ext ( )
693
721
&& let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
694
722
let msg = format ! (
0 commit comments