1
Fork 0

Parameterise Parser::{recover_unclosed_char,handle_missing_lit}.

These two methods both produce a `MetaItemLit`, and then some of the
call sites convert the `MetaItemLit` to a `token::Lit` with
`as_token_lit`.

This commit parameterises these two methods with a `mk_lit_char`
closure, which can be used to produce either `MetaItemLit` or
`token::Lit` directly as necessary.
This commit is contained in:
Nicholas Nethercote 2022-12-05 14:39:56 +11:00
parent 4ae956f600
commit d887615b4c
2 changed files with 49 additions and 30 deletions

View file

@ -1543,15 +1543,16 @@ impl<'a> Parser<'a> {
&& (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
|| self.token.is_op()) || self.token.is_op())
{ {
let lit = self.recover_unclosed_char(label_.ident, |self_| { let (lit, _) =
self_.sess.create_err(UnexpectedTokenAfterLabel { self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
span: self_.token.span, self_.sess.create_err(UnexpectedTokenAfterLabel {
remove_label: None, span: self_.token.span,
enclose_in_block: None, remove_label: None,
}) enclose_in_block: None,
}); })
});
consume_colon = false; consume_colon = false;
Ok(self.mk_expr(lo, ExprKind::Lit(lit.as_token_lit()))) Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
} else if !ate_colon } else if !ate_colon
&& (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
{ {
@ -1626,12 +1627,13 @@ impl<'a> Parser<'a> {
Ok(expr) Ok(expr)
} }
/// Emit an error when a char is parsed as a lifetime because of a missing quote /// Emit an error when a char is parsed as a lifetime because of a missing quote.
pub(super) fn recover_unclosed_char( pub(super) fn recover_unclosed_char<L>(
&self, &self,
lifetime: Ident, lifetime: Ident,
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>, err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>,
) -> ast::MetaItemLit { ) -> L {
if let Some(mut diag) = if let Some(mut diag) =
self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar)
{ {
@ -1653,12 +1655,7 @@ impl<'a> Parser<'a> {
.emit(); .emit();
} }
let name = lifetime.without_first_quote().name; let name = lifetime.without_first_quote().name;
ast::MetaItemLit { mk_lit_char(name, lifetime.span)
symbol: name,
suffix: None,
kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
span: lifetime.span,
}
} }
/// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
@ -1785,7 +1782,23 @@ impl<'a> Parser<'a> {
} }
} }
fn handle_missing_lit(&mut self) -> PResult<'a, MetaItemLit> { pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {
(token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
}
fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
ast::MetaItemLit {
symbol: name,
suffix: None,
kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
span,
}
}
fn handle_missing_lit<L>(
&mut self,
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
) -> PResult<'a, L> {
if let token::Interpolated(inner) = &self.token.kind { if let token::Interpolated(inner) = &self.token.kind {
let expr = match inner.as_ref() { let expr = match inner.as_ref() {
token::NtExpr(expr) => Some(expr), token::NtExpr(expr) => Some(expr),
@ -1809,7 +1822,7 @@ impl<'a> Parser<'a> {
// On an error path, eagerly consider a lifetime to be an unclosed character lit // On an error path, eagerly consider a lifetime to be an unclosed character lit
if self.token.is_lifetime() { if self.token.is_lifetime() {
let lt = self.expect_lifetime(); let lt = self.expect_lifetime();
Ok(self.recover_unclosed_char(lt.ident, err)) Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))
} else { } else {
Err(err(self)) Err(err(self))
} }
@ -1818,11 +1831,13 @@ impl<'a> Parser<'a> {
pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> { pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {
self.parse_opt_token_lit() self.parse_opt_token_lit()
.ok_or(()) .ok_or(())
.or_else(|()| self.handle_missing_lit().map(|lit| (lit.as_token_lit(), lit.span))) .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))
} }
pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> { pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {
self.parse_opt_meta_item_lit().ok_or(()).or_else(|()| self.handle_missing_lit()) self.parse_opt_meta_item_lit()
.ok_or(())
.or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))
} }
fn recover_after_dot(&mut self) -> Option<Token> { fn recover_after_dot(&mut self) -> Option<Token> {

View file

@ -411,16 +411,20 @@ impl<'a> Parser<'a> {
{ {
// Recover a `'a` as a `'a'` literal // Recover a `'a` as a `'a'` literal
let lt = self.expect_lifetime(); let lt = self.expect_lifetime();
let lit = self.recover_unclosed_char(lt.ident, |self_| { let (lit, _) =
let expected = expected.unwrap_or("pattern"); self.recover_unclosed_char(lt.ident, Parser::mk_token_lit_char, |self_| {
let msg = let expected = expected.unwrap_or("pattern");
format!("expected {}, found {}", expected, super::token_descr(&self_.token)); let msg = format!(
"expected {}, found {}",
expected,
super::token_descr(&self_.token)
);
let mut err = self_.struct_span_err(self_.token.span, &msg); let mut err = self_.struct_span_err(self_.token.span, &msg);
err.span_label(self_.token.span, format!("expected {}", expected)); err.span_label(self_.token.span, format!("expected {}", expected));
err err
}); });
PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit.as_token_lit()))) PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
} else { } else {
// Try to parse everything else as literal with optional minus // Try to parse everything else as literal with optional minus
match self.parse_literal_maybe_minus() { match self.parse_literal_maybe_minus() {