@@ -45,14 +45,14 @@ use PositionUsedAs::*;
45
45
/// If parsing succeeds, the return value is:
46
46
///
47
47
/// ```text
48
- /// Some ((fmtstr, parsed arguments))
48
+ /// Ok ((fmtstr, parsed arguments))
49
49
/// ```
50
50
fn parse_args < ' a > (
51
51
ecx : & mut ExtCtxt < ' a > ,
52
52
sp : Span ,
53
53
tts : TokenStream ,
54
- ) -> PResult < ' a , ( P < Expr > , Vec < ( P < Expr > , FormatArgKind ) > ) > {
55
- let mut args = Vec :: < ( P < Expr > , FormatArgKind ) > :: new ( ) ;
54
+ ) -> PResult < ' a , ( P < Expr > , FormatArguments ) > {
55
+ let mut args = FormatArguments :: new ( ) ;
56
56
57
57
let mut p = ecx. new_parser_from_tts ( tts) ;
58
58
@@ -81,7 +81,6 @@ fn parse_args<'a>(
81
81
} ;
82
82
83
83
let mut first = true ;
84
- let mut named = false ;
85
84
86
85
while p. token != token:: Eof {
87
86
if !p. eat ( & token:: Comma ) {
@@ -113,40 +112,40 @@ fn parse_args<'a>(
113
112
} // accept trailing commas
114
113
match p. token . ident ( ) {
115
114
Some ( ( ident, _) ) if p. look_ahead ( 1 , |t| * t == token:: Eq ) => {
116
- named = true ;
117
115
p. bump ( ) ;
118
116
p. expect ( & token:: Eq ) ?;
119
- let e = p. parse_expr ( ) ?;
120
- if let Some ( prev) =
121
- args. iter ( ) . rev ( ) . map_while ( |a| a. 1 . ident ( ) ) . find ( |n| n. name == ident. name )
122
- {
117
+ let expr = p. parse_expr ( ) ?;
118
+ if let Some ( ( _, prev) ) = args. by_name ( ident. name ) {
123
119
ecx. struct_span_err (
124
120
ident. span ,
125
121
& format ! ( "duplicate argument named `{}`" , ident) ,
126
122
)
127
- . span_label ( prev. span , "previously here" )
123
+ . span_label ( prev. kind . ident ( ) . unwrap ( ) . span , "previously here" )
128
124
. span_label ( ident. span , "duplicate argument" )
129
125
. emit ( ) ;
130
126
continue ;
131
127
}
132
- args. push ( ( e , FormatArgKind :: Named ( ident) ) ) ;
128
+ args. add ( FormatArgument { kind : FormatArgumentKind :: Named ( ident) , expr } ) ;
133
129
}
134
130
_ => {
135
- let e = p. parse_expr ( ) ?;
136
- if named {
131
+ let expr = p. parse_expr ( ) ?;
132
+ if !args . named_args ( ) . is_empty ( ) {
137
133
let mut err = ecx. struct_span_err (
138
- e . span ,
134
+ expr . span ,
139
135
"positional arguments cannot follow named arguments" ,
140
136
) ;
141
- err. span_label ( e. span , "positional arguments must be before named arguments" ) ;
142
- for arg in & args {
143
- if let Some ( name) = arg. 1 . ident ( ) {
144
- err. span_label ( name. span . to ( arg. 0 . span ) , "named argument" ) ;
137
+ err. span_label (
138
+ expr. span ,
139
+ "positional arguments must be before named arguments" ,
140
+ ) ;
141
+ for arg in args. named_args ( ) {
142
+ if let Some ( name) = arg. kind . ident ( ) {
143
+ err. span_label ( name. span . to ( arg. expr . span ) , "named argument" ) ;
145
144
}
146
145
}
147
146
err. emit ( ) ;
148
147
}
149
- args. push ( ( e , FormatArgKind :: Normal ) ) ;
148
+ args. add ( FormatArgument { kind : FormatArgumentKind :: Normal , expr } ) ;
150
149
}
151
150
}
152
151
}
@@ -156,12 +155,9 @@ fn parse_args<'a>(
156
155
pub fn make_format_args (
157
156
ecx : & mut ExtCtxt < ' _ > ,
158
157
efmt : P < Expr > ,
159
- mut args : Vec < ( P < Expr > , FormatArgKind ) > ,
158
+ mut args : FormatArguments ,
160
159
append_newline : bool ,
161
160
) -> Result < FormatArgs , ( ) > {
162
- let start_of_named_args =
163
- args. iter ( ) . position ( |arg| arg. 1 . ident ( ) . is_some ( ) ) . unwrap_or ( args. len ( ) ) ;
164
-
165
161
let msg = "format argument must be a string literal" ;
166
162
let fmt_span = efmt. span ;
167
163
let ( fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string ( ecx, efmt, msg) {
@@ -172,9 +168,9 @@ pub fn make_format_args(
172
168
Ok ( fmt) => fmt,
173
169
Err ( err) => {
174
170
if let Some ( ( mut err, suggested) ) = err {
175
- let sugg_fmt = match args. len ( ) {
171
+ let sugg_fmt = match args. explicit_args ( ) . len ( ) {
176
172
0 => "{}" . to_string ( ) ,
177
- _ => format ! ( "{}{{}}" , "{} " . repeat( args. len( ) ) ) ,
173
+ _ => format ! ( "{}{{}}" , "{} " . repeat( args. explicit_args ( ) . len( ) ) ) ,
178
174
} ;
179
175
if !suggested {
180
176
err. span_suggestion (
@@ -243,14 +239,14 @@ pub fn make_format_args(
243
239
let captured_arg_span =
244
240
fmt_span. from_inner ( InnerSpan :: new ( err. span . start , err. span . end ) ) ;
245
241
if let Ok ( arg) = ecx. source_map ( ) . span_to_snippet ( captured_arg_span) {
246
- let span = match args[ ..start_of_named_args ] . last ( ) {
247
- Some ( arg) => arg. 0 . span ,
242
+ let span = match args. unnamed_args ( ) . last ( ) {
243
+ Some ( arg) => arg. expr . span ,
248
244
None => fmt_span,
249
245
} ;
250
246
e. multipart_suggestion_verbose (
251
247
"consider using a positional formatting argument instead" ,
252
248
vec ! [
253
- ( captured_arg_span, start_of_named_args . to_string( ) ) ,
249
+ ( captured_arg_span, args . unnamed_args ( ) . len ( ) . to_string( ) ) ,
254
250
( span. shrink_to_hi( ) , format!( ", {}" , arg) ) ,
255
251
] ,
256
252
Applicability :: MachineApplicable ,
@@ -267,8 +263,7 @@ pub fn make_format_args(
267
263
} )
268
264
} ;
269
265
270
- let num_explicit_args = args. len ( ) ;
271
- let mut used = vec ! [ false ; num_explicit_args] ;
266
+ let mut used = vec ! [ false ; args. explicit_args( ) . len( ) ] ;
272
267
let mut invalid_refs = Vec :: new ( ) ;
273
268
let mut numeric_refences_to_named_arg = Vec :: new ( ) ;
274
269
@@ -285,32 +280,24 @@ pub fn make_format_args(
285
280
-> FormatArgPosition {
286
281
let index = match arg {
287
282
Index ( index) => {
288
- match args. get ( index) {
289
- Some ( ( _, FormatArgKind :: Normal ) ) => {
290
- used[ index] = true ;
291
- Ok ( index)
292
- }
293
- Some ( ( _, FormatArgKind :: Named ( _) ) ) => {
294
- used[ index] = true ;
283
+ if let Some ( arg) = args. by_index ( index) {
284
+ used[ index] = true ;
285
+ if arg. kind . ident ( ) . is_some ( ) {
286
+ // This was a named argument, but it was used as a positional argument.
295
287
numeric_refences_to_named_arg. push ( ( index, span, used_as) ) ;
296
- Ok ( index)
297
- }
298
- Some ( ( _, FormatArgKind :: Captured ( _) ) ) | None => {
299
- // Doesn't exist as an explicit argument.
300
- invalid_refs. push ( ( index, span, used_as, kind) ) ;
301
- Err ( index)
302
288
}
289
+ Ok ( index)
290
+ } else {
291
+ // Doesn't exist as an explicit argument.
292
+ invalid_refs. push ( ( index, span, used_as, kind) ) ;
293
+ Err ( index)
303
294
}
304
295
}
305
296
Name ( name, span) => {
306
297
let name = Symbol :: intern ( name) ;
307
- if let Some ( i) = args[ start_of_named_args..]
308
- . iter ( )
309
- . position ( |arg| arg. 1 . ident ( ) . is_some_and ( |id| id. name == name) )
310
- {
311
- // Name found in `args`, so we resolve it to its index in that Vec.
312
- let index = start_of_named_args + i;
313
- if !matches ! ( args[ index] . 1 , FormatArgKind :: Captured ( _) ) {
298
+ if let Some ( ( index, _) ) = args. by_name ( name) {
299
+ // Name found in `args`, so we resolve it to its index.
300
+ if index < args. explicit_args ( ) . len ( ) {
314
301
// Mark it as used, if it was an explicit argument.
315
302
used[ index] = true ;
316
303
}
@@ -319,7 +306,7 @@ pub fn make_format_args(
319
306
// Name not found in `args`, so we add it as an implicitly captured argument.
320
307
let span = span. unwrap_or ( fmt_span) ;
321
308
let ident = Ident :: new ( name, span) ;
322
- let arg = if is_literal {
309
+ let expr = if is_literal {
323
310
ecx. expr_ident ( span, ident)
324
311
} else {
325
312
// For the moment capturing variables from format strings expanded from macros is
@@ -330,8 +317,7 @@ pub fn make_format_args(
330
317
. emit ( ) ;
331
318
DummyResult :: raw_expr ( span, true )
332
319
} ;
333
- args. push ( ( arg, FormatArgKind :: Captured ( ident) ) ) ;
334
- Ok ( args. len ( ) - 1 )
320
+ Ok ( args. add ( FormatArgument { kind : FormatArgumentKind :: Captured ( ident) , expr } ) )
335
321
}
336
322
}
337
323
} ;
@@ -466,35 +452,27 @@ pub fn make_format_args(
466
452
}
467
453
468
454
if !invalid_refs. is_empty ( ) {
469
- report_invalid_references (
470
- ecx,
471
- & invalid_refs,
472
- & template,
473
- fmt_span,
474
- num_explicit_args,
475
- & args,
476
- parser,
477
- ) ;
455
+ report_invalid_references ( ecx, & invalid_refs, & template, fmt_span, & args, parser) ;
478
456
}
479
457
480
458
let unused = used
481
459
. iter ( )
482
460
. enumerate ( )
483
461
. filter ( |& ( _, used) | !used)
484
462
. map ( |( i, _) | {
485
- let msg = if let FormatArgKind :: Named ( _) = args[ i] . 1 {
463
+ let msg = if let FormatArgumentKind :: Named ( _) = args. explicit_args ( ) [ i] . kind {
486
464
"named argument never used"
487
465
} else {
488
466
"argument never used"
489
467
} ;
490
- ( args[ i] . 0 . span , msg)
468
+ ( args. explicit_args ( ) [ i] . expr . span , msg)
491
469
} )
492
470
. collect :: < Vec < _ > > ( ) ;
493
471
494
472
if !unused. is_empty ( ) {
495
473
// If there's a lot of unused arguments,
496
474
// let's check if this format arguments looks like another syntax (printf / shell).
497
- let detect_foreign_fmt = unused. len ( ) > num_explicit_args / 2 ;
475
+ let detect_foreign_fmt = unused. len ( ) > args . explicit_args ( ) . len ( ) / 2 ;
498
476
report_missing_placeholders ( ecx, unused, detect_foreign_fmt, str_style, fmt_str, fmt_span) ;
499
477
}
500
478
@@ -511,7 +489,7 @@ pub fn make_format_args(
511
489
}
512
490
Width => ( span, span) ,
513
491
} ;
514
- let arg_name = args[ index] . 1 . ident ( ) . unwrap ( ) ;
492
+ let arg_name = args. explicit_args ( ) [ index] . kind . ident ( ) . unwrap ( ) ;
515
493
ecx. buffered_early_lint . push ( BufferedEarlyLint {
516
494
span : arg_name. span . into ( ) ,
517
495
msg : format ! ( "named argument `{}` is not used by name" , arg_name. name) . into ( ) ,
@@ -695,11 +673,10 @@ fn report_invalid_references(
695
673
invalid_refs : & [ ( usize , Option < Span > , PositionUsedAs , FormatArgPositionKind ) ] ,
696
674
template : & [ FormatArgsPiece ] ,
697
675
fmt_span : Span ,
698
- num_explicit_args : usize ,
699
- args : & [ ( P < Expr > , FormatArgKind ) ] ,
676
+ args : & FormatArguments ,
700
677
parser : parse:: Parser < ' _ > ,
701
678
) {
702
- let num_args_desc = match num_explicit_args {
679
+ let num_args_desc = match args . explicit_args ( ) . len ( ) {
703
680
0 => "no arguments were given" . to_string ( ) ,
704
681
1 => "there is 1 argument" . to_string ( ) ,
705
682
n => format ! ( "there are {} arguments" , n) ,
@@ -785,8 +762,8 @@ fn report_invalid_references(
785
762
num_args_desc,
786
763
) ,
787
764
) ;
788
- for ( arg, _ ) in & args[ ..num_explicit_args ] {
789
- e. span_label ( arg. span , "" ) ;
765
+ for arg in args. explicit_args ( ) {
766
+ e. span_label ( arg. expr . span , "" ) ;
790
767
}
791
768
// Point out `{:.*}` placeholders: those take an extra argument.
792
769
let mut has_precision_star = false ;
0 commit comments