Skip to content

Commit 965ed81

Browse files
authored
Rollup merge of #100277 - m-ou-se:format-args-1, r=compiler-errors
Simplify format_args builtin macro implementation. Instead of a FxHashMap<Symbol, (usize, Span)> for the named arguments, this now includes the name and span in the elements of the Vec<FormatArg> directly. The FxHashMap still exists to look up the index, but no longer contains the span. Looking up the name or span of an argument is now trivial and does not need the map anymore.
2 parents d6b6503 + a639fdb commit 965ed81

File tree

1 file changed

+64
-90
lines changed

1 file changed

+64
-90
lines changed

compiler/rustc_builtin_macros/src/format.rs

+64-90
Original file line numberDiff line numberDiff line change
@@ -130,64 +130,46 @@ impl PositionalNamedArgsLint {
130130
/// CountIsParam, which contains an index into the arguments.
131131
fn maybe_add_positional_named_arg(
132132
&mut self,
133-
current_positional_arg: usize,
134-
total_args_length: usize,
135-
format_argument_index: usize,
133+
arg: Option<&FormatArg>,
136134
ty: PositionalNamedArgType,
137135
cur_piece: usize,
138136
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
139-
names: &FxHashMap<Symbol, (usize, Span)>,
140137
has_formatting: bool,
141138
) {
142-
let start_of_named_args = total_args_length - names.len();
143-
if current_positional_arg >= start_of_named_args {
144-
self.maybe_push(
145-
format_argument_index,
146-
ty,
147-
cur_piece,
148-
inner_span_to_replace,
149-
names,
150-
has_formatting,
151-
)
139+
if let Some(arg) = arg {
140+
if let Some(name) = arg.name {
141+
self.push(name, ty, cur_piece, inner_span_to_replace, has_formatting)
142+
}
152143
}
153144
}
154145

155-
/// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional
156-
/// named arguments. If a named arg associated with `format_argument_index` cannot be found,
157-
/// a new item will not be added as the lint cannot be emitted in this case.
158-
fn maybe_push(
146+
/// Construct a PositionalNamedArg struct and push it into the vec of positional
147+
/// named arguments.
148+
fn push(
159149
&mut self,
160-
format_argument_index: usize,
150+
arg_name: Ident,
161151
ty: PositionalNamedArgType,
162152
cur_piece: usize,
163153
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
164-
names: &FxHashMap<Symbol, (usize, Span)>,
165154
has_formatting: bool,
166155
) {
167-
let named_arg = names
168-
.iter()
169-
.find(|&(_, &(index, _))| index == format_argument_index)
170-
.map(|found| found.clone());
171-
172-
if let Some((&replacement, &(_, positional_named_arg_span))) = named_arg {
173-
// In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
174-
// the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
175-
// `Precision`.
176-
let inner_span_to_replace = if ty == PositionalNamedArgType::Precision {
177-
inner_span_to_replace
178-
.map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end })
179-
} else {
180-
inner_span_to_replace
181-
};
182-
self.positional_named_args.push(PositionalNamedArg {
183-
ty,
184-
cur_piece,
185-
inner_span_to_replace,
186-
replacement,
187-
positional_named_arg_span,
188-
has_formatting,
189-
});
190-
}
156+
// In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
157+
// the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
158+
// `Precision`.
159+
let inner_span_to_replace = if ty == PositionalNamedArgType::Precision {
160+
inner_span_to_replace
161+
.map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end })
162+
} else {
163+
inner_span_to_replace
164+
};
165+
self.positional_named_args.push(PositionalNamedArg {
166+
ty,
167+
cur_piece,
168+
inner_span_to_replace,
169+
replacement: arg_name.name,
170+
positional_named_arg_span: arg_name.span,
171+
has_formatting,
172+
});
191173
}
192174
}
193175

@@ -211,15 +193,15 @@ struct Context<'a, 'b> {
211193
/// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]`
212194
/// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
213195
/// * `names` (in JSON): `{"foo": 2}`
214-
args: Vec<P<ast::Expr>>,
196+
args: Vec<FormatArg>,
215197
/// The number of arguments that were added by implicit capturing.
216198
num_captured_args: usize,
217199
/// Placeholder slot numbers indexed by argument.
218200
arg_types: Vec<Vec<usize>>,
219201
/// Unique format specs seen for each argument.
220202
arg_unique_types: Vec<Vec<ArgumentType>>,
221203
/// Map from named arguments to their resolved indices.
222-
names: FxHashMap<Symbol, (usize, Span)>,
204+
names: FxHashMap<Symbol, usize>,
223205

224206
/// The latest consecutive literal strings, or empty if there weren't any.
225207
literal: String,
@@ -282,7 +264,7 @@ struct Context<'a, 'b> {
282264

283265
pub struct FormatArg {
284266
expr: P<ast::Expr>,
285-
named: bool,
267+
name: Option<Ident>,
286268
}
287269

288270
/// Parses the arguments from the given list of tokens, returning the diagnostic
@@ -298,9 +280,9 @@ fn parse_args<'a>(
298280
ecx: &mut ExtCtxt<'a>,
299281
sp: Span,
300282
tts: TokenStream,
301-
) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, (usize, Span)>)> {
283+
) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, usize>)> {
302284
let mut args = Vec::<FormatArg>::new();
303-
let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
285+
let mut names = FxHashMap::<Symbol, usize>::default();
304286

305287
let mut p = ecx.new_parser_from_tts(tts);
306288

@@ -365,9 +347,9 @@ fn parse_args<'a>(
365347
p.bump();
366348
p.expect(&token::Eq)?;
367349
let e = p.parse_expr()?;
368-
if let Some((prev, _)) = names.get(&ident.name) {
350+
if let Some(&prev) = names.get(&ident.name) {
369351
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
370-
.span_label(args[*prev].expr.span, "previously here")
352+
.span_label(args[prev].expr.span, "previously here")
371353
.span_label(e.span, "duplicate argument")
372354
.emit();
373355
continue;
@@ -378,8 +360,8 @@ fn parse_args<'a>(
378360
// if the input is valid, we can simply append to the positional
379361
// args. And remember the names.
380362
let slot = args.len();
381-
names.insert(ident.name, (slot, ident.span));
382-
args.push(FormatArg { expr: e, named: true });
363+
names.insert(ident.name, slot);
364+
args.push(FormatArg { expr: e, name: Some(ident) });
383365
}
384366
_ => {
385367
let e = p.parse_expr()?;
@@ -389,12 +371,12 @@ fn parse_args<'a>(
389371
"positional arguments cannot follow named arguments",
390372
);
391373
err.span_label(e.span, "positional arguments must be before named arguments");
392-
for pos in names.values() {
393-
err.span_label(args[pos.0].expr.span, "named argument");
374+
for &pos in names.values() {
375+
err.span_label(args[pos].expr.span, "named argument");
394376
}
395377
err.emit();
396378
}
397-
args.push(FormatArg { expr: e, named: false });
379+
args.push(FormatArg { expr: e, name: None });
398380
}
399381
}
400382
}
@@ -410,8 +392,7 @@ impl<'a, 'b> Context<'a, 'b> {
410392
fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) {
411393
// NOTE: the `unwrap_or` branch is needed in case of invalid format
412394
// arguments, e.g., `format_args!("{foo}")`.
413-
let lookup =
414-
|s: &str| self.names.get(&Symbol::intern(s)).unwrap_or(&(0, Span::default())).0;
395+
let lookup = |s: &str| self.names.get(&Symbol::intern(s)).copied().unwrap_or(0);
415396

416397
match *p {
417398
parse::String(_) => {}
@@ -457,27 +438,21 @@ impl<'a, 'b> Context<'a, 'b> {
457438
let pos = match arg.position {
458439
parse::ArgumentIs(i) => {
459440
self.unused_names_lint.maybe_add_positional_named_arg(
460-
i,
461-
self.args.len(),
462-
i,
441+
self.args.get(i),
463442
PositionalNamedArgType::Arg,
464443
self.curpiece,
465444
Some(arg.position_span),
466-
&self.names,
467445
has_precision || has_width,
468446
);
469447

470448
Exact(i)
471449
}
472450
parse::ArgumentImplicitlyIs(i) => {
473451
self.unused_names_lint.maybe_add_positional_named_arg(
474-
i,
475-
self.args.len(),
476-
i,
452+
self.args.get(i),
477453
PositionalNamedArgType::Arg,
478454
self.curpiece,
479455
None,
480-
&self.names,
481456
has_precision || has_width,
482457
);
483458
Exact(i)
@@ -563,13 +538,10 @@ impl<'a, 'b> Context<'a, 'b> {
563538
parse::CountImplied | parse::CountIs(..) => {}
564539
parse::CountIsParam(i) => {
565540
self.unused_names_lint.maybe_add_positional_named_arg(
566-
i,
567-
self.args.len(),
568-
i,
541+
self.args.get(i),
569542
named_arg_type,
570543
self.curpiece,
571544
*inner_span,
572-
&self.names,
573545
true,
574546
);
575547
self.verify_arg_type(Exact(i), Count);
@@ -622,7 +594,7 @@ impl<'a, 'b> Context<'a, 'b> {
622594
);
623595
for arg in &self.args {
624596
// Point at the arguments that will be formatted.
625-
e.span_label(arg.span, "");
597+
e.span_label(arg.expr.span, "");
626598
}
627599
} else {
628600
let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip();
@@ -692,7 +664,7 @@ impl<'a, 'b> Context<'a, 'b> {
692664
);
693665
if let Some(arg) = self.args.get(pos) {
694666
e.span_label(
695-
arg.span,
667+
arg.expr.span,
696668
"this parameter corresponds to the precision flag",
697669
);
698670
}
@@ -771,7 +743,7 @@ impl<'a, 'b> Context<'a, 'b> {
771743
match self.names.get(&name) {
772744
Some(&idx) => {
773745
// Treat as positional arg.
774-
self.verify_arg_type(Capture(idx.0), ty)
746+
self.verify_arg_type(Capture(idx), ty)
775747
}
776748
None => {
777749
// For the moment capturing variables from format strings expanded from macros is
@@ -787,8 +759,11 @@ impl<'a, 'b> Context<'a, 'b> {
787759
self.fmtsp
788760
};
789761
self.num_captured_args += 1;
790-
self.args.push(self.ecx.expr_ident(span, Ident::new(name, span)));
791-
self.names.insert(name, (idx, span));
762+
self.args.push(FormatArg {
763+
expr: self.ecx.expr_ident(span, Ident::new(name, span)),
764+
name: Some(Ident::new(name, span)),
765+
});
766+
self.names.insert(name, idx);
792767
self.verify_arg_type(Capture(idx), ty)
793768
} else {
794769
let msg = format!("there is no argument named `{}`", name);
@@ -1054,11 +1029,11 @@ impl<'a, 'b> Context<'a, 'b> {
10541029
// evaluated a single time each, in the order written by the programmer,
10551030
// and that the surrounding future/generator (if any) is Send whenever
10561031
// possible.
1057-
let no_need_for_match =
1058-
nicely_ordered && !original_args.iter().skip(1).any(|e| may_contain_yield_point(e));
1032+
let no_need_for_match = nicely_ordered
1033+
&& !original_args.iter().skip(1).any(|arg| may_contain_yield_point(&arg.expr));
10591034

10601035
for (arg_index, arg_ty) in fmt_arg_index_and_ty {
1061-
let e = &mut original_args[arg_index];
1036+
let e = &mut original_args[arg_index].expr;
10621037
let span = e.span;
10631038
let arg = if no_need_for_match {
10641039
let expansion_span = e.span.with_ctxt(self.macsp.ctxt());
@@ -1087,7 +1062,9 @@ impl<'a, 'b> Context<'a, 'b> {
10871062
// span is otherwise unavailable in the MIR used by borrowck).
10881063
let heads = original_args
10891064
.into_iter()
1090-
.map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e))
1065+
.map(|arg| {
1066+
self.ecx.expr_addr_of(arg.expr.span.with_ctxt(self.macsp.ctxt()), arg.expr)
1067+
})
10911068
.collect();
10921069

10931070
let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
@@ -1220,7 +1197,7 @@ pub fn expand_preparsed_format_args(
12201197
sp: Span,
12211198
efmt: P<ast::Expr>,
12221199
args: Vec<FormatArg>,
1223-
names: FxHashMap<Symbol, (usize, Span)>,
1200+
names: FxHashMap<Symbol, usize>,
12241201
append_newline: bool,
12251202
) -> P<ast::Expr> {
12261203
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
@@ -1312,16 +1289,17 @@ pub fn expand_preparsed_format_args(
13121289
if err.should_be_replaced_with_positional_argument {
13131290
let captured_arg_span =
13141291
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
1315-
let positional_args = args.iter().filter(|arg| !arg.named).collect::<Vec<_>>();
1292+
let n_positional_args =
1293+
args.iter().rposition(|arg| arg.name.is_none()).map_or(0, |i| i + 1);
13161294
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
1317-
let span = match positional_args.last() {
1295+
let span = match args[..n_positional_args].last() {
13181296
Some(arg) => arg.expr.span,
13191297
None => fmt_sp,
13201298
};
13211299
e.multipart_suggestion_verbose(
13221300
"consider using a positional formatting argument instead",
13231301
vec![
1324-
(captured_arg_span, positional_args.len().to_string()),
1302+
(captured_arg_span, n_positional_args.to_string()),
13251303
(span.shrink_to_hi(), format!(", {}", arg)),
13261304
],
13271305
Applicability::MachineApplicable,
@@ -1338,11 +1316,9 @@ pub fn expand_preparsed_format_args(
13381316
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
13391317
.collect();
13401318

1341-
let named_pos: FxHashSet<usize> = names.values().cloned().map(|(i, _)| i).collect();
1342-
13431319
let mut cx = Context {
13441320
ecx,
1345-
args: args.into_iter().map(|arg| arg.expr).collect(),
1321+
args,
13461322
num_captured_args: 0,
13471323
arg_types,
13481324
arg_unique_types,
@@ -1410,14 +1386,12 @@ pub fn expand_preparsed_format_args(
14101386
.enumerate()
14111387
.filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
14121388
.map(|(i, _)| {
1413-
let msg = if named_pos.contains(&i) {
1414-
// named argument
1389+
let msg = if cx.args[i].name.is_some() {
14151390
"named argument never used"
14161391
} else {
1417-
// positional argument
14181392
"argument never used"
14191393
};
1420-
(cx.args[i].span, msg)
1394+
(cx.args[i].expr.span, msg)
14211395
})
14221396
.collect::<Vec<_>>();
14231397

0 commit comments

Comments
 (0)