@@ -764,23 +764,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
764
764
// // found_trait_ref: std::ops::FnMut<(&i32,)>
765
765
// ```
766
766
767
- let closure_args_span = found_did. and_then ( |did| self . tcx . hir . get_if_local ( did) )
767
+ let ( closure_span, closure_args) = found_did
768
+ . and_then ( |did| self . tcx . hir . get_if_local ( did) )
768
769
. and_then ( |node| {
769
770
if let hir:: map:: NodeExpr (
770
- & hir:: Expr { node : hir:: ExprClosure ( _, _, _, span, _) , .. } ) = node
771
+ & hir:: Expr {
772
+ node : hir:: ExprClosure ( _, ref decl, id, span, _) ,
773
+ ..
774
+ } ) = node
771
775
{
772
- Some ( span)
776
+ let ty_snips = decl. inputs . iter ( )
777
+ . map ( |ty| {
778
+ self . tcx . sess . codemap ( ) . span_to_snippet ( ty. span ) . ok ( )
779
+ . and_then ( |snip| {
780
+ // filter out dummy spans
781
+ if snip == "," || snip == "|" {
782
+ None
783
+ } else {
784
+ Some ( snip)
785
+ }
786
+ } )
787
+ } )
788
+ . collect :: < Vec < Option < String > > > ( ) ;
789
+
790
+ let body = self . tcx . hir . body ( id) ;
791
+ let pat_snips = body. arguments . iter ( )
792
+ . map ( |arg|
793
+ self . tcx . sess . codemap ( ) . span_to_snippet ( arg. pat . span ) . ok ( ) )
794
+ . collect :: < Option < Vec < String > > > ( ) ;
795
+
796
+ Some ( ( span, pat_snips, ty_snips) )
773
797
} else {
774
798
None
775
799
}
776
- } ) ;
800
+ } )
801
+ . map ( |( span, pat, ty) | ( Some ( span) , Some ( ( pat, ty) ) ) )
802
+ . unwrap_or ( ( None , None ) ) ;
803
+ let closure_args = closure_args. and_then ( |( pat, ty) | Some ( ( pat?, ty) ) ) ;
777
804
778
805
self . report_arg_count_mismatch (
779
806
span,
780
- closure_args_span . or ( found_span) ,
807
+ closure_span . or ( found_span) ,
781
808
expected_ty_count,
782
809
expected_tuple,
783
810
found_ty_count,
811
+ closure_args,
784
812
found_trait_ty. is_closure ( )
785
813
)
786
814
}
@@ -803,44 +831,85 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
803
831
err. emit ( ) ;
804
832
}
805
833
806
- fn report_arg_count_mismatch ( & self ,
807
- span : Span ,
808
- found_span : Option < Span > ,
809
- expected : usize ,
810
- expected_tuple : Option < usize > ,
811
- found : usize ,
812
- is_closure : bool )
813
- -> DiagnosticBuilder < ' tcx >
814
- {
834
+ fn report_arg_count_mismatch (
835
+ & self ,
836
+ span : Span ,
837
+ found_span : Option < Span > ,
838
+ expected : usize ,
839
+ expected_tuple : Option < usize > ,
840
+ found : usize ,
841
+ closure_args : Option < ( Vec < String > , Vec < Option < String > > ) > ,
842
+ is_closure : bool
843
+ ) -> DiagnosticBuilder < ' tcx > {
844
+ use std:: borrow:: Cow ;
845
+
815
846
let kind = if is_closure { "closure" } else { "function" } ;
816
847
817
- let tuple_or_args = |tuple, args| if let Some ( n) = tuple {
818
- format ! ( "a {}-tuple" , n)
819
- } else {
820
- format ! (
848
+ let args_str = |n| format ! (
821
849
"{} argument{}" ,
822
- args,
823
- if args == 1 { "" } else { "s" }
824
- )
825
- } ;
826
-
827
- let found_str = tuple_or_args ( None , found) ;
828
- let expected_str = tuple_or_args ( expected_tuple, expected) ;
850
+ n,
851
+ if n == 1 { "" } else { "s" }
852
+ ) ;
829
853
830
854
let mut err = struct_span_err ! ( self . tcx. sess, span, E0593 ,
831
- "{} takes {} but {} {} required" ,
855
+ "{} takes {}, but {} {} required" ,
832
856
kind,
833
- found_str,
834
- expected_str,
835
- if expected_tuple. is_some( ) || expected == 1 { "is" } else { "are" } ) ;
857
+ if expected_tuple. is_some( ) {
858
+ Cow :: from( "multiple arguments" )
859
+ } else {
860
+ Cow :: from( args_str( found) )
861
+ } ,
862
+ if expected_tuple. is_some( ) {
863
+ Cow :: from( "a tuple argument" )
864
+ } else {
865
+ Cow :: from( args_str( expected) )
866
+ } ,
867
+ if expected == 1 { "is" } else { "are" } ) ;
836
868
837
869
err. span_label (
838
870
span,
839
- format ! ( "expected {} that takes {}" , kind, expected_str)
871
+ format ! (
872
+ "expected {} that takes {}{}" ,
873
+ kind,
874
+ args_str( expected) ,
875
+ if let Some ( n) = expected_tuple {
876
+ assert!( expected == 1 ) ;
877
+ Cow :: from( format!( ", a {}-tuple" , n) )
878
+ } else {
879
+ Cow :: from( "" )
880
+ }
881
+ )
840
882
) ;
841
883
842
884
if let Some ( span) = found_span {
843
- err. span_label ( span, format ! ( "takes {}" , found_str) ) ;
885
+ if let ( Some ( expected_tuple) , Some ( ( pats, tys) ) ) = ( expected_tuple, closure_args) {
886
+ if expected_tuple != found || pats. len ( ) != found {
887
+ err. span_label ( span, format ! ( "takes {}" , args_str( found) ) ) ;
888
+ } else {
889
+ let sugg = format ! (
890
+ "|({}){}|" ,
891
+ pats. join( ", " ) ,
892
+
893
+ // add type annotations if available
894
+ if tys. iter( ) . any( |ty| ty. is_some( ) ) {
895
+ Cow :: from( format!(
896
+ ": ({})" ,
897
+ tys. into_iter( ) . map( |ty| if let Some ( ty) = ty {
898
+ ty
899
+ } else {
900
+ "_" . to_string( )
901
+ } ) . collect:: <Vec <String >>( ) . join( ", " )
902
+ ) )
903
+ } else {
904
+ Cow :: from( "" )
905
+ } ,
906
+ ) ;
907
+
908
+ err. span_suggestion ( span, "consider changing to" , sugg) ;
909
+ }
910
+ } else {
911
+ err. span_label ( span, format ! ( "takes {}" , args_str( found) ) ) ;
912
+ }
844
913
}
845
914
846
915
err
0 commit comments