@@ -755,15 +755,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
755
755
}
756
756
757
757
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
+ } ) ;
767
775
768
776
// We're done if we found errors, but we already emitted them.
769
777
if errors. is_empty ( ) {
@@ -864,7 +872,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
864
872
}
865
873
let mut suggestion_text = SuggestionText :: None ;
866
874
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
+
867
894
let mut errors = errors. into_iter ( ) . peekable ( ) ;
895
+ let mut suggestions = vec ! [ ] ;
868
896
while let Some ( error) = errors. next ( ) {
869
897
match error {
870
898
Error :: Invalid ( provided_idx, expected_idx, compatibility) => {
@@ -906,6 +934,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
906
934
} ;
907
935
labels
908
936
. 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
+
909
952
suggestion_text = match suggestion_text {
910
953
SuggestionText :: None => SuggestionText :: Remove ( false ) ,
911
954
SuggestionText :: Remove ( _) => SuggestionText :: Remove ( true ) ,
@@ -1095,6 +1138,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1095
1138
}
1096
1139
}
1097
1140
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
+
1098
1156
// If we have less than 5 things to say, it would be useful to call out exactly what's wrong
1099
1157
if labels. len ( ) <= 5 {
1100
1158
for ( span, label) in labels {
@@ -1112,7 +1170,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1112
1170
Some ( format ! ( "provide the argument{}" , if plural { "s" } else { "" } ) )
1113
1171
}
1114
1172
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
1116
1179
}
1117
1180
SuggestionText :: Swap => Some ( "swap these arguments" . to_string ( ) ) ,
1118
1181
SuggestionText :: Reorder => Some ( "reorder these arguments" . to_string ( ) ) ,
@@ -1151,20 +1214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1151
1214
} else {
1152
1215
// Propose a placeholder of the correct type
1153
1216
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)
1168
1218
} ;
1169
1219
suggestion += & suggestion_text;
1170
1220
}
0 commit comments