@@ -280,6 +280,11 @@ struct Context<'a, 'b> {
280
280
unused_names_lint : PositionalNamedArgsLint ,
281
281
}
282
282
283
+ pub struct FormatArg {
284
+ expr : P < ast:: Expr > ,
285
+ named : bool ,
286
+ }
287
+
283
288
/// Parses the arguments from the given list of tokens, returning the diagnostic
284
289
/// if there's a parse error so we can continue parsing other format!
285
290
/// expressions.
@@ -293,8 +298,8 @@ fn parse_args<'a>(
293
298
ecx : & mut ExtCtxt < ' a > ,
294
299
sp : Span ,
295
300
tts : TokenStream ,
296
- ) -> PResult < ' a , ( P < ast:: Expr > , Vec < P < ast :: Expr > > , FxHashMap < Symbol , ( usize , Span ) > ) > {
297
- let mut args = Vec :: < P < ast :: Expr > > :: new ( ) ;
301
+ ) -> PResult < ' a , ( P < ast:: Expr > , Vec < FormatArg > , FxHashMap < Symbol , ( usize , Span ) > ) > {
302
+ let mut args = Vec :: < FormatArg > :: new ( ) ;
298
303
let mut names = FxHashMap :: < Symbol , ( usize , Span ) > :: default ( ) ;
299
304
300
305
let mut p = ecx. new_parser_from_tts ( tts) ;
@@ -362,7 +367,7 @@ fn parse_args<'a>(
362
367
let e = p. parse_expr ( ) ?;
363
368
if let Some ( ( prev, _) ) = names. get ( & ident. name ) {
364
369
ecx. struct_span_err ( e. span , & format ! ( "duplicate argument named `{}`" , ident) )
365
- . span_label ( args[ * prev] . span , "previously here" )
370
+ . span_label ( args[ * prev] . expr . span , "previously here" )
366
371
. span_label ( e. span , "duplicate argument" )
367
372
. emit ( ) ;
368
373
continue ;
@@ -374,7 +379,7 @@ fn parse_args<'a>(
374
379
// args. And remember the names.
375
380
let slot = args. len ( ) ;
376
381
names. insert ( ident. name , ( slot, ident. span ) ) ;
377
- args. push ( e ) ;
382
+ args. push ( FormatArg { expr : e , named : true } ) ;
378
383
}
379
384
_ => {
380
385
let e = p. parse_expr ( ) ?;
@@ -385,11 +390,11 @@ fn parse_args<'a>(
385
390
) ;
386
391
err. span_label ( e. span , "positional arguments must be before named arguments" ) ;
387
392
for pos in names. values ( ) {
388
- err. span_label ( args[ pos. 0 ] . span , "named argument" ) ;
393
+ err. span_label ( args[ pos. 0 ] . expr . span , "named argument" ) ;
389
394
}
390
395
err. emit ( ) ;
391
396
}
392
- args. push ( e ) ;
397
+ args. push ( FormatArg { expr : e , named : false } ) ;
393
398
}
394
399
}
395
400
}
@@ -1214,7 +1219,7 @@ pub fn expand_preparsed_format_args(
1214
1219
ecx : & mut ExtCtxt < ' _ > ,
1215
1220
sp : Span ,
1216
1221
efmt : P < ast:: Expr > ,
1217
- args : Vec < P < ast :: Expr > > ,
1222
+ args : Vec < FormatArg > ,
1218
1223
names : FxHashMap < Symbol , ( usize , Span ) > ,
1219
1224
append_newline : bool ,
1220
1225
) -> P < ast:: Expr > {
@@ -1304,6 +1309,25 @@ pub fn expand_preparsed_format_args(
1304
1309
e. span_label ( fmt_span. from_inner ( InnerSpan :: new ( span. start , span. end ) ) , label) ;
1305
1310
}
1306
1311
}
1312
+ if err. should_be_replaced_with_positional_argument {
1313
+ let captured_arg_span =
1314
+ fmt_span. from_inner ( InnerSpan :: new ( err. span . start , err. span . end ) ) ;
1315
+ let positional_args = args. iter ( ) . filter ( |arg| !arg. named ) . collect :: < Vec < _ > > ( ) ;
1316
+ if let Ok ( arg) = ecx. source_map ( ) . span_to_snippet ( captured_arg_span) {
1317
+ let span = match positional_args. last ( ) {
1318
+ Some ( arg) => arg. expr . span ,
1319
+ None => fmt_sp,
1320
+ } ;
1321
+ e. multipart_suggestion_verbose (
1322
+ "consider using a positional formatting argument instead" ,
1323
+ vec ! [
1324
+ ( captured_arg_span, positional_args. len( ) . to_string( ) ) ,
1325
+ ( span. shrink_to_hi( ) , format!( ", {}" , arg) ) ,
1326
+ ] ,
1327
+ Applicability :: MachineApplicable ,
1328
+ ) ;
1329
+ }
1330
+ }
1307
1331
e. emit ( ) ;
1308
1332
return DummyResult :: raw_expr ( sp, true ) ;
1309
1333
}
@@ -1318,7 +1342,7 @@ pub fn expand_preparsed_format_args(
1318
1342
1319
1343
let mut cx = Context {
1320
1344
ecx,
1321
- args,
1345
+ args : args . into_iter ( ) . map ( |arg| arg . expr ) . collect ( ) ,
1322
1346
num_captured_args : 0 ,
1323
1347
arg_types,
1324
1348
arg_unique_types,
0 commit comments