@@ -28,6 +28,11 @@ use crate::structured_errors::StructuredDiagnostic;
2828use std:: iter;
2929use std:: slice;
3030
31+ enum FnArgsAsTuple < ' hir > {
32+ Single ( & ' hir hir:: Expr < ' hir > ) ,
33+ Multi { first : & ' hir hir:: Expr < ' hir > , last : & ' hir hir:: Expr < ' hir > } ,
34+ }
35+
3136impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
3237 pub ( in super :: super ) fn check_casts ( & self ) {
3338 let mut deferred_cast_checks = self . deferred_cast_checks . borrow_mut ( ) ;
@@ -127,8 +132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
127132
128133 let expected_arg_count = formal_input_tys. len ( ) ;
129134
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 ;
132137
133138 // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
134139 let ( formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
@@ -138,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
138143 ty:: Tuple ( arg_types) => {
139144 // Argument length differs
140145 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 ) ) ;
142147 }
143148 let expected_input_tys = match expected_input_tys. get ( 0 ) {
144149 Some ( & ty) => match ty. kind ( ) {
@@ -169,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
169174 if supplied_arg_count >= expected_arg_count {
170175 ( formal_input_tys. to_vec ( ) , expected_input_tys)
171176 } else {
172- error = Some ( ( expected_arg_count, supplied_arg_count, "E0060" , false ) ) ;
177+ error = Some ( ( expected_arg_count, supplied_arg_count, "E0060" , false , None ) ) ;
173178 ( self . err_args ( supplied_arg_count) , vec ! [ ] )
174179 }
175180 } else {
@@ -181,7 +186,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
181186 } else {
182187 false
183188 } ;
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+ ) ) ;
185226 ( self . err_args ( supplied_arg_count) , vec ! [ ] )
186227 } ;
187228
@@ -305,7 +346,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
305346 }
306347
307348 // 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+ {
309351 let ( span, start_span, args, ctor_of) = match & call_expr. kind {
310352 hir:: ExprKind :: Call (
311353 hir:: Expr {
@@ -408,6 +450,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408450 String :: from ( "()" ) ,
409451 Applicability :: MachineApplicable ,
410452 ) ;
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+ ) ;
411472 } else {
412473 err. span_label (
413474 span,
0 commit comments