Skip to content

Commit a6ea373

Browse files
authored
Unrolled build for rust-lang#133603
Rollup merge of rust-lang#133603 - dtolnay:precedence, r=lcnr Eliminate magic numbers from expression precedence Context: see rust-lang#133140. This PR continues on backporting Syn's expression precedence design into rustc. Rustc's design used mysterious integer quantities represented variously as `i8` or `usize` (e.g. `PREC_CLOSURE = -40i8`), a special significance around `0` that is never named, and an extra `PREC_FORCE_PAREN` precedence level that does not correspond to any expression. Syn's design uses a C-like enum with variants that clearly correspond to specific sets of expression kinds. This PR is a refactoring that has no intended behavior change on its own, but it unblocks other precedence work that rustc's precedence design was poorly suited to accommodate. - Asymmetrical precedence, so that a pretty-printer can tell `(return 1) + 1` needs parens but `1 + return 1` does not. - Squashing the `Closure` and `Jump` cases into a single precedence level. - Numerous remaining false positives and false negatives in rustc pretty-printer's parenthesization of macro metavariables, for example in `$e < rhs` where $e is `lhs as Thing<T>`. FYI `@fmease` &mdash; you don't need to review if rustbot picks someone else, but you mentioned being interested in the followup PRs.
2 parents 32eea2f + 7ced18f commit a6ea373

File tree

19 files changed

+222
-198
lines changed

19 files changed

+222
-198
lines changed

compiler/rustc_ast/src/ast.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ pub use crate::format::*;
3939
use crate::ptr::P;
4040
use crate::token::{self, CommentKind, Delimiter};
4141
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
42-
use crate::util::parser::{
43-
AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
44-
};
42+
use crate::util::parser::{AssocOp, ExprPrecedence};
4543

4644
/// A "Label" is an identifier of some point in sources,
4745
/// e.g. in the following code:
@@ -1317,29 +1315,29 @@ impl Expr {
13171315
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
13181316
}
13191317

1320-
pub fn precedence(&self) -> i8 {
1318+
pub fn precedence(&self) -> ExprPrecedence {
13211319
match self.kind {
1322-
ExprKind::Closure(..) => PREC_CLOSURE,
1320+
ExprKind::Closure(..) => ExprPrecedence::Closure,
13231321

13241322
ExprKind::Break(..)
13251323
| ExprKind::Continue(..)
13261324
| ExprKind::Ret(..)
13271325
| ExprKind::Yield(..)
13281326
| ExprKind::Yeet(..)
1329-
| ExprKind::Become(..) => PREC_JUMP,
1327+
| ExprKind::Become(..) => ExprPrecedence::Jump,
13301328

13311329
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
13321330
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
13331331
// ensures that `pprust` will add parentheses in the right places to get the desired
13341332
// parse.
1335-
ExprKind::Range(..) => PREC_RANGE,
1333+
ExprKind::Range(..) => ExprPrecedence::Range,
13361334

13371335
// Binop-like expr kinds, handled by `AssocOp`.
1338-
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
1339-
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
1336+
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(),
1337+
ExprKind::Cast(..) => ExprPrecedence::Cast,
13401338

13411339
ExprKind::Assign(..) |
1342-
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
1340+
ExprKind::AssignOp(..) => ExprPrecedence::Assign,
13431341

13441342
// Unary, prefix
13451343
ExprKind::AddrOf(..)
@@ -1348,7 +1346,7 @@ impl Expr {
13481346
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
13491347
// but we need to print `(let _ = a) < b` as-is with parens.
13501348
| ExprKind::Let(..)
1351-
| ExprKind::Unary(..) => PREC_PREFIX,
1349+
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
13521350

13531351
// Never need parens
13541352
ExprKind::Array(_)
@@ -1381,7 +1379,7 @@ impl Expr {
13811379
| ExprKind::Underscore
13821380
| ExprKind::While(..)
13831381
| ExprKind::Err(_)
1384-
| ExprKind::Dummy => PREC_UNAMBIGUOUS,
1382+
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
13851383
}
13861384
}
13871385

compiler/rustc_ast/src/util/parser.rs

+51-24
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,21 @@ impl AssocOp {
128128
}
129129

130130
/// Gets the precedence of this operator
131-
pub fn precedence(&self) -> usize {
131+
pub fn precedence(&self) -> ExprPrecedence {
132132
use AssocOp::*;
133133
match *self {
134-
As => 14,
135-
Multiply | Divide | Modulus => 13,
136-
Add | Subtract => 12,
137-
ShiftLeft | ShiftRight => 11,
138-
BitAnd => 10,
139-
BitXor => 9,
140-
BitOr => 8,
141-
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
142-
LAnd => 6,
143-
LOr => 5,
144-
DotDot | DotDotEq => 4,
145-
Assign | AssignOp(_) => 2,
134+
As => ExprPrecedence::Cast,
135+
Multiply | Divide | Modulus => ExprPrecedence::Product,
136+
Add | Subtract => ExprPrecedence::Sum,
137+
ShiftLeft | ShiftRight => ExprPrecedence::Shift,
138+
BitAnd => ExprPrecedence::BitAnd,
139+
BitXor => ExprPrecedence::BitXor,
140+
BitOr => ExprPrecedence::BitOr,
141+
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => ExprPrecedence::Compare,
142+
LAnd => ExprPrecedence::LAnd,
143+
LOr => ExprPrecedence::LOr,
144+
DotDot | DotDotEq => ExprPrecedence::Range,
145+
Assign | AssignOp(_) => ExprPrecedence::Assign,
146146
}
147147
}
148148

@@ -229,26 +229,53 @@ impl AssocOp {
229229
}
230230
}
231231

232-
pub const PREC_CLOSURE: i8 = -40;
233-
pub const PREC_JUMP: i8 = -30;
234-
pub const PREC_RANGE: i8 = -10;
235-
// The range 2..=14 is reserved for AssocOp binary operator precedences.
236-
pub const PREC_PREFIX: i8 = 50;
237-
pub const PREC_UNAMBIGUOUS: i8 = 60;
238-
pub const PREC_FORCE_PAREN: i8 = 100;
232+
#[derive(Clone, Copy, PartialEq, PartialOrd)]
233+
pub enum ExprPrecedence {
234+
Closure,
235+
// return, break, yield
236+
Jump,
237+
// = += -= *= /= %= &= |= ^= <<= >>=
238+
Assign,
239+
// .. ..=
240+
Range,
241+
// ||
242+
LOr,
243+
// &&
244+
LAnd,
245+
// == != < > <= >=
246+
Compare,
247+
// |
248+
BitOr,
249+
// ^
250+
BitXor,
251+
// &
252+
BitAnd,
253+
// << >>
254+
Shift,
255+
// + -
256+
Sum,
257+
// * / %
258+
Product,
259+
// as
260+
Cast,
261+
// unary - * ! & &mut
262+
Prefix,
263+
// paths, loops, function calls, array indexing, field expressions, method calls
264+
Unambiguous,
265+
}
239266

240267
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
241-
pub fn prec_let_scrutinee_needs_par() -> usize {
242-
AssocOp::LAnd.precedence()
268+
pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
269+
ExprPrecedence::LAnd
243270
}
244271

245272
/// Suppose we have `let _ = e` and the `order` of `e`.
246273
/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
247274
///
248275
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
249276
/// Can we print this as `let _ = a OP b`?
250-
pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
251-
order <= prec_let_scrutinee_needs_par() as i8
277+
pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
278+
order <= prec_let_scrutinee_needs_par()
252279
}
253280

254281
/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any

0 commit comments

Comments
 (0)