diff --git a/src/expr.rs b/src/expr.rs index ca16fdee2d..4183ced263 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1391,7 +1391,11 @@ pub(crate) mod parsing { ) -> Result { loop { let ahead = input.fork(); - if let Ok(op) = ahead.parse::() { + if let Expr::Range(ExprRange { end: Some(_), .. }) = lhs { + // A range with an upper bound cannot be the left-hand side of + // another binary operator. + break; + } else if let Ok(op) = ahead.parse::() { let precedence = Precedence::of(&op); if precedence < base { break; diff --git a/tests/test_expr.rs b/tests/test_expr.rs index daf0d63c3b..13c37b6b44 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -331,7 +331,7 @@ fn test_postfix_operator_after_cast() { } #[test] -fn test_ranges() { +fn test_range_kinds() { syn::parse_str::("..").unwrap(); syn::parse_str::("..hi").unwrap(); syn::parse_str::("lo..").unwrap(); @@ -348,6 +348,44 @@ fn test_ranges() { syn::parse_str::("lo...hi").unwrap_err(); } +#[test] +fn test_range_precedence() { + snapshot!(".. .." as Expr, @r###" + Expr::Range { + limits: RangeLimits::HalfOpen, + end: Some(Expr::Range { + limits: RangeLimits::HalfOpen, + }), + } + "###); + + snapshot!(".. .. ()" as Expr, @r###" + Expr::Range { + limits: RangeLimits::HalfOpen, + end: Some(Expr::Range { + limits: RangeLimits::HalfOpen, + end: Some(Expr::Tuple), + }), + } + "###); + + snapshot!("() .. .." as Expr, @r###" + Expr::Range { + start: Some(Expr::Tuple), + limits: RangeLimits::HalfOpen, + end: Some(Expr::Range { + limits: RangeLimits::HalfOpen, + }), + } + "###); + + // A range with a lower bound cannot be the upper bound of another range, + // and a range with an upper bound cannot be the lower bound of another + // range. + syn::parse_str::(".. x ..").unwrap_err(); + syn::parse_str::("x .. x ..").unwrap_err(); +} + #[test] fn test_ambiguous_label() { for stmt in [