Skip to content

Commit afe8d13

Browse files
committed
Use single source of truth for expr precedence
Introduce a new unified type that holds the expression precedence for both AST and HIR nodes.
1 parent 09efaaf commit afe8d13

File tree

6 files changed

+248
-115
lines changed

6 files changed

+248
-115
lines changed

src/librustc/hir/mod.rs

+63-1
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@ use util::nodemap::{NodeMap, FxHashSet};
3434
use syntax_pos::{Span, DUMMY_SP};
3535
use syntax::codemap::{self, Spanned};
3636
use syntax::abi::Abi;
37-
use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
37+
use syntax::ast::{self, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
3838
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
3939
use syntax::ext::hygiene::SyntaxContext;
4040
use syntax::ptr::P;
4141
use syntax::symbol::{Symbol, keywords};
4242
use syntax::tokenstream::TokenStream;
4343
use syntax::util::ThinVec;
44+
use syntax::ast::ExprPrecedence;
4445
use ty::AdtKind;
4546

4647
use rustc_data_structures::indexed_vec;
@@ -958,6 +959,31 @@ impl BinOp_ {
958959
}
959960
}
960961

962+
impl Into<ast::BinOpKind> for BinOp_ {
963+
fn into(self) -> ast::BinOpKind {
964+
match self {
965+
BiAdd => ast::BinOpKind::Add,
966+
BiSub => ast::BinOpKind::Sub,
967+
BiMul => ast::BinOpKind::Mul,
968+
BiDiv => ast::BinOpKind::Div,
969+
BiRem => ast::BinOpKind::Rem,
970+
BiAnd => ast::BinOpKind::And,
971+
BiOr => ast::BinOpKind::Or,
972+
BiBitXor => ast::BinOpKind::BitXor,
973+
BiBitAnd => ast::BinOpKind::BitAnd,
974+
BiBitOr => ast::BinOpKind::BitOr,
975+
BiShl => ast::BinOpKind::Shl,
976+
BiShr => ast::BinOpKind::Shr,
977+
BiEq => ast::BinOpKind::Eq,
978+
BiLt => ast::BinOpKind::Lt,
979+
BiLe => ast::BinOpKind::Le,
980+
BiNe => ast::BinOpKind::Ne,
981+
BiGe => ast::BinOpKind::Ge,
982+
BiGt => ast::BinOpKind::Gt,
983+
}
984+
}
985+
}
986+
961987
pub type BinOp = Spanned<BinOp_>;
962988

963989
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
@@ -1166,6 +1192,42 @@ pub struct Expr {
11661192
pub hir_id: HirId,
11671193
}
11681194

1195+
impl Expr {
1196+
pub fn precedence(&self) -> ExprPrecedence {
1197+
match self.node {
1198+
ExprBox(_) => ExprPrecedence::Box,
1199+
ExprArray(_) => ExprPrecedence::Array,
1200+
ExprCall(..) => ExprPrecedence::Call,
1201+
ExprMethodCall(..) => ExprPrecedence::MethodCall,
1202+
ExprTup(_) => ExprPrecedence::Tup,
1203+
ExprBinary(op, ..) => ExprPrecedence::Binary(op.node.into()),
1204+
ExprUnary(..) => ExprPrecedence::Unary,
1205+
ExprLit(_) => ExprPrecedence::Lit,
1206+
ExprType(..) | ExprCast(..) => ExprPrecedence::Cast,
1207+
ExprIf(..) => ExprPrecedence::If,
1208+
ExprWhile(..) => ExprPrecedence::While,
1209+
ExprLoop(..) => ExprPrecedence::Loop,
1210+
ExprMatch(..) => ExprPrecedence::Match,
1211+
ExprClosure(..) => ExprPrecedence::Closure,
1212+
ExprBlock(..) => ExprPrecedence::Block,
1213+
ExprAssign(..) => ExprPrecedence::Assign,
1214+
ExprAssignOp(..) => ExprPrecedence::AssignOp,
1215+
ExprField(..) => ExprPrecedence::Field,
1216+
ExprTupField(..) => ExprPrecedence::TupField,
1217+
ExprIndex(..) => ExprPrecedence::Index,
1218+
ExprPath(..) => ExprPrecedence::Path,
1219+
ExprAddrOf(..) => ExprPrecedence::AddrOf,
1220+
ExprBreak(..) => ExprPrecedence::Break,
1221+
ExprAgain(..) => ExprPrecedence::Continue,
1222+
ExprRet(..) => ExprPrecedence::Ret,
1223+
ExprInlineAsm(..) => ExprPrecedence::InlineAsm,
1224+
ExprStruct(..) => ExprPrecedence::Struct,
1225+
ExprRepeat(..) => ExprPrecedence::Repeat,
1226+
ExprYield(..) => ExprPrecedence::Yield,
1227+
}
1228+
}
1229+
}
1230+
11691231
impl fmt::Debug for Expr {
11701232
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
11711233
write!(f, "expr({}: {})", self.id,

src/librustc/hir/print.rs

+1-50
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@ impl<'a> State<'a> {
11041104
}
11051105

11061106
pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr, prec: i8) -> io::Result<()> {
1107-
let needs_par = expr_precedence(expr) < prec;
1107+
let needs_par = expr.precedence().order() < prec;
11081108
if needs_par {
11091109
self.popen()?;
11101110
}
@@ -2318,55 +2318,6 @@ fn stmt_ends_with_semi(stmt: &hir::Stmt_) -> bool {
23182318
}
23192319
}
23202320

2321-
2322-
fn expr_precedence(expr: &hir::Expr) -> i8 {
2323-
use syntax::util::parser::*;
2324-
2325-
match expr.node {
2326-
hir::ExprClosure(..) => PREC_CLOSURE,
2327-
2328-
hir::ExprBreak(..) |
2329-
hir::ExprAgain(..) |
2330-
hir::ExprRet(..) |
2331-
hir::ExprYield(..) => PREC_JUMP,
2332-
2333-
// Binop-like expr kinds, handled by `AssocOp`.
2334-
hir::ExprBinary(op, _, _) => bin_op_to_assoc_op(op.node).precedence() as i8,
2335-
2336-
hir::ExprCast(..) => AssocOp::As.precedence() as i8,
2337-
hir::ExprType(..) => AssocOp::Colon.precedence() as i8,
2338-
2339-
hir::ExprAssign(..) |
2340-
hir::ExprAssignOp(..) => AssocOp::Assign.precedence() as i8,
2341-
2342-
// Unary, prefix
2343-
hir::ExprBox(..) |
2344-
hir::ExprAddrOf(..) |
2345-
hir::ExprUnary(..) => PREC_PREFIX,
2346-
2347-
// Unary, postfix
2348-
hir::ExprCall(..) |
2349-
hir::ExprMethodCall(..) |
2350-
hir::ExprField(..) |
2351-
hir::ExprTupField(..) |
2352-
hir::ExprIndex(..) |
2353-
hir::ExprInlineAsm(..) => PREC_POSTFIX,
2354-
2355-
// Never need parens
2356-
hir::ExprArray(..) |
2357-
hir::ExprRepeat(..) |
2358-
hir::ExprTup(..) |
2359-
hir::ExprLit(..) |
2360-
hir::ExprPath(..) |
2361-
hir::ExprIf(..) |
2362-
hir::ExprWhile(..) |
2363-
hir::ExprLoop(..) |
2364-
hir::ExprMatch(..) |
2365-
hir::ExprBlock(..) |
2366-
hir::ExprStruct(..) => PREC_PAREN,
2367-
}
2368-
}
2369-
23702321
fn bin_op_to_assoc_op(op: hir::BinOp_) -> AssocOp {
23712322
use hir::BinOp_::*;
23722323
match op {

src/librustc_typeck/check/demand.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::infer::InferOk;
1515
use rustc::traits::ObligationCause;
1616

1717
use syntax::ast;
18-
use syntax::util::parser::{expr_precedence, AssocOp};
18+
use syntax::util::parser::AssocOp;
1919
use syntax_pos::{self, Span};
2020
use rustc::hir;
2121
use rustc::hir::print;
@@ -336,7 +336,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
336336
// For now, don't suggest casting with `as`.
337337
let can_cast = false;
338338

339-
let needs_paren = expr_precedence(expr) < (AssocOp::As.precedence() as i8);
339+
let needs_paren = expr.precedence().order() < (AssocOp::As.precedence() as i8);
340340

341341
if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
342342
let msg = format!("you can cast an `{}` to `{}`", checked_ty, expected_ty);

src/libsyntax/ast.rs

+180
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ pub use self::UnsafeSource::*;
1515
pub use self::PathParameters::*;
1616
pub use symbol::{Ident, Symbol as Name};
1717
pub use util::ThinVec;
18+
pub use util::parser::{
19+
AssocOp,
20+
PREC_RESET,
21+
PREC_CLOSURE,
22+
PREC_JUMP,
23+
PREC_RANGE,
24+
PREC_PREFIX,
25+
PREC_POSTFIX,
26+
PREC_PAREN,
27+
PREC_FORCE_PAREN,
28+
};
1829

1930
use syntax_pos::{Span, DUMMY_SP};
2031
use codemap::{respan, Spanned};
@@ -28,6 +39,7 @@ use tokenstream::{ThinTokenStream, TokenStream};
2839

2940
use serialize::{self, Encoder, Decoder};
3041
use std::collections::HashSet;
42+
use std::cmp::Ordering;
3143
use std::fmt;
3244
use std::rc::Rc;
3345
use std::u32;
@@ -730,6 +742,7 @@ impl BinOpKind {
730742
_ => false
731743
}
732744
}
745+
733746
pub fn is_comparison(&self) -> bool {
734747
use self::BinOpKind::*;
735748
match *self {
@@ -740,6 +753,7 @@ impl BinOpKind {
740753
false,
741754
}
742755
}
756+
743757
/// Returns `true` if the binary operator takes its arguments by value
744758
pub fn is_by_value(&self) -> bool {
745759
!self.is_comparison()
@@ -903,6 +917,129 @@ pub struct Expr {
903917
pub attrs: ThinVec<Attribute>
904918
}
905919

920+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
921+
pub enum ExprPrecedence {
922+
Closure,
923+
Break,
924+
Continue,
925+
Ret,
926+
Yield,
927+
928+
Range,
929+
930+
Binary(BinOpKind),
931+
932+
InPlace,
933+
Cast,
934+
Type,
935+
936+
Assign,
937+
AssignOp,
938+
939+
Box,
940+
AddrOf,
941+
Unary,
942+
943+
Call,
944+
MethodCall,
945+
Field,
946+
TupField,
947+
Index,
948+
Try,
949+
InlineAsm,
950+
Mac,
951+
952+
Array,
953+
Repeat,
954+
Tup,
955+
Lit,
956+
Path,
957+
Paren,
958+
If,
959+
IfLet,
960+
While,
961+
WhileLet,
962+
ForLoop,
963+
Loop,
964+
Match,
965+
Block,
966+
Catch,
967+
Struct,
968+
}
969+
970+
impl PartialOrd for ExprPrecedence {
971+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
972+
Some(self.order().cmp(&other.order()))
973+
}
974+
}
975+
976+
impl Ord for ExprPrecedence {
977+
fn cmp(&self, other: &Self) -> Ordering {
978+
self.order().cmp(&other.order())
979+
}
980+
}
981+
982+
impl ExprPrecedence {
983+
pub fn order(self) -> i8 {
984+
match self {
985+
ExprPrecedence::Closure => PREC_CLOSURE,
986+
987+
ExprPrecedence::Break |
988+
ExprPrecedence::Continue |
989+
ExprPrecedence::Ret |
990+
ExprPrecedence::Yield => PREC_JUMP,
991+
992+
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
993+
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
994+
// ensures that `pprust` will add parentheses in the right places to get the desired
995+
// parse.
996+
ExprPrecedence::Range => PREC_RANGE,
997+
998+
// Binop-like expr kinds, handled by `AssocOp`.
999+
ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
1000+
ExprPrecedence::InPlace => AssocOp::Inplace.precedence() as i8,
1001+
ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
1002+
ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
1003+
1004+
ExprPrecedence::Assign |
1005+
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
1006+
1007+
// Unary, prefix
1008+
ExprPrecedence::Box |
1009+
ExprPrecedence::AddrOf |
1010+
ExprPrecedence::Unary => PREC_PREFIX,
1011+
1012+
// Unary, postfix
1013+
ExprPrecedence::Call |
1014+
ExprPrecedence::MethodCall |
1015+
ExprPrecedence::Field |
1016+
ExprPrecedence::TupField |
1017+
ExprPrecedence::Index |
1018+
ExprPrecedence::Try |
1019+
ExprPrecedence::InlineAsm |
1020+
ExprPrecedence::Mac => PREC_POSTFIX,
1021+
1022+
// Never need parens
1023+
ExprPrecedence::Array |
1024+
ExprPrecedence::Repeat |
1025+
ExprPrecedence::Tup |
1026+
ExprPrecedence::Lit |
1027+
ExprPrecedence::Path |
1028+
ExprPrecedence::Paren |
1029+
ExprPrecedence::If |
1030+
ExprPrecedence::IfLet |
1031+
ExprPrecedence::While |
1032+
ExprPrecedence::WhileLet |
1033+
ExprPrecedence::ForLoop |
1034+
ExprPrecedence::Loop |
1035+
ExprPrecedence::Match |
1036+
ExprPrecedence::Block |
1037+
ExprPrecedence::Catch |
1038+
ExprPrecedence::Struct => PREC_PAREN,
1039+
}
1040+
}
1041+
}
1042+
9061043
impl Expr {
9071044
/// Wether this expression would be valid somewhere that expects a value, for example, an `if`
9081045
/// condition.
@@ -966,6 +1103,49 @@ impl Expr {
9661103

9671104
Some(P(Ty { node, id: self.id, span: self.span }))
9681105
}
1106+
1107+
pub fn precedence(&self) -> ExprPrecedence {
1108+
match self.node {
1109+
ExprKind::Box(_) => ExprPrecedence::Box,
1110+
ExprKind::InPlace(..) => ExprPrecedence::InPlace,
1111+
ExprKind::Array(_) => ExprPrecedence::Array,
1112+
ExprKind::Call(..) => ExprPrecedence::Call,
1113+
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
1114+
ExprKind::Tup(_) => ExprPrecedence::Tup,
1115+
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
1116+
ExprKind::Unary(..) => ExprPrecedence::Unary,
1117+
ExprKind::Lit(_) => ExprPrecedence::Lit,
1118+
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
1119+
ExprKind::If(..) => ExprPrecedence::If,
1120+
ExprKind::IfLet(..) => ExprPrecedence::IfLet,
1121+
ExprKind::While(..) => ExprPrecedence::While,
1122+
ExprKind::WhileLet(..) => ExprPrecedence::WhileLet,
1123+
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
1124+
ExprKind::Loop(..) => ExprPrecedence::Loop,
1125+
ExprKind::Match(..) => ExprPrecedence::Match,
1126+
ExprKind::Closure(..) => ExprPrecedence::Closure,
1127+
ExprKind::Block(..) => ExprPrecedence::Block,
1128+
ExprKind::Catch(..) => ExprPrecedence::Catch,
1129+
ExprKind::Assign(..) => ExprPrecedence::Assign,
1130+
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
1131+
ExprKind::Field(..) => ExprPrecedence::Field,
1132+
ExprKind::TupField(..) => ExprPrecedence::TupField,
1133+
ExprKind::Index(..) => ExprPrecedence::Index,
1134+
ExprKind::Range(..) => ExprPrecedence::Range,
1135+
ExprKind::Path(..) => ExprPrecedence::Path,
1136+
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
1137+
ExprKind::Break(..) => ExprPrecedence::Break,
1138+
ExprKind::Continue(..) => ExprPrecedence::Continue,
1139+
ExprKind::Ret(..) => ExprPrecedence::Ret,
1140+
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
1141+
ExprKind::Mac(..) => ExprPrecedence::Mac,
1142+
ExprKind::Struct(..) => ExprPrecedence::Struct,
1143+
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
1144+
ExprKind::Paren(..) => ExprPrecedence::Paren,
1145+
ExprKind::Try(..) => ExprPrecedence::Try,
1146+
ExprKind::Yield(..) => ExprPrecedence::Yield,
1147+
}
1148+
}
9691149
}
9701150

9711151
impl fmt::Debug for Expr {

0 commit comments

Comments
 (0)