From c463a74f7bd4f8cd81a57c8a77faece2d2590a42 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 May 2024 20:04:00 -0700 Subject: [PATCH 1/2] Add tests of binop associativity --- tests/test_expr.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/test_expr.rs b/tests/test_expr.rs index b908311d49..87fca8d936 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -577,6 +577,48 @@ fn test_tuple_comma() { "###); } +#[test] +fn test_binop_associativity() { + // Left to right. + snapshot!("() + () + ()" as Expr, @r###" + Expr::Binary { + left: Expr::Binary { + left: Expr::Tuple, + op: BinOp::Add, + right: Expr::Tuple, + }, + op: BinOp::Add, + right: Expr::Tuple, + } + "###); + + // Right to left. + snapshot!("() += () += ()" as Expr, @r###" + Expr::Binary { + left: Expr::Tuple, + op: BinOp::AddAssign, + right: Expr::Binary { + left: Expr::Tuple, + op: BinOp::AddAssign, + right: Expr::Tuple, + }, + } + "###); + + // FIXME: this should fail to parse. Parenthesization is required. + snapshot!("() == () == ()" as Expr, @r###" + Expr::Binary { + left: Expr::Binary { + left: Expr::Tuple, + op: BinOp::Eq, + right: Expr::Tuple, + }, + op: BinOp::Eq, + right: Expr::Tuple, + } + "###); +} + #[test] fn test_assign_range_precedence() { // Range has higher precedence as the right-hand of an assignment, but From dc4ffde94ecac024785fd4fe75e7318fbc46be22 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 May 2024 20:05:41 -0700 Subject: [PATCH 2/2] Require parens for chained comparison binops --- src/expr.rs | 14 ++++++++++++++ tests/test_expr.rs | 14 ++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 4183ced263..8b44342eae 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1400,6 +1400,13 @@ pub(crate) mod parsing { if precedence < base { break; } + if precedence == Precedence::Compare { + if let Expr::Binary(lhs) = &lhs { + if Precedence::of(&lhs.op) == Precedence::Compare { + break; + } + } + } input.advance_to(&ahead); let right = parse_binop_rhs(input, allow_struct, precedence)?; lhs = Expr::Binary(ExprBinary { @@ -1455,6 +1462,13 @@ pub(crate) mod parsing { if precedence < base { break; } + if precedence == Precedence::Compare { + if let Expr::Binary(lhs) = &lhs { + if Precedence::of(&lhs.op) == Precedence::Compare { + break; + } + } + } input.advance_to(&ahead); let right = parse_binop_rhs(input, precedence)?; lhs = Expr::Binary(ExprBinary { diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 87fca8d936..f39200d3f2 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -605,18 +605,8 @@ fn test_binop_associativity() { } "###); - // FIXME: this should fail to parse. Parenthesization is required. - snapshot!("() == () == ()" as Expr, @r###" - Expr::Binary { - left: Expr::Binary { - left: Expr::Tuple, - op: BinOp::Eq, - right: Expr::Tuple, - }, - op: BinOp::Eq, - right: Expr::Tuple, - } - "###); + // Parenthesization is required. + syn::parse_str::("() == () == ()").unwrap_err(); } #[test]