@@ -755,15 +755,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
755755 }
756756
757757 errors. drain_filter ( |error| {
758- let Error :: Invalid ( provided_idx, expected_idx, Compatibility :: Incompatible ( Some ( e) ) ) = error else { return false } ;
759- let ( provided_ty, provided_span) = provided_arg_tys[ * provided_idx] ;
760- let trace = mk_trace ( provided_span, formal_and_expected_inputs[ * expected_idx] , provided_ty) ;
761- if !matches ! ( trace. cause. as_failure_code( * e) , FailureCode :: Error0308 ( _) ) {
762- self . err_ctxt ( ) . report_and_explain_type_error ( trace, * e) . emit ( ) ;
763- return true ;
764- }
765- false
766- } ) ;
758+ let Error :: Invalid (
759+ provided_idx,
760+ expected_idx,
761+ Compatibility :: Incompatible ( Some ( e) ) ,
762+ ) = error else { return false } ;
763+ let ( provided_ty, provided_span) = provided_arg_tys[ * provided_idx] ;
764+ let trace = mk_trace (
765+ provided_span,
766+ formal_and_expected_inputs[ * expected_idx] ,
767+ provided_ty,
768+ ) ;
769+ if !matches ! ( trace. cause. as_failure_code( * e) , FailureCode :: Error0308 ( _) ) {
770+ self . err_ctxt ( ) . report_and_explain_type_error ( trace, * e) . emit ( ) ;
771+ return true ;
772+ }
773+ false
774+ } ) ;
767775
768776 // We're done if we found errors, but we already emitted them.
769777 if errors. is_empty ( ) {
@@ -864,7 +872,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
864872 }
865873 let mut suggestion_text = SuggestionText :: None ;
866874
875+ let ty_to_snippet = |ty : Ty < ' tcx > , expected_idx : ExpectedIdx | {
876+ if ty. is_unit ( ) {
877+ "()" . to_string ( )
878+ } else if ty. is_suggestable ( tcx, false ) {
879+ format ! ( "/* {} */" , ty)
880+ } else if let Some ( fn_def_id) = fn_def_id
881+ && self . tcx . def_kind ( fn_def_id) . is_fn_like ( )
882+ && let self_implicit =
883+ matches ! ( call_expr. kind, hir:: ExprKind :: MethodCall ( ..) ) as usize
884+ && let Some ( arg) = self . tcx . fn_arg_names ( fn_def_id)
885+ . get ( expected_idx. as_usize ( ) + self_implicit)
886+ && arg. name != kw:: SelfLower
887+ {
888+ format ! ( "/* {} */" , arg. name)
889+ } else {
890+ "/* value */" . to_string ( )
891+ }
892+ } ;
893+
867894 let mut errors = errors. into_iter ( ) . peekable ( ) ;
895+ let mut suggestions = vec ! [ ] ;
868896 while let Some ( error) = errors. next ( ) {
869897 match error {
870898 Error :: Invalid ( provided_idx, expected_idx, compatibility) => {
@@ -906,6 +934,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
906934 } ;
907935 labels
908936 . push ( ( provided_span, format ! ( "argument{} unexpected" , provided_ty_name) ) ) ;
937+ let mut span = provided_span;
938+ if let Some ( ( _, next) ) = provided_arg_tys. get (
939+ ProvidedIdx :: from_usize ( arg_idx. index ( ) + 1 ) ,
940+ ) {
941+ // Include next comma
942+ span = span. until ( * next) ;
943+ } else if arg_idx. index ( ) > 0
944+ && let Some ( ( _, prev) ) = provided_arg_tys
945+ . get ( ProvidedIdx :: from_usize ( arg_idx. index ( ) - 1 )
946+ ) {
947+ // Last argument, include previous comma
948+ span = span. with_lo ( prev. hi ( ) ) ;
949+ }
950+ suggestions. push ( ( span, String :: new ( ) ) ) ;
951+
909952 suggestion_text = match suggestion_text {
910953 SuggestionText :: None => SuggestionText :: Remove ( false ) ,
911954 SuggestionText :: Remove ( _) => SuggestionText :: Remove ( true ) ,
@@ -1095,6 +1138,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10951138 }
10961139 }
10971140
1141+ // Incorporate the argument changes in the removal suggestion.
1142+ let mut prev = -1 ;
1143+ for ( expected_idx, provided_idx) in matched_inputs. iter_enumerated ( ) {
1144+ if let Some ( provided_idx) = provided_idx {
1145+ prev = provided_idx. index ( ) as i64 ;
1146+ }
1147+ let idx = ProvidedIdx :: from_usize ( ( prev + 1 ) as usize ) ;
1148+ if let None = provided_idx
1149+ && let Some ( ( _, arg_span) ) = provided_arg_tys. get ( idx)
1150+ {
1151+ let ( _, expected_ty) = formal_and_expected_inputs[ expected_idx] ;
1152+ suggestions. push ( ( * arg_span, ty_to_snippet ( expected_ty, expected_idx) ) ) ;
1153+ }
1154+ }
1155+
10981156 // If we have less than 5 things to say, it would be useful to call out exactly what's wrong
10991157 if labels. len ( ) <= 5 {
11001158 for ( span, label) in labels {
@@ -1112,7 +1170,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11121170 Some ( format ! ( "provide the argument{}" , if plural { "s" } else { "" } ) )
11131171 }
11141172 SuggestionText :: Remove ( plural) => {
1115- Some ( format ! ( "remove the extra argument{}" , if plural { "s" } else { "" } ) )
1173+ err. multipart_suggestion_verbose (
1174+ & format ! ( "remove the extra argument{}" , if plural { "s" } else { "" } ) ,
1175+ suggestions,
1176+ Applicability :: HasPlaceholders ,
1177+ ) ;
1178+ None
11161179 }
11171180 SuggestionText :: Swap => Some ( "swap these arguments" . to_string ( ) ) ,
11181181 SuggestionText :: Reorder => Some ( "reorder these arguments" . to_string ( ) ) ,
@@ -1151,20 +1214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11511214 } else {
11521215 // Propose a placeholder of the correct type
11531216 let ( _, expected_ty) = formal_and_expected_inputs[ expected_idx] ;
1154- if expected_ty. is_unit ( ) {
1155- "()" . to_string ( )
1156- } else if expected_ty. is_suggestable ( tcx, false ) {
1157- format ! ( "/* {} */" , expected_ty)
1158- } else if let Some ( fn_def_id) = fn_def_id
1159- && self . tcx . def_kind ( fn_def_id) . is_fn_like ( )
1160- && let self_implicit = matches ! ( call_expr. kind, hir:: ExprKind :: MethodCall ( ..) ) as usize
1161- && let Some ( arg) = self . tcx . fn_arg_names ( fn_def_id) . get ( expected_idx. as_usize ( ) + self_implicit)
1162- && arg. name != kw:: SelfLower
1163- {
1164- format ! ( "/* {} */" , arg. name)
1165- } else {
1166- "/* value */" . to_string ( )
1167- }
1217+ ty_to_snippet ( expected_ty, expected_idx)
11681218 } ;
11691219 suggestion += & suggestion_text;
11701220 }
0 commit comments