@@ -250,6 +250,11 @@ struct Context<'a, 'b> {
250
250
unused_names_lint : PositionalNamedArgsLint ,
251
251
}
252
252
253
+ pub struct FormatArg {
254
+ expr : P < ast:: Expr > ,
255
+ named : bool ,
256
+ }
257
+
253
258
/// Parses the arguments from the given list of tokens, returning the diagnostic
254
259
/// if there's a parse error so we can continue parsing other format!
255
260
/// expressions.
@@ -263,8 +268,8 @@ fn parse_args<'a>(
263
268
ecx : & mut ExtCtxt < ' a > ,
264
269
sp : Span ,
265
270
tts : TokenStream ,
266
- ) -> PResult < ' a , ( P < ast:: Expr > , Vec < P < ast :: Expr > > , FxHashMap < Symbol , ( usize , Span ) > ) > {
267
- let mut args = Vec :: < P < ast :: Expr > > :: new ( ) ;
271
+ ) -> PResult < ' a , ( P < ast:: Expr > , Vec < FormatArg > , FxHashMap < Symbol , ( usize , Span ) > ) > {
272
+ let mut args = Vec :: < FormatArg > :: new ( ) ;
268
273
let mut names = FxHashMap :: < Symbol , ( usize , Span ) > :: default ( ) ;
269
274
270
275
let mut p = ecx. new_parser_from_tts ( tts) ;
@@ -332,7 +337,7 @@ fn parse_args<'a>(
332
337
let e = p. parse_expr ( ) ?;
333
338
if let Some ( ( prev, _) ) = names. get ( & ident. name ) {
334
339
ecx. struct_span_err ( e. span , & format ! ( "duplicate argument named `{}`" , ident) )
335
- . span_label ( args[ * prev] . span , "previously here" )
340
+ . span_label ( args[ * prev] . expr . span , "previously here" )
336
341
. span_label ( e. span , "duplicate argument" )
337
342
. emit ( ) ;
338
343
continue ;
@@ -344,7 +349,7 @@ fn parse_args<'a>(
344
349
// args. And remember the names.
345
350
let slot = args. len ( ) ;
346
351
names. insert ( ident. name , ( slot, ident. span ) ) ;
347
- args. push ( e ) ;
352
+ args. push ( FormatArg { expr : e , named : true } ) ;
348
353
}
349
354
_ => {
350
355
let e = p. parse_expr ( ) ?;
@@ -355,11 +360,11 @@ fn parse_args<'a>(
355
360
) ;
356
361
err. span_label ( e. span , "positional arguments must be before named arguments" ) ;
357
362
for pos in names. values ( ) {
358
- err. span_label ( args[ pos. 0 ] . span , "named argument" ) ;
363
+ err. span_label ( args[ pos. 0 ] . expr . span , "named argument" ) ;
359
364
}
360
365
err. emit ( ) ;
361
366
}
362
- args. push ( e ) ;
367
+ args. push ( FormatArg { expr : e , named : false } ) ;
363
368
}
364
369
}
365
370
}
@@ -1180,7 +1185,7 @@ pub fn expand_preparsed_format_args(
1180
1185
ecx : & mut ExtCtxt < ' _ > ,
1181
1186
sp : Span ,
1182
1187
efmt : P < ast:: Expr > ,
1183
- args : Vec < P < ast :: Expr > > ,
1188
+ args : Vec < FormatArg > ,
1184
1189
names : FxHashMap < Symbol , ( usize , Span ) > ,
1185
1190
append_newline : bool ,
1186
1191
) -> P < ast:: Expr > {
@@ -1270,6 +1275,24 @@ pub fn expand_preparsed_format_args(
1270
1275
e. span_label ( fmt_span. from_inner ( InnerSpan :: new ( span. start , span. end ) ) , label) ;
1271
1276
}
1272
1277
}
1278
+ if err. should_be_replaced_with_positional_argument {
1279
+ let captured_arg_span =
1280
+ fmt_span. from_inner ( InnerSpan :: new ( err. span . start , err. span . end ) ) ;
1281
+ let positional_args = args. iter ( ) . filter ( |arg| !arg. named ) . collect :: < Vec < _ > > ( ) ;
1282
+ let mut suggestions = vec ! [ ( captured_arg_span, positional_args. len( ) . to_string( ) ) ] ;
1283
+ if let Ok ( arg) = ecx. source_map ( ) . span_to_snippet ( captured_arg_span) {
1284
+ let span = match positional_args. last ( ) {
1285
+ Some ( arg) => arg. expr . span ,
1286
+ None => fmt_sp,
1287
+ } ;
1288
+ suggestions. push ( ( span. shrink_to_hi ( ) , format ! ( ", {}" , arg) ) )
1289
+ }
1290
+ e. multipart_suggestion_verbose (
1291
+ "consider using a positional formatting argument instead" ,
1292
+ suggestions,
1293
+ Applicability :: MachineApplicable ,
1294
+ ) ;
1295
+ }
1273
1296
e. emit ( ) ;
1274
1297
return DummyResult :: raw_expr ( sp, true ) ;
1275
1298
}
@@ -1284,7 +1307,7 @@ pub fn expand_preparsed_format_args(
1284
1307
1285
1308
let mut cx = Context {
1286
1309
ecx,
1287
- args,
1310
+ args : args . into_iter ( ) . map ( |arg| arg . expr ) . collect ( ) ,
1288
1311
num_captured_args : 0 ,
1289
1312
arg_types,
1290
1313
arg_unique_types,
0 commit comments