@@ -45,14 +45,14 @@ use PositionUsedAs::*;
4545/// If parsing succeeds, the return value is:
4646///
4747/// ```text
48- /// Some ((fmtstr, parsed arguments))
48+ /// Ok ((fmtstr, parsed arguments))
4949/// ```
5050fn parse_args < ' a > (
5151 ecx : & mut ExtCtxt < ' a > ,
5252 sp : Span ,
5353 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 ( ) ;
5656
5757 let mut p = ecx. new_parser_from_tts ( tts) ;
5858
@@ -81,7 +81,6 @@ fn parse_args<'a>(
8181 } ;
8282
8383 let mut first = true ;
84- let mut named = false ;
8584
8685 while p. token != token:: Eof {
8786 if !p. eat ( & token:: Comma ) {
@@ -113,40 +112,40 @@ fn parse_args<'a>(
113112 } // accept trailing commas
114113 match p. token . ident ( ) {
115114 Some ( ( ident, _) ) if p. look_ahead ( 1 , |t| * t == token:: Eq ) => {
116- named = true ;
117115 p. bump ( ) ;
118116 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 ) {
123119 ecx. struct_span_err (
124120 ident. span ,
125121 & format ! ( "duplicate argument named `{}`" , ident) ,
126122 )
127- . span_label ( prev. span , "previously here" )
123+ . span_label ( prev. kind . ident ( ) . unwrap ( ) . span , "previously here" )
128124 . span_label ( ident. span , "duplicate argument" )
129125 . emit ( ) ;
130126 continue ;
131127 }
132- args. push ( ( e , FormatArgKind :: Named ( ident) ) ) ;
128+ args. add ( FormatArgument { kind : FormatArgumentKind :: Named ( ident) , expr } ) ;
133129 }
134130 _ => {
135- let e = p. parse_expr ( ) ?;
136- if named {
131+ let expr = p. parse_expr ( ) ?;
132+ if !args . named_args ( ) . is_empty ( ) {
137133 let mut err = ecx. struct_span_err (
138- e . span ,
134+ expr . span ,
139135 "positional arguments cannot follow named arguments" ,
140136 ) ;
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" ) ;
145144 }
146145 }
147146 err. emit ( ) ;
148147 }
149- args. push ( ( e , FormatArgKind :: Normal ) ) ;
148+ args. add ( FormatArgument { kind : FormatArgumentKind :: Normal , expr } ) ;
150149 }
151150 }
152151 }
@@ -156,12 +155,9 @@ fn parse_args<'a>(
156155pub fn make_format_args (
157156 ecx : & mut ExtCtxt < ' _ > ,
158157 efmt : P < Expr > ,
159- mut args : Vec < ( P < Expr > , FormatArgKind ) > ,
158+ mut args : FormatArguments ,
160159 append_newline : bool ,
161160) -> Result < FormatArgs , ( ) > {
162- let start_of_named_args =
163- args. iter ( ) . position ( |arg| arg. 1 . ident ( ) . is_some ( ) ) . unwrap_or ( args. len ( ) ) ;
164-
165161 let msg = "format argument must be a string literal" ;
166162 let fmt_span = efmt. span ;
167163 let ( fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string ( ecx, efmt, msg) {
@@ -172,9 +168,9 @@ pub fn make_format_args(
172168 Ok ( fmt) => fmt,
173169 Err ( err) => {
174170 if let Some ( ( mut err, suggested) ) = err {
175- let sugg_fmt = match args. len ( ) {
171+ let sugg_fmt = match args. explicit_args ( ) . len ( ) {
176172 0 => "{}" . to_string ( ) ,
177- _ => format ! ( "{}{{}}" , "{} " . repeat( args. len( ) ) ) ,
173+ _ => format ! ( "{}{{}}" , "{} " . repeat( args. explicit_args ( ) . len( ) ) ) ,
178174 } ;
179175 if !suggested {
180176 err. span_suggestion (
@@ -243,14 +239,14 @@ pub fn make_format_args(
243239 let captured_arg_span =
244240 fmt_span. from_inner ( InnerSpan :: new ( err. span . start , err. span . end ) ) ;
245241 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 ,
248244 None => fmt_span,
249245 } ;
250246 e. multipart_suggestion_verbose (
251247 "consider using a positional formatting argument instead" ,
252248 vec ! [
253- ( captured_arg_span, start_of_named_args . to_string( ) ) ,
249+ ( captured_arg_span, args . unnamed_args ( ) . len ( ) . to_string( ) ) ,
254250 ( span. shrink_to_hi( ) , format!( ", {}" , arg) ) ,
255251 ] ,
256252 Applicability :: MachineApplicable ,
@@ -267,8 +263,7 @@ pub fn make_format_args(
267263 } )
268264 } ;
269265
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( ) ] ;
272267 let mut invalid_refs = Vec :: new ( ) ;
273268 let mut numeric_refences_to_named_arg = Vec :: new ( ) ;
274269
@@ -285,32 +280,24 @@ pub fn make_format_args(
285280 -> FormatArgPosition {
286281 let index = match arg {
287282 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.
295287 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)
302288 }
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)
303294 }
304295 }
305296 Name ( name, span) => {
306297 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 ( ) {
314301 // Mark it as used, if it was an explicit argument.
315302 used[ index] = true ;
316303 }
@@ -319,7 +306,7 @@ pub fn make_format_args(
319306 // Name not found in `args`, so we add it as an implicitly captured argument.
320307 let span = span. unwrap_or ( fmt_span) ;
321308 let ident = Ident :: new ( name, span) ;
322- let arg = if is_literal {
309+ let expr = if is_literal {
323310 ecx. expr_ident ( span, ident)
324311 } else {
325312 // For the moment capturing variables from format strings expanded from macros is
@@ -330,8 +317,7 @@ pub fn make_format_args(
330317 . emit ( ) ;
331318 DummyResult :: raw_expr ( span, true )
332319 } ;
333- args. push ( ( arg, FormatArgKind :: Captured ( ident) ) ) ;
334- Ok ( args. len ( ) - 1 )
320+ Ok ( args. add ( FormatArgument { kind : FormatArgumentKind :: Captured ( ident) , expr } ) )
335321 }
336322 }
337323 } ;
@@ -466,35 +452,27 @@ pub fn make_format_args(
466452 }
467453
468454 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) ;
478456 }
479457
480458 let unused = used
481459 . iter ( )
482460 . enumerate ( )
483461 . filter ( |& ( _, used) | !used)
484462 . map ( |( i, _) | {
485- let msg = if let FormatArgKind :: Named ( _) = args[ i] . 1 {
463+ let msg = if let FormatArgumentKind :: Named ( _) = args. explicit_args ( ) [ i] . kind {
486464 "named argument never used"
487465 } else {
488466 "argument never used"
489467 } ;
490- ( args[ i] . 0 . span , msg)
468+ ( args. explicit_args ( ) [ i] . expr . span , msg)
491469 } )
492470 . collect :: < Vec < _ > > ( ) ;
493471
494472 if !unused. is_empty ( ) {
495473 // If there's a lot of unused arguments,
496474 // 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 ;
498476 report_missing_placeholders ( ecx, unused, detect_foreign_fmt, str_style, fmt_str, fmt_span) ;
499477 }
500478
@@ -511,7 +489,7 @@ pub fn make_format_args(
511489 }
512490 Width => ( span, span) ,
513491 } ;
514- let arg_name = args[ index] . 1 . ident ( ) . unwrap ( ) ;
492+ let arg_name = args. explicit_args ( ) [ index] . kind . ident ( ) . unwrap ( ) ;
515493 ecx. buffered_early_lint . push ( BufferedEarlyLint {
516494 span : arg_name. span . into ( ) ,
517495 msg : format ! ( "named argument `{}` is not used by name" , arg_name. name) . into ( ) ,
@@ -695,11 +673,10 @@ fn report_invalid_references(
695673 invalid_refs : & [ ( usize , Option < Span > , PositionUsedAs , FormatArgPositionKind ) ] ,
696674 template : & [ FormatArgsPiece ] ,
697675 fmt_span : Span ,
698- num_explicit_args : usize ,
699- args : & [ ( P < Expr > , FormatArgKind ) ] ,
676+ args : & FormatArguments ,
700677 parser : parse:: Parser < ' _ > ,
701678) {
702- let num_args_desc = match num_explicit_args {
679+ let num_args_desc = match args . explicit_args ( ) . len ( ) {
703680 0 => "no arguments were given" . to_string ( ) ,
704681 1 => "there is 1 argument" . to_string ( ) ,
705682 n => format ! ( "there are {} arguments" , n) ,
@@ -785,8 +762,8 @@ fn report_invalid_references(
785762 num_args_desc,
786763 ) ,
787764 ) ;
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 , "" ) ;
790767 }
791768 // Point out `{:.*}` placeholders: those take an extra argument.
792769 let mut has_precision_star = false ;
0 commit comments