Rollup merge of #136846 - nnethercote:make-AssocOp-more-like-ExprKind, r=spastorino
Make `AssocOp` more like `ExprKind` This is step 1 of [MCP 831](https://github.com/rust-lang/compiler-team/issues/831). r? ``@estebank``
This commit is contained in:
commit
4ecca4c09c
11 changed files with 205 additions and 374 deletions
|
@ -1350,13 +1350,13 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
return match (op.node, &outer_op.node) {
|
||||
// `x == y == z`
|
||||
(BinOpKind::Eq, AssocOp::Equal) |
|
||||
(BinOpKind::Eq, AssocOp::Binary(BinOpKind::Eq)) |
|
||||
// `x < y < z` and friends.
|
||||
(BinOpKind::Lt, AssocOp::Less | AssocOp::LessEqual) |
|
||||
(BinOpKind::Le, AssocOp::LessEqual | AssocOp::Less) |
|
||||
(BinOpKind::Lt, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
|
||||
(BinOpKind::Le, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
|
||||
// `x > y > z` and friends.
|
||||
(BinOpKind::Gt, AssocOp::Greater | AssocOp::GreaterEqual) |
|
||||
(BinOpKind::Ge, AssocOp::GreaterEqual | AssocOp::Greater) => {
|
||||
(BinOpKind::Gt, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) |
|
||||
(BinOpKind::Ge, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) => {
|
||||
let expr_to_str = |e: &Expr| {
|
||||
self.span_to_snippet(e.span)
|
||||
.unwrap_or_else(|_| pprust::expr_to_string(e))
|
||||
|
@ -1368,7 +1368,10 @@ impl<'a> Parser<'a> {
|
|||
false // Keep the current parse behavior, where the AST is `(x < y) < z`.
|
||||
}
|
||||
// `x == y < z`
|
||||
(BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => {
|
||||
(
|
||||
BinOpKind::Eq,
|
||||
AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge)
|
||||
) => {
|
||||
// Consume `z`/outer-op-rhs.
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
match self.parse_expr() {
|
||||
|
@ -1389,7 +1392,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
// `x > y == z`
|
||||
(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, AssocOp::Equal) => {
|
||||
(
|
||||
BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge,
|
||||
AssocOp::Binary(BinOpKind::Eq)
|
||||
) => {
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
// At this point it is always valid to enclose the lhs in parentheses, no
|
||||
// further checks are necessary.
|
||||
|
@ -1457,10 +1463,10 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Include `<` to provide this recommendation even in a case like
|
||||
// `Foo<Bar<Baz<Qux, ()>>>`
|
||||
if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Less
|
||||
|| outer_op.node == AssocOp::Greater
|
||||
if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Binary(BinOpKind::Lt)
|
||||
|| outer_op.node == AssocOp::Binary(BinOpKind::Gt)
|
||||
{
|
||||
if outer_op.node == AssocOp::Less {
|
||||
if outer_op.node == AssocOp::Binary(BinOpKind::Lt) {
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
self.bump();
|
||||
// So far we have parsed `foo<bar<`, consume the rest of the type args.
|
||||
|
@ -2635,10 +2641,12 @@ impl<'a> Parser<'a> {
|
|||
) -> PResult<'a, GenericArg> {
|
||||
let is_op_or_dot = AssocOp::from_token(&self.token)
|
||||
.and_then(|op| {
|
||||
if let AssocOp::Greater
|
||||
| AssocOp::Less
|
||||
| AssocOp::ShiftRight
|
||||
| AssocOp::GreaterEqual
|
||||
if let AssocOp::Binary(
|
||||
BinOpKind::Gt
|
||||
| BinOpKind::Lt
|
||||
| BinOpKind::Shr
|
||||
| BinOpKind::Ge
|
||||
)
|
||||
// Don't recover from `foo::<bar = baz>`, because this could be an attempt to
|
||||
// assign a value to a defaulted generic parameter.
|
||||
| AssocOp::Assign
|
||||
|
|
|
@ -171,7 +171,7 @@ impl<'a> Parser<'a> {
|
|||
break;
|
||||
}
|
||||
// Check for deprecated `...` syntax
|
||||
if self.token == token::DotDotDot && op.node == AssocOp::DotDotEq {
|
||||
if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) {
|
||||
self.err_dotdotdot_syntax(self.token.span);
|
||||
}
|
||||
|
||||
|
@ -188,17 +188,12 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
// Look for JS' `===` and `!==` and recover
|
||||
if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual)
|
||||
if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node
|
||||
&& self.token == token::Eq
|
||||
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||
{
|
||||
let sp = op.span.to(self.token.span);
|
||||
let sugg = match op.node {
|
||||
AssocOp::Equal => "==",
|
||||
AssocOp::NotEqual => "!=",
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.into();
|
||||
let sugg = bop.as_str().into();
|
||||
let invalid = format!("{sugg}=");
|
||||
self.dcx().emit_err(errors::InvalidComparisonOperator {
|
||||
span: sp,
|
||||
|
@ -213,7 +208,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
// Look for PHP's `<>` and recover
|
||||
if op.node == AssocOp::Less
|
||||
if op.node == AssocOp::Binary(BinOpKind::Lt)
|
||||
&& self.token == token::Gt
|
||||
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||
{
|
||||
|
@ -231,7 +226,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
// Look for C++'s `<=>` and recover
|
||||
if op.node == AssocOp::LessEqual
|
||||
if op.node == AssocOp::Binary(BinOpKind::Le)
|
||||
&& self.token == token::Gt
|
||||
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||
{
|
||||
|
@ -269,13 +264,13 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let op = op.node;
|
||||
// Special cases:
|
||||
if op == AssocOp::As {
|
||||
if op == AssocOp::Cast {
|
||||
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
|
||||
continue;
|
||||
} else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
|
||||
} else if let AssocOp::Range(limits) = op {
|
||||
// If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
|
||||
// generalise it to the Fixity::None code.
|
||||
lhs = self.parse_expr_range(prec, lhs, op, cur_op_span)?;
|
||||
lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -290,46 +285,16 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
|
||||
lhs = match op {
|
||||
AssocOp::Add
|
||||
| AssocOp::Subtract
|
||||
| AssocOp::Multiply
|
||||
| AssocOp::Divide
|
||||
| AssocOp::Modulus
|
||||
| AssocOp::LAnd
|
||||
| AssocOp::LOr
|
||||
| AssocOp::BitXor
|
||||
| AssocOp::BitAnd
|
||||
| AssocOp::BitOr
|
||||
| AssocOp::ShiftLeft
|
||||
| AssocOp::ShiftRight
|
||||
| AssocOp::Equal
|
||||
| AssocOp::Less
|
||||
| AssocOp::LessEqual
|
||||
| AssocOp::NotEqual
|
||||
| AssocOp::Greater
|
||||
| AssocOp::GreaterEqual => {
|
||||
let ast_op = op.to_ast_binop().unwrap();
|
||||
AssocOp::Binary(ast_op) => {
|
||||
let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
|
||||
self.mk_expr(span, binary)
|
||||
}
|
||||
AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),
|
||||
AssocOp::AssignOp(k) => {
|
||||
let aop = match k {
|
||||
token::Plus => BinOpKind::Add,
|
||||
token::Minus => BinOpKind::Sub,
|
||||
token::Star => BinOpKind::Mul,
|
||||
token::Slash => BinOpKind::Div,
|
||||
token::Percent => BinOpKind::Rem,
|
||||
token::Caret => BinOpKind::BitXor,
|
||||
token::And => BinOpKind::BitAnd,
|
||||
token::Or => BinOpKind::BitOr,
|
||||
token::Shl => BinOpKind::Shl,
|
||||
token::Shr => BinOpKind::Shr,
|
||||
};
|
||||
AssocOp::AssignOp(aop) => {
|
||||
let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
|
||||
self.mk_expr(span, aopexpr)
|
||||
}
|
||||
AssocOp::As | AssocOp::DotDot | AssocOp::DotDotEq => {
|
||||
AssocOp::Cast | AssocOp::Range(_) => {
|
||||
self.dcx().span_bug(span, "AssocOp should have been handled by special case")
|
||||
}
|
||||
};
|
||||
|
@ -347,13 +312,14 @@ impl<'a> Parser<'a> {
|
|||
// An exhaustive check is done in the following block, but these are checked first
|
||||
// because they *are* ambiguous but also reasonable looking incorrect syntax, so we
|
||||
// want to keep their span info to improve diagnostics in these cases in a later stage.
|
||||
(true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
|
||||
(true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
|
||||
(true, Some(AssocOp::Add)) | // `{ 42 } + 42` (unary plus)
|
||||
(true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
|
||||
(true, Some(AssocOp::LOr)) | // `{ 42 } || 42` ("logical or" or closure)
|
||||
(true, Some(AssocOp::BitOr)) // `{ 42 } | 42` or `{ 42 } |x| 42`
|
||||
=> {
|
||||
(true, Some(AssocOp::Binary(
|
||||
BinOpKind::Mul | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
|
||||
BinOpKind::Sub | // `{ 42 } -5`
|
||||
BinOpKind::Add | // `{ 42 } + 42` (unary plus)
|
||||
BinOpKind::And | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
|
||||
BinOpKind::Or | // `{ 42 } || 42` ("logical or" or closure)
|
||||
BinOpKind::BitOr // `{ 42 } | 42` or `{ 42 } |x| 42`
|
||||
))) => {
|
||||
// These cases are ambiguous and can't be identified in the parser alone.
|
||||
//
|
||||
// Bitwise AND is left out because guessing intent is hard. We can make
|
||||
|
@ -392,23 +358,21 @@ impl<'a> Parser<'a> {
|
|||
// When parsing const expressions, stop parsing when encountering `>`.
|
||||
(
|
||||
Some(
|
||||
AssocOp::ShiftRight
|
||||
| AssocOp::Greater
|
||||
| AssocOp::GreaterEqual
|
||||
| AssocOp::AssignOp(token::BinOpToken::Shr),
|
||||
AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
|
||||
| AssocOp::AssignOp(BinOpKind::Shr),
|
||||
),
|
||||
_,
|
||||
) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
|
||||
return None;
|
||||
}
|
||||
// When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`.
|
||||
// When recovering patterns as expressions, stop parsing when encountering an
|
||||
// assignment `=`, an alternative `|`, or a range `..`.
|
||||
(
|
||||
Some(
|
||||
AssocOp::Assign
|
||||
| AssocOp::AssignOp(_)
|
||||
| AssocOp::BitOr
|
||||
| AssocOp::DotDot
|
||||
| AssocOp::DotDotEq,
|
||||
| AssocOp::Binary(BinOpKind::BitOr)
|
||||
| AssocOp::Range(_),
|
||||
),
|
||||
_,
|
||||
) if self.restrictions.contains(Restrictions::IS_PAT) => {
|
||||
|
@ -423,7 +387,7 @@ impl<'a> Parser<'a> {
|
|||
incorrect: "and".into(),
|
||||
sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span),
|
||||
});
|
||||
(AssocOp::LAnd, span)
|
||||
(AssocOp::Binary(BinOpKind::And), span)
|
||||
}
|
||||
(None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {
|
||||
self.dcx().emit_err(errors::InvalidLogicalOperator {
|
||||
|
@ -431,7 +395,7 @@ impl<'a> Parser<'a> {
|
|||
incorrect: "or".into(),
|
||||
sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span),
|
||||
});
|
||||
(AssocOp::LOr, span)
|
||||
(AssocOp::Binary(BinOpKind::Or), span)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
@ -449,7 +413,7 @@ impl<'a> Parser<'a> {
|
|||
&mut self,
|
||||
prec: ExprPrecedence,
|
||||
lhs: P<Expr>,
|
||||
op: AssocOp,
|
||||
limits: RangeLimits,
|
||||
cur_op_span: Span,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let rhs = if self.is_at_start_of_range_notation_rhs() {
|
||||
|
@ -465,8 +429,6 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
|
||||
let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
|
||||
let limits =
|
||||
if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
|
||||
let range = self.mk_range(Some(lhs), rhs, limits);
|
||||
Ok(self.mk_expr(span, range))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue