@@ -50,7 +50,8 @@ struct Context<'a, 'b:'a> {
5050 /// Named expressions are resolved early, and are appended to the end of
5151 /// argument expressions.
5252 args : Vec < P < ast:: Expr > > ,
53- arg_types : Vec < Vec < ArgumentType > > ,
53+ arg_types : Vec < Vec < usize > > ,
54+ arg_unique_types : Vec < Vec < ArgumentType > > ,
5455 /// Map from named arguments to their resolved indices.
5556 names : HashMap < String , usize > ,
5657
@@ -69,7 +70,7 @@ struct Context<'a, 'b:'a> {
6970 /// corresponding to each positional argument, and number of references
7071 /// consumed so far for each argument, to facilitate correct `Position`
7172 /// mapping in `trans_piece`.
72- arg_index_map : Vec < usize > ,
73+ arg_index_map : Vec < Vec < usize > > ,
7374
7475 count_args_index_offset : usize ,
7576
@@ -234,7 +235,17 @@ impl<'a, 'b> Context<'a, 'b> {
234235 }
235236 match ty {
236237 Placeholder ( _) => {
237- self . arg_types [ arg] . push ( ty) ;
238+ // record every (position, type) combination only once
239+ let ref mut seen_ty = self . arg_unique_types [ arg] ;
240+ let i = match seen_ty. iter ( ) . position ( |x| * x == ty) {
241+ Some ( i) => i,
242+ None => {
243+ let i = seen_ty. len ( ) ;
244+ seen_ty. push ( ty) ;
245+ i
246+ }
247+ } ;
248+ self . arg_types [ arg] . push ( i) ;
238249 }
239250 Count => {
240251 match self . count_positions . entry ( arg) {
@@ -274,8 +285,13 @@ impl<'a, 'b> Context<'a, 'b> {
274285
275286 // Generate mapping for positional args
276287 for i in 0 ..args_len {
277- self . arg_index_map . push ( sofar) ;
278- sofar += self . arg_types [ i] . len ( ) ;
288+ let ref arg_types = self . arg_types [ i] ;
289+ let mut arg_offsets = Vec :: with_capacity ( arg_types. len ( ) ) ;
290+ for offset in arg_types {
291+ arg_offsets. push ( sofar + * offset) ;
292+ }
293+ self . arg_index_map . push ( arg_offsets) ;
294+ sofar += self . arg_unique_types [ i] . len ( ) ;
279295 }
280296
281297 // Record starting index for counts, which appear just
@@ -355,12 +371,13 @@ impl<'a, 'b> Context<'a, 'b> {
355371 parse:: ArgumentIs ( i) => {
356372 // Map to index in final generated argument array
357373 // in case of multiple types specified
358- let arg_idx = if self . args . len ( ) > i {
359- let arg_idx = self . arg_index_map [ i] + arg_index_consumed[ i] ;
360- arg_index_consumed[ i] += 1 ;
361- arg_idx
362- } else {
363- 0 // error already emitted elsewhere
374+ let arg_idx = match arg_index_consumed. get_mut ( i) {
375+ None => 0 , // error already emitted elsewhere
376+ Some ( offset) => {
377+ let arg_idx = self . arg_index_map [ i] [ * offset] ;
378+ * offset += 1 ;
379+ arg_idx
380+ }
364381 } ;
365382 pos ( "At" , Some ( arg_idx) )
366383 }
@@ -490,7 +507,7 @@ impl<'a, 'b> Context<'a, 'b> {
490507 for ( i, e) in self . args . into_iter ( ) . enumerate ( ) {
491508 let name = self . ecx . ident_of ( & format ! ( "__arg{}" , i) ) ;
492509 pats. push ( self . ecx . pat_ident ( DUMMY_SP , name) ) ;
493- for ref arg_ty in self . arg_types [ i] . iter ( ) {
510+ for ref arg_ty in self . arg_unique_types [ i] . iter ( ) {
494511 locals. push ( Context :: format_arg ( self . ecx , self . macsp , e. span , arg_ty,
495512 self . ecx . expr_ident ( e. span , name) ) ) ;
496513 }
@@ -626,6 +643,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
626643 names : HashMap < String , usize > )
627644 -> P < ast:: Expr > {
628645 let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
646+ let arg_unique_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
629647 let macsp = ecx. call_site ( ) ;
630648 // Expand the format literal so that efmt.span will have a backtrace. This
631649 // is essential for locating a bug when the format literal is generated in
@@ -635,6 +653,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
635653 ecx : ecx,
636654 args : args,
637655 arg_types : arg_types,
656+ arg_unique_types : arg_unique_types,
638657 names : names,
639658 curarg : 0 ,
640659 arg_index_map : Vec :: new ( ) ,
0 commit comments