@@ -164,18 +164,32 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
164164 . collect ( ) ,
165165 ) ;
166166
167- let has_any_format_options = fmt. template . iter ( ) . any ( |piece| {
168- let FormatArgsPiece :: Placeholder ( placeholder) = piece else { return false } ;
169- placeholder. format_options != Default :: default ( )
170- } ) ;
167+ // Whether we'll use the `Arguments::new_v1_formatted` form (true),
168+ // or the `Arguments::new_v1` form (false).
169+ let mut use_format_options = false ;
171170
172- let ( args, format_options) = if has_any_format_options {
173- // Create a list of all _unique_ (argument, format trait) combinations.
174- // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
175- let mut argmap = FxIndexSet :: default ( ) ;
171+ // Create a list of all _unique_ (argument, format trait) combinations.
172+ // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
173+ let mut argmap = FxIndexSet :: default ( ) ;
174+ for piece in & fmt. template {
175+ let FormatArgsPiece :: Placeholder ( placeholder) = piece else { continue } ;
176+ if placeholder. format_options != Default :: default ( ) {
177+ // Can't use basic form if there's any formatting options.
178+ use_format_options = true ;
179+ }
180+ if let Ok ( index) = placeholder. argument . index {
181+ if !argmap. insert ( ( index, ArgumentType :: Format ( placeholder. format_trait ) ) ) {
182+ // Duplicate (argument, format trait) combination,
183+ // which we'll only put once in the args array.
184+ use_format_options = true ;
185+ }
186+ }
187+ }
188+
189+ let format_options = use_format_options. then ( || {
176190 // Generate:
177191 // &[format_spec_0, format_spec_1, format_spec_2]
178- let format_options = ecx. expr_array_ref (
192+ ecx. expr_array_ref (
179193 macsp,
180194 fmt. template
181195 . iter ( )
@@ -184,34 +198,18 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
184198 Some ( make_format_spec ( ecx, macsp, placeholder, & mut argmap) )
185199 } )
186200 . collect ( ) ,
187- ) ;
188- ( Vec :: from_iter ( argmap) , Some ( format_options) )
189- } else {
190- // Create a list of all (argument, format trait) pairs, one for each placeholder.
191- // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (0, Display), (1, Display)]
192- let args = fmt
193- . template
194- . iter ( )
195- . filter_map ( |piece| {
196- let FormatArgsPiece :: Placeholder ( placeholder) = piece else { return None } ;
197- Some ( (
198- placeholder. argument . index . ok ( ) ?,
199- ArgumentType :: Format ( placeholder. format_trait ) ,
200- ) )
201- } )
202- . collect ( ) ;
203- ( args, None )
204- } ;
201+ )
202+ } ) ;
205203
206204 // If the args array contains exactly all the original arguments once,
207205 // in order, we can use a simple array instead of a `match` construction.
208206 // However, if there's a yield point in any argument except the first one,
209207 // we don't do this, because an ArgumentV1 cannot be kept across yield points.
210- let use_simple_array = args . len ( ) == fmt. arguments . len ( )
211- && args . iter ( ) . enumerate ( ) . all ( |( i, & ( j, _) ) | i == j)
208+ let use_simple_array = argmap . len ( ) == fmt. arguments . len ( )
209+ && argmap . iter ( ) . enumerate ( ) . all ( |( i, & ( j, _) ) | i == j)
212210 && fmt. arguments . iter ( ) . skip ( 1 ) . all ( |( arg, _) | !may_contain_yield_point ( arg) ) ;
213211
214- let args_expr = if use_simple_array {
212+ let args = if use_simple_array {
215213 // Generate:
216214 // &[
217215 // ::core::fmt::ArgumentV1::new_display(&arg0),
@@ -222,7 +220,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
222220 macsp,
223221 fmt. arguments
224222 . into_iter ( )
225- . zip ( args )
223+ . zip ( argmap )
226224 . map ( |( ( arg, _) , ( _, ty) ) | {
227225 let sp = arg. span . with_ctxt ( macsp. ctxt ( ) ) ;
228226 make_argument ( ecx, sp, ecx. expr_addr_of ( sp, arg) , ty)
@@ -239,7 +237,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
239237 // ]
240238 // }
241239 let args_ident = Ident :: new ( sym:: args, macsp) ;
242- let args = args
240+ let args = argmap
243241 . iter ( )
244242 . map ( |& ( arg_index, ty) | {
245243 if let Some ( ( arg, _) ) = fmt. arguments . get ( arg_index) {
@@ -270,8 +268,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
270268 . map ( |( arg, _) | ecx. expr_addr_of ( arg. span . with_ctxt ( macsp. ctxt ( ) ) , arg) )
271269 . collect ( ) ,
272270 ) ,
273- [ ecx. arm ( macsp, ecx. pat_ident ( macsp, args_ident) , ecx. expr_array ( macsp, args) ) ]
274- . into ( ) ,
271+ vec ! [ ecx. arm( macsp, ecx. pat_ident( macsp, args_ident) , ecx. expr_array( macsp, args) ) ] ,
275272 ) ,
276273 )
277274 } ;
@@ -289,7 +286,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
289286 ecx. std_path ( & [ sym:: fmt, sym:: Arguments , sym:: new_v1_formatted] ) ,
290287 vec ! [
291288 lit_pieces,
292- args_expr ,
289+ args ,
293290 format_options,
294291 ecx. expr_block( P ( ast:: Block {
295292 stmts: vec![ ecx. stmt_expr( ecx. expr_call_global(
@@ -314,7 +311,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
314311 ecx. expr_call_global (
315312 macsp,
316313 ecx. std_path ( & [ sym:: fmt, sym:: Arguments , sym:: new_v1] ) ,
317- vec ! [ lit_pieces, args_expr ] ,
314+ vec ! [ lit_pieces, args ] ,
318315 )
319316 }
320317}
0 commit comments