summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/expr.rs')
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs151
1 files changed, 119 insertions, 32 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 1b28f3c97..7ede4fbc3 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -91,6 +91,18 @@ impl From<P<Expr>> for LhsExpr {
}
}
+#[derive(Debug)]
+enum DestructuredFloat {
+ /// 1e2
+ Single(Symbol, Span),
+ /// 1.
+ TrailingDot(Symbol, Span, Span),
+ /// 1.2 | 1.2e3
+ MiddleDot(Symbol, Span, Span, Symbol, Span),
+ /// Invalid
+ Error,
+}
+
impl<'a> Parser<'a> {
/// Parses an expression.
#[inline]
@@ -1001,9 +1013,15 @@ impl<'a> Parser<'a> {
}
fn error_unexpected_after_dot(&self) {
- // FIXME Could factor this out into non_fatal_unexpected or something.
let actual = pprust::token_to_string(&self.token);
- self.sess.emit_err(errors::UnexpectedTokenAfterDot { span: self.token.span, actual });
+ let span = self.token.span;
+ let sm = self.sess.source_map();
+ let (span, actual) = match (&self.token.kind, self.subparser_name) {
+ (token::Eof, Some(_)) if let Ok(actual) = sm.span_to_snippet(sm.next_point(span)) =>
+ (span.shrink_to_hi(), actual.into()),
+ _ => (span, actual),
+ };
+ self.sess.emit_err(errors::UnexpectedTokenAfterDot { span, actual });
}
// We need an identifier or integer, but the next token is a float.
@@ -1013,13 +1031,8 @@ impl<'a> Parser<'a> {
// support pushing "future tokens" (would be also helpful to `break_and_eat`), or
// we should break everything including floats into more basic proc-macro style
// tokens in the lexer (probably preferable).
- fn parse_expr_tuple_field_access_float(
- &mut self,
- lo: Span,
- base: P<Expr>,
- float: Symbol,
- suffix: Option<Symbol>,
- ) -> P<Expr> {
+ // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`.
+ fn break_up_float(&mut self, float: Symbol) -> DestructuredFloat {
#[derive(Debug)]
enum FloatComponent {
IdentLike(String),
@@ -1056,7 +1069,7 @@ impl<'a> Parser<'a> {
match &*components {
// 1e2
[IdentLike(i)] => {
- self.parse_expr_tuple_field_access(lo, base, Symbol::intern(&i), suffix, None)
+ DestructuredFloat::Single(Symbol::intern(&i), span)
}
// 1.
[IdentLike(i), Punct('.')] => {
@@ -1068,11 +1081,8 @@ impl<'a> Parser<'a> {
} else {
(span, span)
};
- assert!(suffix.is_none());
let symbol = Symbol::intern(&i);
- self.token = Token::new(token::Ident(symbol, false), ident_span);
- let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
- self.parse_expr_tuple_field_access(lo, base, symbol, None, Some(next_token))
+ DestructuredFloat::TrailingDot(symbol, ident_span, dot_span)
}
// 1.2 | 1.2e3
[IdentLike(i1), Punct('.'), IdentLike(i2)] => {
@@ -1088,16 +1098,8 @@ impl<'a> Parser<'a> {
(span, span, span)
};
let symbol1 = Symbol::intern(&i1);
- self.token = Token::new(token::Ident(symbol1, false), ident1_span);
- // This needs to be `Spacing::Alone` to prevent regressions.
- // See issue #76399 and PR #76285 for more details
- let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
- let base1 =
- self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
let symbol2 = Symbol::intern(&i2);
- let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
- self.bump_with((next_token2, self.token_spacing)); // `.`
- self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
+ DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span)
}
// 1e+ | 1e- (recovered)
[IdentLike(_), Punct('+' | '-')] |
@@ -1109,12 +1111,83 @@ impl<'a> Parser<'a> {
[IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
// See the FIXME about `TokenCursor` above.
self.error_unexpected_after_dot();
- base
+ DestructuredFloat::Error
}
_ => panic!("unexpected components in a float token: {:?}", components),
}
}
+ fn parse_expr_tuple_field_access_float(
+ &mut self,
+ lo: Span,
+ base: P<Expr>,
+ float: Symbol,
+ suffix: Option<Symbol>,
+ ) -> P<Expr> {
+ match self.break_up_float(float) {
+ // 1e2
+ DestructuredFloat::Single(sym, _sp) => {
+ self.parse_expr_tuple_field_access(lo, base, sym, suffix, None)
+ }
+ // 1.
+ DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
+ assert!(suffix.is_none());
+ self.token = Token::new(token::Ident(sym, false), ident_span);
+ let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
+ self.parse_expr_tuple_field_access(lo, base, sym, None, Some(next_token))
+ }
+ // 1.2 | 1.2e3
+ DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) => {
+ self.token = Token::new(token::Ident(symbol1, false), ident1_span);
+ // This needs to be `Spacing::Alone` to prevent regressions.
+ // See issue #76399 and PR #76285 for more details
+ let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
+ let base1 =
+ self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
+ let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
+ self.bump_with((next_token2, self.token_spacing)); // `.`
+ self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
+ }
+ DestructuredFloat::Error => base,
+ }
+ }
+
+ fn parse_field_name_maybe_tuple(&mut self) -> PResult<'a, ThinVec<Ident>> {
+ let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = self.token.kind
+ else {
+ return Ok(thin_vec![self.parse_field_name()?]);
+ };
+ Ok(match self.break_up_float(symbol) {
+ // 1e2
+ DestructuredFloat::Single(sym, sp) => {
+ self.bump();
+ thin_vec![Ident::new(sym, sp)]
+ }
+ // 1.
+ DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
+ assert!(suffix.is_none());
+ // Analogous to `Self::break_and_eat`
+ self.token_cursor.break_last_token = true;
+ // This might work, in cases like `1. 2`, and might not,
+ // in cases like `offset_of!(Ty, 1.)`. It depends on what comes
+ // after the float-like token, and therefore we have to make
+ // the other parts of the parser think that there is a dot literal.
+ self.token = Token::new(token::Ident(sym, false), sym_span);
+ self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
+ thin_vec![Ident::new(sym, sym_span)]
+ }
+ // 1.2 | 1.2e3
+ DestructuredFloat::MiddleDot(symbol1, ident1_span, _dot_span, symbol2, ident2_span) => {
+ self.bump();
+ thin_vec![Ident::new(symbol1, ident1_span), Ident::new(symbol2, ident2_span)]
+ }
+ DestructuredFloat::Error => {
+ self.bump();
+ thin_vec![Ident::new(symbol, self.prev_token.span)]
+ }
+ })
+ }
+
fn parse_expr_tuple_field_access(
&mut self,
lo: Span,
@@ -1363,6 +1436,8 @@ impl<'a> Parser<'a> {
self.parse_expr_yield()
} else if self.is_do_yeet() {
self.parse_expr_yeet()
+ } else if self.eat_keyword(kw::Become) {
+ self.parse_expr_become()
} else if self.check_keyword(kw::Let) {
self.parse_expr_let()
} else if self.eat_keyword(kw::Underscore) {
@@ -1679,6 +1754,16 @@ impl<'a> Parser<'a> {
self.maybe_recover_from_bad_qpath(expr)
}
+ /// Parse `"become" expr`, with `"become"` token already eaten.
+ fn parse_expr_become(&mut self) -> PResult<'a, P<Expr>> {
+ let lo = self.prev_token.span;
+ let kind = ExprKind::Become(self.parse_expr()?);
+ let span = lo.to(self.prev_token.span);
+ self.sess.gated_spans.gate(sym::explicit_tail_calls, span);
+ let expr = self.mk_expr(span, kind);
+ self.maybe_recover_from_bad_qpath(expr)
+ }
+
/// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
/// If the label is followed immediately by a `:` token, the label and `:` are
/// parsed as part of the expression (i.e. a labeled loop). The language team has
@@ -1821,10 +1906,11 @@ impl<'a> Parser<'a> {
let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
&TokenKind::CloseDelim(Delimiter::Parenthesis),
seq_sep,
- Parser::parse_field_name,
+ Parser::parse_field_name_maybe_tuple,
)?;
+ let fields = fields.into_iter().flatten().collect::<Vec<_>>();
let span = lo.to(self.token.span);
- Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
+ Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.into())))
}
/// Returns a string literal if the next token is a string literal.
@@ -1955,17 +2041,14 @@ impl<'a> Parser<'a> {
let recovered = self.recover_after_dot();
let token = recovered.as_ref().unwrap_or(&self.token);
match token::Lit::from_token(token) {
- Some(token_lit) => {
- match MetaItemLit::from_token_lit(token_lit, token.span) {
+ Some(lit) => {
+ match MetaItemLit::from_token_lit(lit, token.span) {
Ok(lit) => {
self.bump();
Some(lit)
}
Err(err) => {
- let span = token.span;
- let token::Literal(lit) = token.kind else {
- unreachable!();
- };
+ let span = token.uninterpolated_span();
self.bump();
report_lit_error(&self.sess, err, lit, span);
// Pack possible quotes and prefixes from the original literal into
@@ -2109,6 +2192,10 @@ impl<'a> Parser<'a> {
self.sess.emit_err(errors::InvalidBlockMacroSegment {
span: self.token.span,
context: lo.to(self.token.span),
+ wrap: errors::WrapInExplicitBlock {
+ lo: self.token.span.shrink_to_lo(),
+ hi: self.token.span.shrink_to_hi(),
+ },
});
}