use syntax::parse::token;
use syntax::ptr::P;
use syntax::symbol::{Symbol, sym};
-use syntax::tokenstream;
+use syntax::tokenstream::TokenStream;
use syntax_pos::{MultiSpan, Span};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
fn parse_args<'a>(
ecx: &mut ExtCtxt<'a>,
sp: Span,
- tts: &[tokenstream::TokenTree]
+ tts: TokenStream,
) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>), DiagnosticBuilder<'a>> {
let mut args = Vec::<P<ast::Expr>>::new();
let mut names = FxHashMap::<Symbol, usize>::default();
}
let fmtstr = p.parse_expr()?;
+ let mut first = true;
let mut named = false;
while p.token != token::Eof {
if !p.eat(&token::Comma) {
- let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
- err.span_label(p.token.span, "expected `,`");
- p.maybe_annotate_with_ascription(&mut err, false);
- return Err(err);
+ if first {
+ // After `format!(""` we always expect *only* a comma...
+ let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+ err.span_label(p.token.span, "expected `,`");
+ p.maybe_annotate_with_ascription(&mut err, false);
+ return Err(err);
+ } else {
+ // ...after that delegate to `expect` to also include the other expected tokens.
+ return Err(p.expect(&token::Comma).err().unwrap());
+ }
}
+ first = false;
if p.token == token::Eof {
break;
} // accept trailing commas
&format!(
"{} positional argument{} in format string, but {}",
count,
- if count > 1 { "s" } else { "" },
+ if count != 1 { "s" } else { "" },
self.describe_num_args(),
),
);
// But the nested match expression is proved to perform not as well
// as series of let's; the first approach does.
let pat = self.ecx.pat_tuple(self.fmtsp, pats);
- let arm = self.ecx.arm(self.fmtsp, vec![pat], args_array);
+ let arm = self.ecx.arm(self.fmtsp, pat, args_array);
let head = self.ecx.expr(self.fmtsp, ast::ExprKind::Tup(heads));
let result = self.ecx.expr_match(self.fmtsp, head, vec![arm]);
fn expand_format_args_impl<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
mut sp: Span,
- tts: &[tokenstream::TokenTree],
+ tts: TokenStream,
nl: bool,
) -> Box<dyn base::MacResult + 'cx> {
sp = ecx.with_def_site_ctxt(sp);
pub fn expand_format_args<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
- tts: &[tokenstream::TokenTree],
+ tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
expand_format_args_impl(ecx, sp, tts, false)
}
pub fn expand_format_args_nl<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
- tts: &[tokenstream::TokenTree],
+ tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
expand_format_args_impl(ecx, sp, tts, true)
}