@@ -20,6 +20,7 @@ use syntax::print::pp::Breaks::{Consistent, Inconsistent};
20
20
use syntax:: print:: pprust:: PrintState ;
21
21
use syntax:: ptr:: P ;
22
22
use syntax:: symbol:: keywords;
23
+ use syntax:: util:: parser:: { self , AssocOp , Fixity } ;
23
24
use syntax_pos:: { self , BytePos } ;
24
25
25
26
use hir;
@@ -210,18 +211,6 @@ pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String {
210
211
} )
211
212
}
212
213
213
- fn needs_parentheses ( expr : & hir:: Expr ) -> bool {
214
- match expr. node {
215
- hir:: ExprAssign ( ..) |
216
- hir:: ExprBinary ( ..) |
217
- hir:: ExprClosure ( ..) |
218
- hir:: ExprAssignOp ( ..) |
219
- hir:: ExprCast ( ..) |
220
- hir:: ExprType ( ..) => true ,
221
- _ => false ,
222
- }
223
- }
224
-
225
214
impl < ' a > State < ' a > {
226
215
pub fn cbox ( & mut self , u : usize ) -> io:: Result < ( ) > {
227
216
self . boxes . push ( pp:: Breaks :: Consistent ) ;
@@ -1047,7 +1036,7 @@ impl<'a> State<'a> {
1047
1036
self . cbox ( indent_unit - 1 ) ?;
1048
1037
self . ibox ( 0 ) ?;
1049
1038
self . s . word ( " else if " ) ?;
1050
- self . print_expr ( & i) ?;
1039
+ self . print_expr_as_cond ( & i) ?;
1051
1040
self . s . space ( ) ?;
1052
1041
self . print_expr ( & then) ?;
1053
1042
self . print_else ( e. as_ref ( ) . map ( |e| & * * e) )
@@ -1075,7 +1064,7 @@ impl<'a> State<'a> {
1075
1064
elseopt : Option < & hir:: Expr > )
1076
1065
-> io:: Result < ( ) > {
1077
1066
self . head ( "if" ) ?;
1078
- self . print_expr ( test) ?;
1067
+ self . print_expr_as_cond ( test) ?;
1079
1068
self . s . space ( ) ?;
1080
1069
self . print_expr ( blk) ?;
1081
1070
self . print_else ( elseopt)
@@ -1091,7 +1080,7 @@ impl<'a> State<'a> {
1091
1080
self . print_pat ( pat) ?;
1092
1081
self . s . space ( ) ?;
1093
1082
self . word_space ( "=" ) ?;
1094
- self . print_expr ( expr) ?;
1083
+ self . print_expr_as_cond ( expr) ?;
1095
1084
self . s . space ( ) ?;
1096
1085
self . print_block ( blk) ?;
1097
1086
self . print_else ( elseopt)
@@ -1104,8 +1093,31 @@ impl<'a> State<'a> {
1104
1093
self . pclose ( )
1105
1094
}
1106
1095
1107
- pub fn print_expr_maybe_paren ( & mut self , expr : & hir:: Expr ) -> io:: Result < ( ) > {
1108
- let needs_par = needs_parentheses ( expr) ;
1096
+ pub fn print_expr_maybe_paren ( & mut self , expr : & hir:: Expr , prec : i8 ) -> io:: Result < ( ) > {
1097
+ let needs_par = expr_precedence ( expr) < prec;
1098
+ if needs_par {
1099
+ self . popen ( ) ?;
1100
+ }
1101
+ self . print_expr ( expr) ?;
1102
+ if needs_par {
1103
+ self . pclose ( ) ?;
1104
+ }
1105
+ Ok ( ( ) )
1106
+ }
1107
+
1108
+ /// Print an expr using syntax that's acceptable in a condition position, such as the `cond` in
1109
+ /// `if cond { ... }`.
1110
+ pub fn print_expr_as_cond ( & mut self , expr : & hir:: Expr ) -> io:: Result < ( ) > {
1111
+ let needs_par = match expr. node {
1112
+ // These cases need parens due to the parse error observed in #26461: `if return {}`
1113
+ // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
1114
+ hir:: ExprClosure ( ..) |
1115
+ hir:: ExprRet ( ..) |
1116
+ hir:: ExprBreak ( ..) => true ,
1117
+
1118
+ _ => contains_exterior_struct_lit ( expr) ,
1119
+ } ;
1120
+
1109
1121
if needs_par {
1110
1122
self . popen ( ) ?;
1111
1123
}
@@ -1182,7 +1194,14 @@ impl<'a> State<'a> {
1182
1194
}
1183
1195
1184
1196
fn print_expr_call ( & mut self , func : & hir:: Expr , args : & [ hir:: Expr ] ) -> io:: Result < ( ) > {
1185
- self . print_expr_maybe_paren ( func) ?;
1197
+ let prec =
1198
+ match func. node {
1199
+ hir:: ExprField ( ..) |
1200
+ hir:: ExprTupField ( ..) => parser:: PREC_FORCE_PAREN ,
1201
+ _ => parser:: PREC_POSTFIX ,
1202
+ } ;
1203
+
1204
+ self . print_expr_maybe_paren ( func, prec) ?;
1186
1205
self . print_call_post ( args)
1187
1206
}
1188
1207
@@ -1191,7 +1210,7 @@ impl<'a> State<'a> {
1191
1210
args : & [ hir:: Expr ] )
1192
1211
-> io:: Result < ( ) > {
1193
1212
let base_args = & args[ 1 ..] ;
1194
- self . print_expr ( & args[ 0 ] ) ?;
1213
+ self . print_expr_maybe_paren ( & args[ 0 ] , parser :: PREC_POSTFIX ) ?;
1195
1214
self . s . word ( "." ) ?;
1196
1215
self . print_name ( segment. name ) ?;
1197
1216
if !segment. parameters . lifetimes . is_empty ( ) ||
@@ -1207,15 +1226,25 @@ impl<'a> State<'a> {
1207
1226
lhs : & hir:: Expr ,
1208
1227
rhs : & hir:: Expr )
1209
1228
-> io:: Result < ( ) > {
1210
- self . print_expr ( lhs) ?;
1229
+ let assoc_op = bin_op_to_assoc_op ( op. node ) ;
1230
+ let prec = assoc_op. precedence ( ) as i8 ;
1231
+ let fixity = assoc_op. fixity ( ) ;
1232
+
1233
+ let ( left_prec, right_prec) = match fixity {
1234
+ Fixity :: Left => ( prec, prec + 1 ) ,
1235
+ Fixity :: Right => ( prec + 1 , prec) ,
1236
+ Fixity :: None => ( prec + 1 , prec + 1 ) ,
1237
+ } ;
1238
+
1239
+ self . print_expr_maybe_paren ( lhs, left_prec) ?;
1211
1240
self . s . space ( ) ?;
1212
1241
self . word_space ( op. node . as_str ( ) ) ?;
1213
- self . print_expr ( rhs)
1242
+ self . print_expr_maybe_paren ( rhs, right_prec )
1214
1243
}
1215
1244
1216
1245
fn print_expr_unary ( & mut self , op : hir:: UnOp , expr : & hir:: Expr ) -> io:: Result < ( ) > {
1217
1246
self . s . word ( op. as_str ( ) ) ?;
1218
- self . print_expr_maybe_paren ( expr)
1247
+ self . print_expr_maybe_paren ( expr, parser :: PREC_PREFIX )
1219
1248
}
1220
1249
1221
1250
fn print_expr_addr_of ( & mut self ,
@@ -1224,7 +1253,7 @@ impl<'a> State<'a> {
1224
1253
-> io:: Result < ( ) > {
1225
1254
self . s . word ( "&" ) ?;
1226
1255
self . print_mutability ( mutability) ?;
1227
- self . print_expr_maybe_paren ( expr)
1256
+ self . print_expr_maybe_paren ( expr, parser :: PREC_PREFIX )
1228
1257
}
1229
1258
1230
1259
pub fn print_expr ( & mut self , expr : & hir:: Expr ) -> io:: Result < ( ) > {
@@ -1235,7 +1264,7 @@ impl<'a> State<'a> {
1235
1264
match expr. node {
1236
1265
hir:: ExprBox ( ref expr) => {
1237
1266
self . word_space ( "box" ) ?;
1238
- self . print_expr ( expr) ?;
1267
+ self . print_expr_maybe_paren ( expr, parser :: PREC_PREFIX ) ?;
1239
1268
}
1240
1269
hir:: ExprArray ( ref exprs) => {
1241
1270
self . print_expr_vec ( exprs) ?;
@@ -1268,13 +1297,15 @@ impl<'a> State<'a> {
1268
1297
self . print_literal ( & lit) ?;
1269
1298
}
1270
1299
hir:: ExprCast ( ref expr, ref ty) => {
1271
- self . print_expr ( & expr) ?;
1300
+ let prec = AssocOp :: As . precedence ( ) as i8 ;
1301
+ self . print_expr_maybe_paren ( & expr, prec) ?;
1272
1302
self . s . space ( ) ?;
1273
1303
self . word_space ( "as" ) ?;
1274
1304
self . print_type ( & ty) ?;
1275
1305
}
1276
1306
hir:: ExprType ( ref expr, ref ty) => {
1277
- self . print_expr ( & expr) ?;
1307
+ let prec = AssocOp :: Colon . precedence ( ) as i8 ;
1308
+ self . print_expr_maybe_paren ( & expr, prec) ?;
1278
1309
self . word_space ( ":" ) ?;
1279
1310
self . print_type ( & ty) ?;
1280
1311
}
@@ -1287,7 +1318,7 @@ impl<'a> State<'a> {
1287
1318
self . word_space ( ":" ) ?;
1288
1319
}
1289
1320
self . head ( "while" ) ?;
1290
- self . print_expr ( & test) ?;
1321
+ self . print_expr_as_cond ( & test) ?;
1291
1322
self . s . space ( ) ?;
1292
1323
self . print_block ( & blk) ?;
1293
1324
}
@@ -1304,7 +1335,7 @@ impl<'a> State<'a> {
1304
1335
self . cbox ( indent_unit) ?;
1305
1336
self . ibox ( 4 ) ?;
1306
1337
self . word_nbsp ( "match" ) ?;
1307
- self . print_expr ( & expr) ?;
1338
+ self . print_expr_as_cond ( & expr) ?;
1308
1339
self . s . space ( ) ?;
1309
1340
self . bopen ( ) ?;
1310
1341
for arm in arms {
@@ -1335,30 +1366,32 @@ impl<'a> State<'a> {
1335
1366
self . print_block ( & blk) ?;
1336
1367
}
1337
1368
hir:: ExprAssign ( ref lhs, ref rhs) => {
1338
- self . print_expr ( & lhs) ?;
1369
+ let prec = AssocOp :: Assign . precedence ( ) as i8 ;
1370
+ self . print_expr_maybe_paren ( & lhs, prec + 1 ) ?;
1339
1371
self . s . space ( ) ?;
1340
1372
self . word_space ( "=" ) ?;
1341
- self . print_expr ( & rhs) ?;
1373
+ self . print_expr_maybe_paren ( & rhs, prec ) ?;
1342
1374
}
1343
1375
hir:: ExprAssignOp ( op, ref lhs, ref rhs) => {
1344
- self . print_expr ( & lhs) ?;
1376
+ let prec = AssocOp :: Assign . precedence ( ) as i8 ;
1377
+ self . print_expr_maybe_paren ( & lhs, prec + 1 ) ?;
1345
1378
self . s . space ( ) ?;
1346
1379
self . s . word ( op. node . as_str ( ) ) ?;
1347
1380
self . word_space ( "=" ) ?;
1348
- self . print_expr ( & rhs) ?;
1381
+ self . print_expr_maybe_paren ( & rhs, prec ) ?;
1349
1382
}
1350
1383
hir:: ExprField ( ref expr, name) => {
1351
- self . print_expr ( & expr) ?;
1384
+ self . print_expr_maybe_paren ( expr, parser :: PREC_POSTFIX ) ?;
1352
1385
self . s . word ( "." ) ?;
1353
1386
self . print_name ( name. node ) ?;
1354
1387
}
1355
1388
hir:: ExprTupField ( ref expr, id) => {
1356
- self . print_expr ( & expr) ?;
1389
+ self . print_expr_maybe_paren ( & expr, parser :: PREC_POSTFIX ) ?;
1357
1390
self . s . word ( "." ) ?;
1358
1391
self . print_usize ( id. node ) ?;
1359
1392
}
1360
1393
hir:: ExprIndex ( ref expr, ref index) => {
1361
- self . print_expr ( & expr) ?;
1394
+ self . print_expr_maybe_paren ( & expr, parser :: PREC_POSTFIX ) ?;
1362
1395
self . s . word ( "[" ) ?;
1363
1396
self . print_expr ( & index) ?;
1364
1397
self . s . word ( "]" ) ?;
@@ -1374,7 +1407,7 @@ impl<'a> State<'a> {
1374
1407
self . s . space ( ) ?;
1375
1408
}
1376
1409
if let Some ( ref expr) = * opt_expr {
1377
- self . print_expr ( expr) ?;
1410
+ self . print_expr_maybe_paren ( expr, parser :: PREC_JUMP ) ?;
1378
1411
self . s . space ( ) ?;
1379
1412
}
1380
1413
}
@@ -1391,7 +1424,7 @@ impl<'a> State<'a> {
1391
1424
match * result {
1392
1425
Some ( ref expr) => {
1393
1426
self . s . word ( " " ) ?;
1394
- self . print_expr ( & expr) ?;
1427
+ self . print_expr_maybe_paren ( & expr, parser :: PREC_JUMP ) ?;
1395
1428
}
1396
1429
_ => ( ) ,
1397
1430
}
@@ -1463,7 +1496,7 @@ impl<'a> State<'a> {
1463
1496
}
1464
1497
hir:: ExprYield ( ref expr) => {
1465
1498
self . s . word ( "yield" ) ?;
1466
- self . print_expr ( & expr) ?;
1499
+ self . print_expr_maybe_paren ( & expr, parser :: PREC_JUMP ) ?;
1467
1500
}
1468
1501
}
1469
1502
self . ann . post ( self , NodeExpr ( expr) ) ?;
@@ -2246,3 +2279,112 @@ fn stmt_ends_with_semi(stmt: &hir::Stmt_) -> bool {
2246
2279
}
2247
2280
}
2248
2281
}
2282
+
2283
+
2284
+ fn expr_precedence ( expr : & hir:: Expr ) -> i8 {
2285
+ use syntax:: util:: parser:: * ;
2286
+
2287
+ match expr. node {
2288
+ hir:: ExprClosure ( ..) => PREC_CLOSURE ,
2289
+
2290
+ hir:: ExprBreak ( ..) |
2291
+ hir:: ExprAgain ( ..) |
2292
+ hir:: ExprRet ( ..) |
2293
+ hir:: ExprYield ( ..) => PREC_JUMP ,
2294
+
2295
+ hir:: ExprIf ( ..) |
2296
+ hir:: ExprWhile ( ..) |
2297
+ hir:: ExprLoop ( ..) |
2298
+ hir:: ExprMatch ( ..) |
2299
+ hir:: ExprBlock ( ..) => PREC_BLOCK ,
2300
+
2301
+ // Binop-like expr kinds, handled by `AssocOp`.
2302
+ hir:: ExprBinary ( op, _, _) => bin_op_to_assoc_op ( op. node ) . precedence ( ) as i8 ,
2303
+
2304
+ hir:: ExprCast ( ..) => AssocOp :: As . precedence ( ) as i8 ,
2305
+ hir:: ExprType ( ..) => AssocOp :: Colon . precedence ( ) as i8 ,
2306
+
2307
+ hir:: ExprAssign ( ..) |
2308
+ hir:: ExprAssignOp ( ..) => AssocOp :: Assign . precedence ( ) as i8 ,
2309
+
2310
+ // Unary, prefix
2311
+ hir:: ExprBox ( ..) |
2312
+ hir:: ExprAddrOf ( ..) |
2313
+ hir:: ExprUnary ( ..) => PREC_PREFIX ,
2314
+
2315
+ // Unary, postfix
2316
+ hir:: ExprCall ( ..) |
2317
+ hir:: ExprMethodCall ( ..) |
2318
+ hir:: ExprField ( ..) |
2319
+ hir:: ExprTupField ( ..) |
2320
+ hir:: ExprIndex ( ..) |
2321
+ hir:: ExprInlineAsm ( ..) => PREC_POSTFIX ,
2322
+
2323
+ // Never need parens
2324
+ hir:: ExprArray ( ..) |
2325
+ hir:: ExprRepeat ( ..) |
2326
+ hir:: ExprTup ( ..) |
2327
+ hir:: ExprLit ( ..) |
2328
+ hir:: ExprPath ( ..) |
2329
+ hir:: ExprStruct ( ..) => PREC_PAREN ,
2330
+ }
2331
+ }
2332
+
2333
+ fn bin_op_to_assoc_op ( op : hir:: BinOp_ ) -> AssocOp {
2334
+ use hir:: BinOp_ :: * ;
2335
+ match op {
2336
+ BiAdd => AssocOp :: Add ,
2337
+ BiSub => AssocOp :: Subtract ,
2338
+ BiMul => AssocOp :: Multiply ,
2339
+ BiDiv => AssocOp :: Divide ,
2340
+ BiRem => AssocOp :: Modulus ,
2341
+
2342
+ BiAnd => AssocOp :: LAnd ,
2343
+ BiOr => AssocOp :: LOr ,
2344
+
2345
+ BiBitXor => AssocOp :: BitXor ,
2346
+ BiBitAnd => AssocOp :: BitAnd ,
2347
+ BiBitOr => AssocOp :: BitOr ,
2348
+ BiShl => AssocOp :: ShiftLeft ,
2349
+ BiShr => AssocOp :: ShiftRight ,
2350
+
2351
+ BiEq => AssocOp :: Equal ,
2352
+ BiLt => AssocOp :: Less ,
2353
+ BiLe => AssocOp :: LessEqual ,
2354
+ BiNe => AssocOp :: NotEqual ,
2355
+ BiGe => AssocOp :: GreaterEqual ,
2356
+ BiGt => AssocOp :: Greater ,
2357
+ }
2358
+ }
2359
+
2360
+ /// Expressions that syntactically contain an "exterior" struct literal i.e. not surrounded by any
2361
+ /// parens or other delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
2362
+ /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
2363
+ fn contains_exterior_struct_lit ( value : & hir:: Expr ) -> bool {
2364
+ match value. node {
2365
+ hir:: ExprStruct ( ..) => true ,
2366
+
2367
+ hir:: ExprAssign ( ref lhs, ref rhs) |
2368
+ hir:: ExprAssignOp ( _, ref lhs, ref rhs) |
2369
+ hir:: ExprBinary ( _, ref lhs, ref rhs) => {
2370
+ // X { y: 1 } + X { y: 2 }
2371
+ contains_exterior_struct_lit ( & lhs) || contains_exterior_struct_lit ( & rhs)
2372
+ }
2373
+ hir:: ExprUnary ( _, ref x) |
2374
+ hir:: ExprCast ( ref x, _) |
2375
+ hir:: ExprType ( ref x, _) |
2376
+ hir:: ExprField ( ref x, _) |
2377
+ hir:: ExprTupField ( ref x, _) |
2378
+ hir:: ExprIndex ( ref x, _) => {
2379
+ // &X { y: 1 }, X { y: 1 }.y
2380
+ contains_exterior_struct_lit ( & x)
2381
+ }
2382
+
2383
+ hir:: ExprMethodCall ( .., ref exprs) => {
2384
+ // X { y: 1 }.bar(...)
2385
+ contains_exterior_struct_lit ( & exprs[ 0 ] )
2386
+ }
2387
+
2388
+ _ => false ,
2389
+ }
2390
+ }
0 commit comments