@@ -720,7 +720,7 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
720
720
_trait_item_span : Option < Span > ) // FIXME necessary?
721
721
-> Result < ( ) , ErrorReported > {
722
722
// FIXME(chrisvittal) Clean up this function, list of FIXME items:
723
- // 1. Better messages for the span lables
723
+ // 1. Better messages for the span labels
724
724
// 2. Explanation as to what is going on
725
725
// 3. Correct the function signature for what we actually use
726
726
// If we get here, we already have the same number of generics, so the zip will
@@ -751,8 +751,131 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
751
751
E0643 ,
752
752
"method `{}` has incompatible signature for trait" ,
753
753
trait_m. name) ;
754
- err. span_label ( trait_span, "annotation in trait" ) ;
755
- err. span_label ( impl_span, "annotation in impl" ) ;
754
+ err. span_label ( trait_span, "declaration in trait here" ) ;
755
+ match ( impl_synthetic, trait_synthetic) {
756
+ // The case where the impl method uses `impl Trait` but the trait method uses
757
+ // explicit generics
758
+ ( Some ( hir:: SyntheticTyParamKind :: ImplTrait ) , None ) => {
759
+ err. span_label ( impl_span, "expected generic parameter, found `impl Trait`" ) ;
760
+ ( || {
761
+ // try taking the name from the trait impl
762
+ // FIXME: this is obviously suboptimal since the name can already be used
763
+ // as another generic argument
764
+ let new_name = tcx
765
+ . sess
766
+ . codemap ( )
767
+ . span_to_snippet ( trait_span)
768
+ . ok ( ) ?;
769
+ let trait_m = tcx. hir . as_local_node_id ( trait_m. def_id ) ?;
770
+ let trait_m = tcx. hir . trait_item ( hir:: TraitItemId { node_id : trait_m } ) ;
771
+
772
+ let impl_m = tcx. hir . as_local_node_id ( impl_m. def_id ) ?;
773
+ let impl_m = tcx. hir . impl_item ( hir:: ImplItemId { node_id : impl_m } ) ;
774
+
775
+ // in case there are no generics, take the spot between the function name
776
+ // and the opening paren of the argument list
777
+ let new_generics_span = tcx
778
+ . sess
779
+ . codemap ( )
780
+ . generate_fn_name_span ( impl_m. span ) ?
781
+ . shrink_to_hi ( ) ;
782
+ // in case there are generics, just replace them
783
+ let generics_span = impl_m
784
+ . generics
785
+ . span
786
+ . substitute_dummy ( new_generics_span) ;
787
+ // replace with the generics from the trait
788
+ let new_generics = tcx
789
+ . sess
790
+ . codemap ( )
791
+ . span_to_snippet ( trait_m. generics . span )
792
+ . ok ( ) ?;
793
+
794
+ err. multipart_suggestion (
795
+ "try changing the `impl Trait` argument to a generic parameter" ,
796
+ vec ! [
797
+ // replace `impl Trait` with `T`
798
+ ( impl_span, new_name) ,
799
+ // replace impl method generics with trait method generics
800
+ // This isn't quite right, as users might have changed the names
801
+ // of the generics, but it works for the common case
802
+ ( generics_span, new_generics) ,
803
+ ] ,
804
+ ) ;
805
+ Some ( ( ) )
806
+ } ) ( ) ;
807
+ } ,
808
+ // The case where the trait method uses `impl Trait`, but the impl method uses
809
+ // explicit generics.
810
+ ( None , Some ( hir:: SyntheticTyParamKind :: ImplTrait ) ) => {
811
+ err. span_label ( impl_span, "expected `impl Trait`, found generic parameter" ) ;
812
+ ( || {
813
+ let impl_m = tcx. hir . as_local_node_id ( impl_m. def_id ) ?;
814
+ let impl_m = tcx. hir . impl_item ( hir:: ImplItemId { node_id : impl_m } ) ;
815
+ let input_tys = match impl_m. node {
816
+ hir:: ImplItemKind :: Method ( ref sig, _) => & sig. decl . inputs ,
817
+ _ => unreachable ! ( ) ,
818
+ } ;
819
+ struct Visitor ( Option < Span > , hir:: def_id:: DefId ) ;
820
+ impl < ' v > hir:: intravisit:: Visitor < ' v > for Visitor {
821
+ fn visit_ty ( & mut self , ty : & ' v hir:: Ty ) {
822
+ hir:: intravisit:: walk_ty ( self , ty) ;
823
+ match ty. node {
824
+ hir:: TyPath ( hir:: QPath :: Resolved ( None , ref path) ) => {
825
+ if let hir:: def:: Def :: TyParam ( def_id) = path. def {
826
+ if def_id == self . 1 {
827
+ self . 0 = Some ( ty. span ) ;
828
+ }
829
+ }
830
+ } ,
831
+ _ => { }
832
+ }
833
+ }
834
+ fn nested_visit_map < ' this > (
835
+ & ' this mut self
836
+ ) -> hir:: intravisit:: NestedVisitorMap < ' this , ' v > {
837
+ hir:: intravisit:: NestedVisitorMap :: None
838
+ }
839
+ }
840
+ let mut visitor = Visitor ( None , impl_def_id) ;
841
+ for ty in input_tys {
842
+ hir:: intravisit:: Visitor :: visit_ty ( & mut visitor, ty) ;
843
+ }
844
+ let span = visitor. 0 ?;
845
+
846
+ let param = impl_m. generics . params . iter ( ) . filter_map ( |param| {
847
+ match param {
848
+ hir:: GenericParam :: Type ( param) => {
849
+ if param. id == impl_node_id {
850
+ Some ( param)
851
+ } else {
852
+ None
853
+ }
854
+ } ,
855
+ hir:: GenericParam :: Lifetime ( ..) => None ,
856
+ }
857
+ } ) . next ( ) ?;
858
+ let bounds = param. bounds . first ( ) ?. span ( ) . to ( param. bounds . last ( ) ?. span ( ) ) ;
859
+ let bounds = tcx
860
+ . sess
861
+ . codemap ( )
862
+ . span_to_snippet ( bounds)
863
+ . ok ( ) ?;
864
+
865
+ err. multipart_suggestion (
866
+ "try removing the generic parameter and using `impl Trait` instead" ,
867
+ vec ! [
868
+ // delete generic parameters
869
+ ( impl_m. generics. span, String :: new( ) ) ,
870
+ // replace param usage with `impl Trait`
871
+ ( span, format!( "impl {}" , bounds) ) ,
872
+ ] ,
873
+ ) ;
874
+ Some ( ( ) )
875
+ } ) ( ) ;
876
+ } ,
877
+ _ => unreachable ! ( ) ,
878
+ }
756
879
err. emit ( ) ;
757
880
error_found = true ;
758
881
}
0 commit comments