Skip to content

Commit 7180994

Browse files
committed
syntax_ext: format: de-duplicate argument objects
1 parent f457e6c commit 7180994

File tree

1 file changed

+31
-12
lines changed

1 file changed

+31
-12
lines changed

src/libsyntax_ext/format.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)