Skip to content

Commit e728a04

Browse files
committed
fix: handle return-like expressions with && operator
1 parent 35f50e7 commit e728a04

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

crates/ide-assists/src/handlers/remove_parentheses.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ mod tests {
264264

265265
#[test]
266266
fn remove_parens_return_in_disjunction_with_closure_risk() {
267-
// `return` may only be blocked when it would form `return ||`
267+
// `return` may only be blocked when it would form `return ||` or `return &&`
268268
check_assist_not_applicable(
269269
remove_parentheses,
270270
r#"fn f() { let _x = true && $0(return) || true; }"#,
@@ -281,6 +281,22 @@ mod tests {
281281
remove_parentheses,
282282
r#"fn f() { let _x = true && !$0(return false) || true; }"#,
283283
);
284+
check_assist_not_applicable(
285+
remove_parentheses,
286+
r#"fn f() { let _x = true && $0(return) && true; }"#,
287+
);
288+
check_assist_not_applicable(
289+
remove_parentheses,
290+
r#"fn f() { let _x = true && !$0(return) && true; }"#,
291+
);
292+
check_assist_not_applicable(
293+
remove_parentheses,
294+
r#"fn f() { let _x = true && $0(return false) && true; }"#,
295+
);
296+
check_assist_not_applicable(
297+
remove_parentheses,
298+
r#"fn f() { let _x = true && !$0(return false) && true; }"#,
299+
);
284300
}
285301

286302
#[test]

crates/syntax/src/ast/prec.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use stdx::always;
55
use crate::{
66
AstNode, Direction, SyntaxNode, T,
77
algo::skip_trivia_token,
8-
ast::{self, BinaryOp, Expr, HasArgList, RangeItem},
8+
ast::{self, BinExpr, BinaryOp, Expr, HasArgList, RangeItem},
99
match_ast,
1010
};
1111

@@ -221,14 +221,24 @@ impl Expr {
221221
return false;
222222
}
223223

224-
// Keep parens when `(return ...)` is followed by `||`;
225-
// otherwise it would become `return || <closure>` with different semantics
226-
if let Expr::ReturnExpr(_) = self
227-
&& let Some(paren_expr) = self.syntax().parent().and_then(ast::ParenExpr::cast)
224+
// Keep parens when a ret-like expr is followed by `||` or `&&`.
225+
// For `||`, removing parens could reparse as `<ret-like> || <closure>`.
226+
// For `&&`, we avoid introducing `<ret-like> && <expr>` into a binary chain.
227+
228+
if matches!(
229+
self,
230+
Expr::ReturnExpr(_)
231+
| Expr::BreakExpr(_)
232+
| Expr::BecomeExpr(_)
233+
| Expr::YeetExpr(_)
234+
| Expr::YieldExpr(_)
235+
) && let Some(paren_expr) = self.syntax().parent().and_then(ast::ParenExpr::cast)
236+
&& let Some(parent_expr) = paren_expr.syntax().parent().and_then(ast::Expr::cast)
237+
&& BinExpr::can_cast(parent_expr.syntax().kind())
228238
&& let Some(r_paren) = paren_expr.r_paren_token()
229239
&& let Some(next) =
230240
r_paren.next_token().and_then(|t| skip_trivia_token(t, Direction::Next))
231-
&& next.kind() == T![||]
241+
&& matches!(next.kind(), T![||] | T![&&])
232242
{
233243
return true;
234244
}

0 commit comments

Comments
 (0)