1
Fork 0

Eliminate precedence arithmetic from rustc_parse

This commit is contained in:
David Tolnay 2024-11-28 14:03:16 -08:00
parent ca8f47439e
commit 539c863eaf
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
3 changed files with 26 additions and 17 deletions

View file

@ -1,7 +1,7 @@
// ignore-tidy-filelength // ignore-tidy-filelength
use core::mem; use core::mem;
use core::ops::ControlFlow; use core::ops::{Bound, ControlFlow};
use ast::mut_visit::{self, MutVisitor}; use ast::mut_visit::{self, MutVisitor};
use ast::token::IdentIsRaw; use ast::token::IdentIsRaw;
@ -120,7 +120,7 @@ impl<'a> Parser<'a> {
r: Restrictions, r: Restrictions,
attrs: AttrWrapper, attrs: AttrWrapper,
) -> PResult<'a, (P<Expr>, bool)> { ) -> PResult<'a, (P<Expr>, bool)> {
self.with_res(r, |this| this.parse_expr_assoc_with(0, attrs)) self.with_res(r, |this| this.parse_expr_assoc_with(Bound::Unbounded, attrs))
} }
/// Parses an associative expression with operators of at least `min_prec` precedence. /// Parses an associative expression with operators of at least `min_prec` precedence.
@ -128,7 +128,7 @@ impl<'a> Parser<'a> {
/// followed by a subexpression (e.g. `1 + 2`). /// followed by a subexpression (e.g. `1 + 2`).
pub(super) fn parse_expr_assoc_with( pub(super) fn parse_expr_assoc_with(
&mut self, &mut self,
min_prec: usize, min_prec: Bound<usize>,
attrs: AttrWrapper, attrs: AttrWrapper,
) -> PResult<'a, (P<Expr>, bool)> { ) -> PResult<'a, (P<Expr>, bool)> {
let lhs = if self.token.is_range_separator() { let lhs = if self.token.is_range_separator() {
@ -144,7 +144,7 @@ impl<'a> Parser<'a> {
/// was actually parsed. /// was actually parsed.
pub(super) fn parse_expr_assoc_rest_with( pub(super) fn parse_expr_assoc_rest_with(
&mut self, &mut self,
min_prec: usize, min_prec: Bound<usize>,
starts_stmt: bool, starts_stmt: bool,
mut lhs: P<Expr>, mut lhs: P<Expr>,
) -> PResult<'a, (P<Expr>, bool)> { ) -> PResult<'a, (P<Expr>, bool)> {
@ -163,7 +163,11 @@ impl<'a> Parser<'a> {
self.restrictions self.restrictions
}; };
let prec = op.node.precedence(); let prec = op.node.precedence();
if prec < min_prec { if match min_prec {
Bound::Included(min_prec) => prec < min_prec,
Bound::Excluded(min_prec) => prec <= min_prec,
Bound::Unbounded => false,
} {
break; break;
} }
// Check for deprecated `...` syntax // Check for deprecated `...` syntax
@ -276,16 +280,16 @@ impl<'a> Parser<'a> {
} }
let fixity = op.fixity(); let fixity = op.fixity();
let prec_adjustment = match fixity { let min_prec = match fixity {
Fixity::Right => 0, Fixity::Right => Bound::Included(prec),
Fixity::Left => 1, Fixity::Left => Bound::Excluded(prec),
// We currently have no non-associative operators that are not handled above by // We currently have no non-associative operators that are not handled above by
// the special cases. The code is here only for future convenience. // the special cases. The code is here only for future convenience.
Fixity::None => 1, Fixity::None => Bound::Excluded(prec),
}; };
let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| { let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
let attrs = this.parse_outer_attributes()?; let attrs = this.parse_outer_attributes()?;
this.parse_expr_assoc_with(prec + prec_adjustment, attrs) this.parse_expr_assoc_with(min_prec, attrs)
})?; })?;
let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
@ -460,7 +464,7 @@ impl<'a> Parser<'a> {
let maybe_lt = self.token.clone(); let maybe_lt = self.token.clone();
let attrs = self.parse_outer_attributes()?; let attrs = self.parse_outer_attributes()?;
Some( Some(
self.parse_expr_assoc_with(prec + 1, attrs) self.parse_expr_assoc_with(Bound::Excluded(prec), attrs)
.map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))? .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?
.0, .0,
) )
@ -518,7 +522,7 @@ impl<'a> Parser<'a> {
let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() { let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
// RHS must be parsed with more associativity than the dots. // RHS must be parsed with more associativity than the dots.
let attrs = this.parse_outer_attributes()?; let attrs = this.parse_outer_attributes()?;
this.parse_expr_assoc_with(op.unwrap().precedence() + 1, attrs) this.parse_expr_assoc_with(Bound::Excluded(op.unwrap().precedence()), attrs)
.map(|(x, _)| (lo.to(x.span), Some(x))) .map(|(x, _)| (lo.to(x.span), Some(x)))
.map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))? .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
} else { } else {
@ -2643,7 +2647,8 @@ impl<'a> Parser<'a> {
self.expect(&token::Eq)?; self.expect(&token::Eq)?;
} }
let attrs = self.parse_outer_attributes()?; let attrs = self.parse_outer_attributes()?;
let (expr, _) = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), attrs)?; let (expr, _) =
self.parse_expr_assoc_with(Bound::Excluded(prec_let_scrutinee_needs_par()), attrs)?;
let span = lo.to(expr.span); let span = lo.to(expr.span);
Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered))) Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered)))
} }

View file

@ -1,3 +1,5 @@
use std::ops::Bound;
use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token}; use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token};
@ -435,8 +437,9 @@ impl<'a> Parser<'a> {
// Parse an associative expression such as `+ expr`, `% expr`, ... // Parse an associative expression such as `+ expr`, `% expr`, ...
// Assignments, ranges and `|` are disabled by [`Restrictions::IS_PAT`]. // Assignments, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
let Ok((expr, _)) = let Ok((expr, _)) = snapshot
snapshot.parse_expr_assoc_rest_with(0, false, expr).map_err(|err| err.cancel()) .parse_expr_assoc_rest_with(Bound::Unbounded, false, expr)
.map_err(|err| err.cancel())
else { else {
// We got a trailing method/operator, but that wasn't an expression. // We got a trailing method/operator, but that wasn't an expression.
return None; return None;

View file

@ -1,5 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::mem; use std::mem;
use std::ops::Bound;
use ast::Label; use ast::Label;
use rustc_ast as ast; use rustc_ast as ast;
@ -207,7 +208,7 @@ impl<'a> Parser<'a> {
// Perform this outside of the `collect_tokens` closure, since our // Perform this outside of the `collect_tokens` closure, since our
// outer attributes do not apply to this part of the expression. // outer attributes do not apply to this part of the expression.
let (expr, _) = self.with_res(Restrictions::STMT_EXPR, |this| { let (expr, _) = self.with_res(Restrictions::STMT_EXPR, |this| {
this.parse_expr_assoc_rest_with(0, true, expr) this.parse_expr_assoc_rest_with(Bound::Unbounded, true, expr)
})?; })?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
} else { } else {
@ -240,7 +241,7 @@ impl<'a> Parser<'a> {
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
let e = self.maybe_recover_from_bad_qpath(e)?; let e = self.maybe_recover_from_bad_qpath(e)?;
let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?; let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
let (e, _) = self.parse_expr_assoc_rest_with(0, false, e)?; let (e, _) = self.parse_expr_assoc_rest_with(Bound::Unbounded, false, e)?;
StmtKind::Expr(e) StmtKind::Expr(e)
}; };
Ok(self.mk_stmt(lo.to(hi), kind)) Ok(self.mk_stmt(lo.to(hi), kind))