@@ -764,23 +764,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
764764 // // found_trait_ref: std::ops::FnMut<(&i32,)>
765765 // ```
766766
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) )
768769 . and_then ( |node| {
769770 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
771775 {
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) )
773797 } else {
774798 None
775799 }
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) ) ) ;
777804
778805 self . report_arg_count_mismatch (
779806 span,
780- closure_args_span . or ( found_span) ,
807+ closure_span . or ( found_span) ,
781808 expected_ty_count,
782809 expected_tuple,
783810 found_ty_count,
811+ closure_args,
784812 found_trait_ty. is_closure ( )
785813 )
786814 }
@@ -803,44 +831,85 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
803831 err. emit ( ) ;
804832 }
805833
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+
815846 let kind = if is_closure { "closure" } else { "function" } ;
816847
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 ! (
821849 "{} 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+ ) ;
829853
830854 let mut err = struct_span_err ! ( self . tcx. sess, span, E0593 ,
831- "{} takes {} but {} {} required" ,
855+ "{} takes {}, but {} {} required" ,
832856 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" } ) ;
836868
837869 err. span_label (
838870 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+ )
840882 ) ;
841883
842884 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+ }
844913 }
845914
846915 err
0 commit comments