@@ -49,7 +49,7 @@ struct Context<'a, 'b:'a> {
49
49
/// Named expressions are resolved early, and are appended to the end of
50
50
/// argument expressions.
51
51
args : Vec < P < ast:: Expr > > ,
52
- arg_types : Vec < Option < ArgumentType > > ,
52
+ arg_types : Vec < Vec < ArgumentType > > ,
53
53
/// Map from named arguments to their resolved indices.
54
54
names : HashMap < String , usize > ,
55
55
@@ -63,6 +63,13 @@ struct Context<'a, 'b:'a> {
63
63
/// Stays `true` if all formatting parameters are default (as in "{}{}").
64
64
all_pieces_simple : bool ,
65
65
66
+ /// Mapping between positional argument references and indices into the
67
+ /// final generated static argument array. We record the starting indices
68
+ /// corresponding to each positional argument, and number of references
69
+ /// consumed so far for each argument, to facilitate correct `Position`
70
+ /// mapping in `trans_piece`.
71
+ arg_index_map : Vec < usize > ,
72
+
66
73
/// Current position of the implicit positional arg pointer, as if it
67
74
/// still existed in this phase of processing.
68
75
/// Used only for `all_pieces_simple` tracking in `trans_piece`.
@@ -218,16 +225,7 @@ impl<'a, 'b> Context<'a, 'b> {
218
225
self . ecx . span_err ( self . fmtsp , & msg[ ..] ) ;
219
226
return ;
220
227
}
221
- {
222
- let arg_type = match self . arg_types [ arg] {
223
- None => None ,
224
- Some ( ref x) => Some ( x)
225
- } ;
226
- self . verify_same ( self . args [ arg] . span , & ty, arg_type) ;
227
- }
228
- if self . arg_types [ arg] . is_none ( ) {
229
- self . arg_types [ arg] = Some ( ty) ;
230
- }
228
+ self . arg_types [ arg] . push ( ty) ;
231
229
}
232
230
233
231
Named ( name) => {
@@ -245,56 +243,27 @@ impl<'a, 'b> Context<'a, 'b> {
245
243
}
246
244
}
247
245
248
- /// When we're keeping track of the types that are declared for certain
249
- /// arguments, we assume that `None` means we haven't seen this argument
250
- /// yet, `Some(None)` means that we've seen the argument, but no format was
251
- /// specified, and `Some(Some(x))` means that the argument was declared to
252
- /// have type `x`.
253
- ///
254
- /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
255
- /// that: `Some(None) == Some(Some(x))`
256
- fn verify_same ( & self ,
257
- sp : Span ,
258
- ty : & ArgumentType ,
259
- before : Option < & ArgumentType > ) {
260
- let cur = match before {
261
- None => return ,
262
- Some ( t) => t,
263
- } ;
264
- if * ty == * cur {
265
- return
266
- }
267
- match ( cur, ty) {
268
- ( & Known ( ref cur) , & Known ( ref ty) ) => {
269
- self . ecx . span_err ( sp,
270
- & format ! ( "argument redeclared with type `{}` when \
271
- it was previously `{}`",
272
- * ty,
273
- * cur) ) ;
274
- }
275
- ( & Known ( ref cur) , _) => {
276
- self . ecx . span_err ( sp,
277
- & format ! ( "argument used to format with `{}` was \
278
- attempted to not be used for formatting",
279
- * cur) ) ;
280
- }
281
- ( _, & Known ( ref ty) ) => {
282
- self . ecx . span_err ( sp,
283
- & format ! ( "argument previously used as a format \
284
- argument attempted to be used as `{}`",
285
- * ty) ) ;
286
- }
287
- ( _, _) => {
288
- self . ecx . span_err ( sp, "argument declared with multiple formats" ) ;
289
- }
246
+ // NOTE: Keep the ordering the same as `into_expr`'s expansion would do!
247
+ fn build_index_map ( & mut self ) {
248
+ let args_len = self . args . len ( ) ;
249
+ self . arg_index_map . reserve ( args_len) ;
250
+
251
+ let mut sofar = 0usize ;
252
+
253
+ // Generate mapping for positional args
254
+ for i in 0 ..args_len {
255
+ self . arg_index_map . push ( sofar) ;
256
+ sofar += self . arg_types [ i] . len ( ) ;
290
257
}
291
258
}
292
259
293
260
fn rtpath ( ecx : & ExtCtxt , s : & str ) -> Vec < ast:: Ident > {
294
261
ecx. std_path ( & [ "fmt" , "rt" , "v1" , s] )
295
262
}
296
263
297
- fn trans_count ( & self , c : parse:: Count ) -> P < ast:: Expr > {
264
+ fn trans_count ( & self ,
265
+ c : parse:: Count ,
266
+ arg_index_consumed : & mut Vec < usize > ) -> P < ast:: Expr > {
298
267
let sp = self . macsp ;
299
268
let count = |c, arg| {
300
269
let mut path = Context :: rtpath ( self . ecx , "Count" ) ;
@@ -307,7 +276,11 @@ impl<'a, 'b> Context<'a, 'b> {
307
276
match c {
308
277
parse:: CountIs ( i) => count ( "Is" , Some ( self . ecx . expr_usize ( sp, i) ) ) ,
309
278
parse:: CountIsParam ( i) => {
310
- count ( "Param" , Some ( self . ecx . expr_usize ( sp, i) ) )
279
+ // This needs mapping too, as `i` is referring to a macro
280
+ // argument.
281
+ let arg_idx = self . arg_index_map [ i] + arg_index_consumed[ i] ;
282
+ arg_index_consumed[ i] += 1 ;
283
+ count ( "Param" , Some ( self . ecx . expr_usize ( sp, arg_idx) ) )
311
284
}
312
285
parse:: CountImplied => count ( "Implied" , None ) ,
313
286
// should never be the case, names are already resolved
@@ -325,7 +298,10 @@ impl<'a, 'b> Context<'a, 'b> {
325
298
326
299
/// Translate a `parse::Piece` to a static `rt::Argument` or append
327
300
/// to the `literal` string.
328
- fn trans_piece ( & mut self , piece : & parse:: Piece ) -> Option < P < ast:: Expr > > {
301
+ fn trans_piece ( & mut self ,
302
+ piece : & parse:: Piece ,
303
+ arg_index_consumed : & mut Vec < usize > )
304
+ -> Option < P < ast:: Expr > > {
329
305
let sp = self . macsp ;
330
306
match * piece {
331
307
parse:: String ( s) => {
@@ -349,7 +325,18 @@ impl<'a, 'b> Context<'a, 'b> {
349
325
}
350
326
} ;
351
327
match arg. position {
352
- parse:: ArgumentIs ( i) => pos ( "At" , Some ( i) ) ,
328
+ parse:: ArgumentIs ( i) => {
329
+ // Map to index in final generated argument array
330
+ // in case of multiple types specified
331
+ let arg_idx = if self . args . len ( ) > i {
332
+ let arg_idx = self . arg_index_map [ i] + arg_index_consumed[ i] ;
333
+ arg_index_consumed[ i] += 1 ;
334
+ arg_idx
335
+ } else {
336
+ 0 // error already emitted elsewhere
337
+ } ;
338
+ pos ( "At" , Some ( arg_idx) )
339
+ }
353
340
354
341
// should never be the case, because names are already
355
342
// resolved.
@@ -396,8 +383,8 @@ impl<'a, 'b> Context<'a, 'b> {
396
383
} ;
397
384
let align = self . ecx . expr_path ( align) ;
398
385
let flags = self . ecx . expr_u32 ( sp, arg. format . flags ) ;
399
- let prec = self . trans_count ( arg. format . precision ) ;
400
- let width = self . trans_count ( arg. format . width ) ;
386
+ let prec = self . trans_count ( arg. format . precision , arg_index_consumed ) ;
387
+ let width = self . trans_count ( arg. format . width , arg_index_consumed ) ;
401
388
let path = self . ecx . path_global ( sp, Context :: rtpath ( self . ecx , "FormatSpec" ) ) ;
402
389
let fmt = self . ecx . expr_struct ( sp, path, vec ! (
403
390
self . ecx. field_imm( sp, self . ecx. ident_of( "fill" ) , fill) ,
@@ -469,15 +456,12 @@ impl<'a, 'b> Context<'a, 'b> {
469
456
// of each variable because we don't want to move out of the arguments
470
457
// passed to this function.
471
458
for ( i, e) in self . args . into_iter ( ) . enumerate ( ) {
472
- let arg_ty = match self . arg_types [ i] . as_ref ( ) {
473
- Some ( ty) => ty,
474
- None => continue // error already generated
475
- } ;
476
-
477
459
let name = self . ecx . ident_of ( & format ! ( "__arg{}" , i) ) ;
478
460
pats. push ( self . ecx . pat_ident ( DUMMY_SP , name) ) ;
479
- locals. push ( Context :: format_arg ( self . ecx , self . macsp , e. span , arg_ty,
480
- self . ecx . expr_ident ( e. span , name) ) ) ;
461
+ for ref arg_ty in self . arg_types [ i] . iter ( ) {
462
+ locals. push ( Context :: format_arg ( self . ecx , self . macsp , e. span , arg_ty,
463
+ self . ecx . expr_ident ( e. span , name) ) ) ;
464
+ }
481
465
heads. push ( self . ecx . expr_addr_of ( e. span , e) ) ;
482
466
}
483
467
@@ -597,7 +581,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
597
581
args : Vec < P < ast:: Expr > > ,
598
582
names : HashMap < String , usize > )
599
583
-> P < ast:: Expr > {
600
- let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| None ) . collect ( ) ;
584
+ let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
601
585
let macsp = ecx. call_site ( ) ;
602
586
// Expand the format literal so that efmt.span will have a backtrace. This
603
587
// is essential for locating a bug when the format literal is generated in
@@ -609,6 +593,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
609
593
arg_types : arg_types,
610
594
names : names,
611
595
curarg : 0 ,
596
+ arg_index_map : Vec :: new ( ) ,
612
597
literal : String :: new ( ) ,
613
598
pieces : Vec :: new ( ) ,
614
599
str_pieces : Vec :: new ( ) ,
@@ -638,8 +623,11 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
638
623
}
639
624
}
640
625
626
+ cx. build_index_map ( ) ;
627
+
628
+ let mut arg_index_consumed = vec ! [ 0usize ; cx. arg_index_map. len( ) ] ;
641
629
for piece in pieces {
642
- if let Some ( piece) = cx. trans_piece ( & piece) {
630
+ if let Some ( piece) = cx. trans_piece ( & piece, & mut arg_index_consumed ) {
643
631
let s = cx. trans_literal_string ( ) ;
644
632
cx. str_pieces . push ( s) ;
645
633
cx. pieces . push ( piece) ;
@@ -659,7 +647,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
659
647
// Make sure that all arguments were used and all arguments have types.
660
648
let num_pos_args = cx. args . len ( ) - cx. names . len ( ) ;
661
649
for ( i, ty) in cx. arg_types . iter ( ) . enumerate ( ) {
662
- if ty. is_none ( ) {
650
+ if ty. len ( ) == 0 {
663
651
let msg = if i >= num_pos_args {
664
652
// named argument
665
653
"named argument never used"
0 commit comments