@@ -127,136 +127,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
127
127
128
128
let expected_arg_count = formal_input_tys. len ( ) ;
129
129
130
- let param_count_error = |expected_count : usize ,
131
- arg_count : usize ,
132
- error_code : & str ,
133
- c_variadic : bool ,
134
- sugg_unit : bool | {
135
- let ( span, start_span, args, ctor_of) = match & call_expr. kind {
136
- hir:: ExprKind :: Call (
137
- hir:: Expr {
138
- span,
139
- kind :
140
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
141
- _,
142
- hir:: Path { res : Res :: Def ( DefKind :: Ctor ( of, _) , _) , .. } ,
143
- ) ) ,
144
- ..
145
- } ,
146
- args,
147
- ) => ( * span, * span, & args[ ..] , Some ( of) ) ,
148
- hir:: ExprKind :: Call ( hir:: Expr { span, .. } , args) => {
149
- ( * span, * span, & args[ ..] , None )
150
- }
151
- hir:: ExprKind :: MethodCall ( path_segment, args, _) => (
152
- path_segment. ident . span ,
153
- // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
154
- path_segment
155
- . args
156
- . and_then ( |args| args. args . iter ( ) . last ( ) )
157
- // Account for `foo.bar::<T>()`.
158
- . map ( |arg| {
159
- // Skip the closing `>`.
160
- tcx. sess
161
- . source_map ( )
162
- . next_point ( tcx. sess . source_map ( ) . next_point ( arg. span ( ) ) )
163
- } )
164
- . unwrap_or ( path_segment. ident . span ) ,
165
- & args[ 1 ..] , // Skip the receiver.
166
- None , // methods are never ctors
167
- ) ,
168
- k => span_bug ! ( call_span, "checking argument types on a non-call: `{:?}`" , k) ,
169
- } ;
170
- let arg_spans = if provided_args. is_empty ( ) {
171
- // foo()
172
- // ^^^-- supplied 0 arguments
173
- // |
174
- // expected 2 arguments
175
- vec ! [ tcx. sess. source_map( ) . next_point( start_span) . with_hi( call_span. hi( ) ) ]
176
- } else {
177
- // foo(1, 2, 3)
178
- // ^^^ - - - supplied 3 arguments
179
- // |
180
- // expected 2 arguments
181
- args. iter ( ) . map ( |arg| arg. span ) . collect :: < Vec < Span > > ( )
182
- } ;
183
-
184
- let mut err = tcx. sess . struct_span_err_with_code (
185
- span,
186
- & format ! (
187
- "this {} takes {}{} but {} {} supplied" ,
188
- match ctor_of {
189
- Some ( CtorOf :: Struct ) => "struct" ,
190
- Some ( CtorOf :: Variant ) => "enum variant" ,
191
- None => "function" ,
192
- } ,
193
- if c_variadic { "at least " } else { "" } ,
194
- potentially_plural_count( expected_count, "argument" ) ,
195
- potentially_plural_count( arg_count, "argument" ) ,
196
- if arg_count == 1 { "was" } else { "were" }
197
- ) ,
198
- DiagnosticId :: Error ( error_code. to_owned ( ) ) ,
199
- ) ;
200
- let label = format ! ( "supplied {}" , potentially_plural_count( arg_count, "argument" ) ) ;
201
- for ( i, span) in arg_spans. into_iter ( ) . enumerate ( ) {
202
- err. span_label (
203
- span,
204
- if arg_count == 0 || i + 1 == arg_count { & label } else { "" } ,
205
- ) ;
206
- }
207
-
208
- if let Some ( def_id) = fn_def_id {
209
- if let Some ( def_span) = tcx. def_ident_span ( def_id) {
210
- let mut spans: MultiSpan = def_span. into ( ) ;
211
-
212
- let params = tcx
213
- . hir ( )
214
- . get_if_local ( def_id)
215
- . and_then ( |node| node. body_id ( ) )
216
- . into_iter ( )
217
- . map ( |id| tcx. hir ( ) . body ( id) . params )
218
- . flatten ( ) ;
219
-
220
- for param in params {
221
- spans. push_span_label ( param. span , String :: new ( ) ) ;
222
- }
223
-
224
- let def_kind = tcx. def_kind ( def_id) ;
225
- err. span_note ( spans, & format ! ( "{} defined here" , def_kind. descr( def_id) ) ) ;
226
- }
227
- }
228
-
229
- if sugg_unit {
230
- let sugg_span = tcx. sess . source_map ( ) . end_point ( call_expr. span ) ;
231
- // remove closing `)` from the span
232
- let sugg_span = sugg_span. shrink_to_lo ( ) ;
233
- err. span_suggestion (
234
- sugg_span,
235
- "expected the unit value `()`; create it with empty parentheses" ,
236
- String :: from ( "()" ) ,
237
- Applicability :: MachineApplicable ,
238
- ) ;
239
- } else {
240
- err. span_label (
241
- span,
242
- format ! (
243
- "expected {}{}" ,
244
- if c_variadic { "at least " } else { "" } ,
245
- potentially_plural_count( expected_count, "argument" )
246
- ) ,
247
- ) ;
248
- }
249
- err. emit ( ) ;
250
- } ;
130
+ // expected_count, arg_count, error_code, sugg_unit
131
+ let mut error: Option < ( usize , usize , & str , bool ) > = None ;
251
132
133
+ // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
252
134
let ( formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
253
135
let tuple_type = self . structurally_resolved_type ( call_span, formal_input_tys[ 0 ] ) ;
254
136
match tuple_type. kind ( ) {
255
- ty:: Tuple ( arg_types) if arg_types. len ( ) != provided_args. len ( ) => {
256
- param_count_error ( arg_types. len ( ) , provided_args. len ( ) , "E0057" , false , false ) ;
257
- ( self . err_args ( provided_args. len ( ) ) , vec ! [ ] )
258
- }
137
+ // We expected a tuple and got a tuple
259
138
ty:: Tuple ( arg_types) => {
139
+ // Argument length differs
140
+ if arg_types. len ( ) != provided_args. len ( ) {
141
+ error = Some ( ( arg_types. len ( ) , provided_args. len ( ) , "E0057" , false ) ) ;
142
+ }
260
143
let expected_input_tys = match expected_input_tys. get ( 0 ) {
261
144
Some ( & ty) => match ty. kind ( ) {
262
145
ty:: Tuple ( ref tys) => tys. iter ( ) . map ( |k| k. expect_ty ( ) ) . collect ( ) ,
@@ -267,6 +150,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
267
150
( arg_types. iter ( ) . map ( |k| k. expect_ty ( ) ) . collect ( ) , expected_input_tys)
268
151
}
269
152
_ => {
153
+ // Otherwise, there's a mismatch, so clear out what we're expecting, and set
154
+ // our input typs to err_args so we don't blow up the error messages
270
155
struct_span_err ! (
271
156
tcx. sess,
272
157
call_span,
@@ -284,7 +169,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
284
169
if supplied_arg_count >= expected_arg_count {
285
170
( formal_input_tys. to_vec ( ) , expected_input_tys)
286
171
} else {
287
- param_count_error ( expected_arg_count, supplied_arg_count, "E0060" , true , false ) ;
172
+ error = Some ( ( expected_arg_count, supplied_arg_count, "E0060" , false ) ) ;
288
173
( self . err_args ( supplied_arg_count) , vec ! [ ] )
289
174
}
290
175
} else {
@@ -296,8 +181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
296
181
} else {
297
182
false
298
183
} ;
299
- param_count_error ( expected_arg_count, supplied_arg_count, "E0061" , false , sugg_unit) ;
300
-
184
+ error = Some ( ( expected_arg_count, supplied_arg_count, "E0061" , sugg_unit) ) ;
301
185
( self . err_args ( supplied_arg_count) , vec ! [ ] )
302
186
} ;
303
187
@@ -315,13 +199,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
315
199
316
200
assert_eq ! ( expected_input_tys. len( ) , formal_input_tys. len( ) ) ;
317
201
202
+ let provided_arg_count: usize = provided_args. len ( ) ;
203
+
318
204
// Keep track of the fully coerced argument types
319
- let mut final_arg_types: Vec < ( usize , Ty < ' _ > , Ty < ' _ > ) > = vec ! [ ] ;
205
+ let mut final_arg_types: Vec < Option < ( Ty < ' _ > , Ty < ' _ > ) > > = vec ! [ None ; provided_arg_count ] ;
320
206
321
207
// We introduce a helper function to demand that a given argument satisfy a given input
322
208
// This is more complicated than just checking type equality, as arguments could be coerced
323
209
// This version writes those types back so further type checking uses the narrowed types
324
- let demand_compatible = |idx, final_arg_types : & mut Vec < ( usize , Ty < ' tcx > , Ty < ' tcx > ) > | {
210
+ let demand_compatible = |idx, final_arg_types : & mut Vec < Option < ( Ty < ' tcx > , Ty < ' tcx > ) > > | {
325
211
let formal_input_ty: Ty < ' tcx > = formal_input_tys[ idx] ;
326
212
let expected_input_ty: Ty < ' tcx > = expected_input_tys[ idx] ;
327
213
let provided_arg = & provided_args[ idx] ;
@@ -340,13 +226,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
340
226
let coerced_ty = expectation. only_has_type ( self ) . unwrap_or ( formal_input_ty) ;
341
227
342
228
// Keep track of these for below
343
- final_arg_types. push ( ( idx, checked_ty, coerced_ty) ) ;
229
+ final_arg_types[ idx] = Some ( ( checked_ty, coerced_ty) ) ;
344
230
345
231
// Cause selection errors caused by resolving a single argument to point at the
346
232
// argument and not the call. This is otherwise redundant with the `demand_coerce`
347
233
// call immediately after, but it lets us customize the span pointed to in the
348
234
// fulfillment error to be more accurate.
349
- let _ =
235
+ let coerced_ty =
350
236
self . resolve_vars_with_obligations_and_mutate_fulfillment ( coerced_ty, |errors| {
351
237
self . point_at_type_arg_instead_of_call_if_possible ( errors, call_expr) ;
352
238
self . point_at_arg_instead_of_call_if_possible (
@@ -358,6 +244,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
358
244
) ;
359
245
} ) ;
360
246
247
+ final_arg_types[ idx] = Some ( ( checked_ty, coerced_ty) ) ;
248
+
361
249
// We're processing function arguments so we definitely want to use
362
250
// two-phase borrows.
363
251
self . demand_coerce ( & provided_arg, checked_ty, coerced_ty, None , AllowTwoPhase :: Yes ) ;
@@ -416,6 +304,123 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
416
304
}
417
305
}
418
306
307
+ // If there was an error in parameter count, emit that here
308
+ if let Some ( ( expected_count, arg_count, err_code, sugg_unit) ) = error {
309
+ let ( span, start_span, args, ctor_of) = match & call_expr. kind {
310
+ hir:: ExprKind :: Call (
311
+ hir:: Expr {
312
+ span,
313
+ kind :
314
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
315
+ _,
316
+ hir:: Path { res : Res :: Def ( DefKind :: Ctor ( of, _) , _) , .. } ,
317
+ ) ) ,
318
+ ..
319
+ } ,
320
+ args,
321
+ ) => ( * span, * span, & args[ ..] , Some ( of) ) ,
322
+ hir:: ExprKind :: Call ( hir:: Expr { span, .. } , args) => {
323
+ ( * span, * span, & args[ ..] , None )
324
+ }
325
+ hir:: ExprKind :: MethodCall ( path_segment, args, _) => (
326
+ path_segment. ident . span ,
327
+ // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
328
+ path_segment
329
+ . args
330
+ . and_then ( |args| args. args . iter ( ) . last ( ) )
331
+ // Account for `foo.bar::<T>()`.
332
+ . map ( |arg| {
333
+ // Skip the closing `>`.
334
+ tcx. sess
335
+ . source_map ( )
336
+ . next_point ( tcx. sess . source_map ( ) . next_point ( arg. span ( ) ) )
337
+ } )
338
+ . unwrap_or ( path_segment. ident . span ) ,
339
+ & args[ 1 ..] , // Skip the receiver.
340
+ None , // methods are never ctors
341
+ ) ,
342
+ k => span_bug ! ( call_span, "checking argument types on a non-call: `{:?}`" , k) ,
343
+ } ;
344
+ let arg_spans = if provided_args. is_empty ( ) {
345
+ // foo()
346
+ // ^^^-- supplied 0 arguments
347
+ // |
348
+ // expected 2 arguments
349
+ vec ! [ tcx. sess. source_map( ) . next_point( start_span) . with_hi( call_span. hi( ) ) ]
350
+ } else {
351
+ // foo(1, 2, 3)
352
+ // ^^^ - - - supplied 3 arguments
353
+ // |
354
+ // expected 2 arguments
355
+ args. iter ( ) . map ( |arg| arg. span ) . collect :: < Vec < Span > > ( )
356
+ } ;
357
+ let call_name = match ctor_of {
358
+ Some ( CtorOf :: Struct ) => "struct" ,
359
+ Some ( CtorOf :: Variant ) => "enum variant" ,
360
+ None => "function" ,
361
+ } ;
362
+ let mut err = tcx. sess . struct_span_err_with_code (
363
+ span,
364
+ & format ! (
365
+ "this {} takes {}{} but {} {} supplied" ,
366
+ call_name,
367
+ if c_variadic { "at least " } else { "" } ,
368
+ potentially_plural_count( expected_count, "argument" ) ,
369
+ potentially_plural_count( arg_count, "argument" ) ,
370
+ if arg_count == 1 { "was" } else { "were" }
371
+ ) ,
372
+ DiagnosticId :: Error ( err_code. to_owned ( ) ) ,
373
+ ) ;
374
+ let label = format ! ( "supplied {}" , potentially_plural_count( arg_count, "argument" ) ) ;
375
+ for ( i, span) in arg_spans. into_iter ( ) . enumerate ( ) {
376
+ err. span_label (
377
+ span,
378
+ if arg_count == 0 || i + 1 == arg_count { & label } else { "" } ,
379
+ ) ;
380
+ }
381
+ if let Some ( def_id) = fn_def_id {
382
+ if let Some ( def_span) = tcx. def_ident_span ( def_id) {
383
+ let mut spans: MultiSpan = def_span. into ( ) ;
384
+
385
+ let params = tcx
386
+ . hir ( )
387
+ . get_if_local ( def_id)
388
+ . and_then ( |node| node. body_id ( ) )
389
+ . into_iter ( )
390
+ . map ( |id| tcx. hir ( ) . body ( id) . params )
391
+ . flatten ( ) ;
392
+
393
+ for param in params {
394
+ spans. push_span_label ( param. span , String :: new ( ) ) ;
395
+ }
396
+
397
+ let def_kind = tcx. def_kind ( def_id) ;
398
+ err. span_note ( spans, & format ! ( "{} defined here" , def_kind. descr( def_id) ) ) ;
399
+ }
400
+ }
401
+ if sugg_unit {
402
+ let sugg_span = tcx. sess . source_map ( ) . end_point ( call_expr. span ) ;
403
+ // remove closing `)` from the span
404
+ let sugg_span = sugg_span. shrink_to_lo ( ) ;
405
+ err. span_suggestion (
406
+ sugg_span,
407
+ "expected the unit value `()`; create it with empty parentheses" ,
408
+ String :: from ( "()" ) ,
409
+ Applicability :: MachineApplicable ,
410
+ ) ;
411
+ } else {
412
+ err. span_label (
413
+ span,
414
+ format ! (
415
+ "expected {}{}" ,
416
+ if c_variadic { "at least " } else { "" } ,
417
+ potentially_plural_count( expected_count, "argument" )
418
+ ) ,
419
+ ) ;
420
+ }
421
+ err. emit ( ) ;
422
+ }
423
+
419
424
// We also need to make sure we at least write the ty of the other
420
425
// arguments which we skipped above.
421
426
if c_variadic {
@@ -975,7 +980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
975
980
fn point_at_arg_instead_of_call_if_possible (
976
981
& self ,
977
982
errors : & mut Vec < traits:: FulfillmentError < ' tcx > > ,
978
- final_arg_types : & [ ( usize , Ty < ' tcx > , Ty < ' tcx > ) ] ,
983
+ final_arg_types : & [ Option < ( Ty < ' tcx > , Ty < ' tcx > ) > ] ,
979
984
expr : & ' tcx hir:: Expr < ' tcx > ,
980
985
call_sp : Span ,
981
986
args : & ' tcx [ hir:: Expr < ' tcx > ] ,
@@ -1030,8 +1035,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1030
1035
// `FulfillmentError`.
1031
1036
let mut referenced_in = final_arg_types
1032
1037
. iter ( )
1033
- . map ( |& ( i, checked_ty, _) | ( i, checked_ty) )
1034
- . chain ( final_arg_types. iter ( ) . map ( |& ( i, _, coerced_ty) | ( i, coerced_ty) ) )
1038
+ . enumerate ( )
1039
+ . filter_map ( |( i, arg) | match arg {
1040
+ Some ( ( checked_ty, coerce_ty) ) => Some ( [ ( i, * checked_ty) , ( i, * coerce_ty) ] ) ,
1041
+ _ => None ,
1042
+ } )
1043
+ . flatten ( )
1035
1044
. flat_map ( |( i, ty) | {
1036
1045
let ty = self . resolve_vars_if_possible ( ty) ;
1037
1046
// We walk the argument type because the argument's type could have
0 commit comments