From 05939a8d38959b1ff418a0f54663eaba0f5e3108 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 14 Jan 2026 17:54:23 +0800 Subject: [PATCH] Fix false positive precedence in `(2 as i32) < 3` Example --- ```rust fn f() { _ = $0(1 as u32) << 10; } ``` **Before this PR** This is syntax error ```rust fn f() { _ = 1 as u32 << 10; } ``` **After this PR** Assist not applicable --- .../src/handlers/remove_parentheses.rs | 6 +++++ .../crates/syntax/src/ast/prec.rs | 24 +++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs index aa4d2bcadb01..f07da489e23a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs @@ -321,6 +321,12 @@ mod tests { ); } + #[test] + fn remove_parens_conflict_cast_before_l_angle() { + check_assist_not_applicable(remove_parentheses, r#"fn f() { _ = $0(1 as u32) << 10; }"#); + check_assist_not_applicable(remove_parentheses, r#"fn f() { _ = $0(1 as u32) < 10; }"#); + } + #[test] fn remove_parens_double_paren_stmt() { check_assist( diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs index 8c88224a761a..d99cf492616e 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs @@ -154,6 +154,11 @@ fn check_ancestry(ancestor: &SyntaxNode, descendent: &SyntaxNode) -> bool { bail() } +fn next_token_of(node: &SyntaxNode) -> Option { + let last = node.last_token()?; + skip_trivia_token(last.next_token()?, Direction::Next) +} + impl Expr { pub fn precedence(&self) -> ExprPrecedence { precedence(self) @@ -197,6 +202,8 @@ impl Expr { if is_parent_call_expr && is_field_expr { return true; } + let place_of_parent = + || place_of.ancestors().find(|it| it.parent().is_none_or(|p| &p == parent.syntax())); // Special-case block weirdness if parent.child_is_followed_by_a_block() { @@ -226,15 +233,24 @@ impl Expr { // For `&&`, we avoid introducing ` && ` 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)) + && let Some(node) = place_of_parent() + && let Some(next) = next_token_of(&node) && matches!(next.kind(), T![||] | T![&&]) { return true; } + // Special-case `2 as x < 3` + if let ast::Expr::CastExpr(it) = self + && let Some(ty) = it.ty() + && ty.syntax().last_token().and_then(|it| ast::NameLike::cast(it.parent()?)).is_some() + && let Some(node) = place_of_parent() + && let Some(next) = next_token_of(&node) + && matches!(next.kind(), T![<] | T![<<]) + { + return true; + } + if self.is_paren_like() || parent.is_paren_like() || self.is_prefix()