@@ -28,6 +28,11 @@ use crate::structured_errors::StructuredDiagnostic;
28
28
use std:: iter;
29
29
use std:: slice;
30
30
31
+ enum FnArgsAsTuple < ' hir > {
32
+ Single ( & ' hir hir:: Expr < ' hir > ) ,
33
+ Multi { first : & ' hir hir:: Expr < ' hir > , last : & ' hir hir:: Expr < ' hir > } ,
34
+ }
35
+
31
36
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
32
37
pub ( in super :: super ) fn check_casts ( & self ) {
33
38
let mut deferred_cast_checks = self . deferred_cast_checks . borrow_mut ( ) ;
@@ -127,8 +132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
127
132
128
133
let expected_arg_count = formal_input_tys. len ( ) ;
129
134
130
- // expected_count, arg_count, error_code, sugg_unit
131
- let mut error: Option < ( usize , usize , & str , bool ) > = None ;
135
+ // expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args
136
+ let mut error: Option < ( usize , usize , & str , bool , Option < FnArgsAsTuple < ' _ > > ) > = None ;
132
137
133
138
// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
134
139
let ( formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
@@ -138,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
138
143
ty:: Tuple ( arg_types) => {
139
144
// Argument length differs
140
145
if arg_types. len ( ) != provided_args. len ( ) {
141
- error = Some ( ( arg_types. len ( ) , provided_args. len ( ) , "E0057" , false ) ) ;
146
+ error = Some ( ( arg_types. len ( ) , provided_args. len ( ) , "E0057" , false , None ) ) ;
142
147
}
143
148
let expected_input_tys = match expected_input_tys. get ( 0 ) {
144
149
Some ( & ty) => match ty. kind ( ) {
@@ -169,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
169
174
if supplied_arg_count >= expected_arg_count {
170
175
( formal_input_tys. to_vec ( ) , expected_input_tys)
171
176
} else {
172
- error = Some ( ( expected_arg_count, supplied_arg_count, "E0060" , false ) ) ;
177
+ error = Some ( ( expected_arg_count, supplied_arg_count, "E0060" , false , None ) ) ;
173
178
( self . err_args ( supplied_arg_count) , vec ! [ ] )
174
179
}
175
180
} else {
@@ -181,7 +186,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
181
186
} else {
182
187
false
183
188
} ;
184
- error = Some ( ( expected_arg_count, supplied_arg_count, "E0061" , sugg_unit) ) ;
189
+
190
+ // are we passing elements of a tuple without the tuple parentheses?
191
+ let chosen_arg_tys = if expected_input_tys. is_empty ( ) {
192
+ // In most cases we can use expected_arg_tys, but some callers won't have the type
193
+ // information, in which case we fall back to the types from the input expressions.
194
+ formal_input_tys
195
+ } else {
196
+ & * expected_input_tys
197
+ } ;
198
+
199
+ let sugg_tuple_wrap_args = chosen_arg_tys
200
+ . get ( 0 )
201
+ . cloned ( )
202
+ . map ( |arg_ty| self . resolve_vars_if_possible ( arg_ty) )
203
+ . and_then ( |arg_ty| match arg_ty. kind ( ) {
204
+ ty:: Tuple ( tup_elems) => Some ( tup_elems) ,
205
+ _ => None ,
206
+ } )
207
+ . and_then ( |tup_elems| {
208
+ if tup_elems. len ( ) == supplied_arg_count && chosen_arg_tys. len ( ) == 1 {
209
+ match provided_args {
210
+ [ ] => None ,
211
+ [ single] => Some ( FnArgsAsTuple :: Single ( single) ) ,
212
+ [ first, .., last] => Some ( FnArgsAsTuple :: Multi { first, last } ) ,
213
+ }
214
+ } else {
215
+ None
216
+ }
217
+ } ) ;
218
+
219
+ error = Some ( (
220
+ expected_arg_count,
221
+ supplied_arg_count,
222
+ "E0061" ,
223
+ sugg_unit,
224
+ sugg_tuple_wrap_args,
225
+ ) ) ;
185
226
( self . err_args ( supplied_arg_count) , vec ! [ ] )
186
227
} ;
187
228
@@ -305,7 +346,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
305
346
}
306
347
307
348
// If there was an error in parameter count, emit that here
308
- if let Some ( ( expected_count, arg_count, err_code, sugg_unit) ) = error {
349
+ if let Some ( ( expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args) ) = error
350
+ {
309
351
let ( span, start_span, args, ctor_of) = match & call_expr. kind {
310
352
hir:: ExprKind :: Call (
311
353
hir:: Expr {
@@ -408,6 +450,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408
450
String :: from ( "()" ) ,
409
451
Applicability :: MachineApplicable ,
410
452
) ;
453
+ } else if let Some ( tuple_fn_arg) = sugg_tuple_wrap_args {
454
+ use FnArgsAsTuple :: * ;
455
+
456
+ let spans = match tuple_fn_arg {
457
+ Multi { first, last } => vec ! [
458
+ ( first. span. shrink_to_lo( ) , '(' . to_string( ) ) ,
459
+ ( last. span. shrink_to_hi( ) , ')' . to_string( ) ) ,
460
+ ] ,
461
+ Single ( single) => vec ! [
462
+ ( single. span. shrink_to_lo( ) , '(' . to_string( ) ) ,
463
+ ( single. span. shrink_to_hi( ) , ",)" . to_string( ) ) ,
464
+ ] ,
465
+ } ;
466
+
467
+ err. multipart_suggestion (
468
+ "use parentheses to construct a tuple" ,
469
+ spans,
470
+ Applicability :: MachineApplicable ,
471
+ ) ;
411
472
} else {
412
473
err. span_label (
413
474
span,
0 commit comments