Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/ast/prec.rs')
| -rw-r--r-- | crates/syntax/src/ast/prec.rs | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/crates/syntax/src/ast/prec.rs b/crates/syntax/src/ast/prec.rs index 1364adb187..8c88224a76 100644 --- a/crates/syntax/src/ast/prec.rs +++ b/crates/syntax/src/ast/prec.rs @@ -3,14 +3,15 @@ use stdx::always; use crate::{ - AstNode, SyntaxNode, + AstNode, Direction, SyntaxNode, T, + algo::skip_trivia_token, ast::{self, BinaryOp, Expr, HasArgList, RangeItem}, match_ast, }; #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub enum ExprPrecedence { - // return val, break val, yield val, closures + // return, break, continue, yield, yeet, become (with or without value) Jump, // = += -= *= /= %= &= |= ^= <<= >>= Assign, @@ -76,18 +77,12 @@ pub fn precedence(expr: &ast::Expr) -> ExprPrecedence { Some(_) => ExprPrecedence::Unambiguous, }, - Expr::BreakExpr(e) if e.expr().is_some() => ExprPrecedence::Jump, - Expr::BecomeExpr(e) if e.expr().is_some() => ExprPrecedence::Jump, - Expr::ReturnExpr(e) if e.expr().is_some() => ExprPrecedence::Jump, - Expr::YeetExpr(e) if e.expr().is_some() => ExprPrecedence::Jump, - Expr::YieldExpr(e) if e.expr().is_some() => ExprPrecedence::Jump, - Expr::BreakExpr(_) | Expr::BecomeExpr(_) | Expr::ReturnExpr(_) | Expr::YeetExpr(_) | Expr::YieldExpr(_) - | Expr::ContinueExpr(_) => ExprPrecedence::Unambiguous, + | Expr::ContinueExpr(_) => ExprPrecedence::Jump, Expr::RangeExpr(..) => ExprPrecedence::Range, @@ -226,6 +221,20 @@ impl Expr { return false; } + // Keep parens when a ret-like expr is followed by `||` or `&&`. + // For `||`, removing parens could reparse as `<ret-like> || <closure>`. + // For `&&`, we avoid introducing `<ret-like> && <expr>` into a binary chain. + + if self.precedence() == ExprPrecedence::Jump + && let Some(node) = + place_of.ancestors().find(|it| it.parent().is_none_or(|p| &p == parent.syntax())) + && let Some(next) = + node.last_token().and_then(|t| skip_trivia_token(t.next_token()?, Direction::Next)) + && matches!(next.kind(), T![||] | T![&&]) + { + return true; + } + if self.is_paren_like() || parent.is_paren_like() || self.is_prefix() |