1
Fork 0

Clarify parse_dot_suffix_expr.

For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
  holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
  token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
  `dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
  moves the `sym2` token into `prev_token`, and discards the `dot` token
  altogether.

New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
  unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
  wrong -- that value is never used. That comment was added in #77250,
  and AFAICT it has always been incorrect.

The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
This commit is contained in:
Nicholas Nethercote 2024-03-21 16:14:56 +11:00
parent 9c091160dc
commit dce0f7f5c2

View file

@ -16,7 +16,6 @@ use core::mem;
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::Spacing;
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
use rustc_ast::util::classify; use rustc_ast::util::classify;
use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
@ -999,6 +998,8 @@ impl<'a> Parser<'a> {
} }
pub fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> { pub fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
// At this point we've consumed something like `expr.` and `self.token` holds the token
// after the dot.
match self.token.uninterpolate().kind { match self.token.uninterpolate().kind {
token::Ident(..) => self.parse_dot_suffix(base, lo), token::Ident(..) => self.parse_dot_suffix(base, lo),
token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => { token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
@ -1010,39 +1011,41 @@ impl<'a> Parser<'a> {
Ok(match self.break_up_float(symbol, self.token.span) { Ok(match self.break_up_float(symbol, self.token.span) {
// 1e2 // 1e2
DestructuredFloat::Single(sym, _sp) => { DestructuredFloat::Single(sym, _sp) => {
// `foo.1e2`: a single complete dot access, fully consumed. We end up with
// the `1e2` token in `self.prev_token` and the following token in
// `self.token`.
let ident_span = self.token.span; let ident_span = self.token.span;
self.bump(); self.bump();
self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix) self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)
} }
// 1. // 1.
DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => { DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
// `foo.1.`: a single complete dot access and the start of another.
// We end up with the `sym` (`1`) token in `self.prev_token` and a dot in
// `self.token`.
assert!(suffix.is_none()); assert!(suffix.is_none());
self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span); self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);
let ident_span = self.token.span;
self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing)); self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None) self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)
} }
// 1.2 | 1.2e3 // 1.2 | 1.2e3
DestructuredFloat::MiddleDot( DestructuredFloat::MiddleDot(
symbol1, sym1,
ident1_span, ident1_span,
dot_span, _dot_span,
symbol2, sym2,
ident2_span, ident2_span,
) => { ) => {
self.token = Token::new(token::Ident(symbol1, IdentIsRaw::No), ident1_span); // `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with
// This needs to be `Spacing::Alone` to prevent regressions. // the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following
// See issue #76399 and PR #76285 for more details // token in `self.token`.
let ident_span = self.token.span;
self.bump_with((Token::new(token::Dot, dot_span), Spacing::Alone));
let base1 =
self.mk_expr_tuple_field_access(lo, ident_span, base, symbol1, None);
let next_token2 = let next_token2 =
Token::new(token::Ident(symbol2, IdentIsRaw::No), ident2_span); Token::new(token::Ident(sym2, IdentIsRaw::No), ident2_span);
self.bump_with((next_token2, self.token_spacing)); // `.` self.bump_with((next_token2, self.token_spacing));
let ident_span = self.token.span;
self.bump(); self.bump();
self.mk_expr_tuple_field_access(lo, ident_span, base1, symbol2, suffix) let base1 =
self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
} }
DestructuredFloat::Error => base, DestructuredFloat::Error => base,
}) })