@@ -164,18 +164,32 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
164
164
. collect ( ) ,
165
165
) ;
166
166
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 ;
171
170
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 ( || {
176
190
// Generate:
177
191
// &[format_spec_0, format_spec_1, format_spec_2]
178
- let format_options = ecx. expr_array_ref (
192
+ ecx. expr_array_ref (
179
193
macsp,
180
194
fmt. template
181
195
. iter ( )
@@ -184,34 +198,18 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
184
198
Some ( make_format_spec ( ecx, macsp, placeholder, & mut argmap) )
185
199
} )
186
200
. 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
+ } ) ;
205
203
206
204
// If the args array contains exactly all the original arguments once,
207
205
// in order, we can use a simple array instead of a `match` construction.
208
206
// However, if there's a yield point in any argument except the first one,
209
207
// 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)
212
210
&& fmt. arguments . iter ( ) . skip ( 1 ) . all ( |( arg, _) | !may_contain_yield_point ( arg) ) ;
213
211
214
- let args_expr = if use_simple_array {
212
+ let args = if use_simple_array {
215
213
// Generate:
216
214
// &[
217
215
// ::core::fmt::ArgumentV1::new_display(&arg0),
@@ -222,7 +220,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
222
220
macsp,
223
221
fmt. arguments
224
222
. into_iter ( )
225
- . zip ( args )
223
+ . zip ( argmap )
226
224
. map ( |( ( arg, _) , ( _, ty) ) | {
227
225
let sp = arg. span . with_ctxt ( macsp. ctxt ( ) ) ;
228
226
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
239
237
// ]
240
238
// }
241
239
let args_ident = Ident :: new ( sym:: args, macsp) ;
242
- let args = args
240
+ let args = argmap
243
241
. iter ( )
244
242
. map ( |& ( arg_index, ty) | {
245
243
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
270
268
. map ( |( arg, _) | ecx. expr_addr_of ( arg. span . with_ctxt ( macsp. ctxt ( ) ) , arg) )
271
269
. collect ( ) ,
272
270
) ,
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) ) ] ,
275
272
) ,
276
273
)
277
274
} ;
@@ -289,7 +286,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
289
286
ecx. std_path ( & [ sym:: fmt, sym:: Arguments , sym:: new_v1_formatted] ) ,
290
287
vec ! [
291
288
lit_pieces,
292
- args_expr ,
289
+ args ,
293
290
format_options,
294
291
ecx. expr_block( P ( ast:: Block {
295
292
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
314
311
ecx. expr_call_global (
315
312
macsp,
316
313
ecx. std_path ( & [ sym:: fmt, sym:: Arguments , sym:: new_v1] ) ,
317
- vec ! [ lit_pieces, args_expr ] ,
314
+ vec ! [ lit_pieces, args ] ,
318
315
)
319
316
}
320
317
}
0 commit comments