From 07f33e2b81699e5136add823bea076625cdbcb8c Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 14 Sep 2025 00:42:11 +0800 Subject: [PATCH] Fix IfExpr then branch suggest - And add logic operation suggest Example --- In the old implementation, it always suggested conditions, this is a lot of noise, e.g `contract_checks()~(use std::intrinsics::contract_checks) const fn() -> bool` ```rust fn foo() { if true { c$0 } } ``` --- crates/ide-completion/src/context/analysis.rs | 13 +++- crates/ide-completion/src/context/tests.rs | 69 +++++++++++++++++++ crates/ide-completion/src/tests/expression.rs | 8 +-- 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 7b78a9700e..cdb1ad8b38 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -637,6 +637,9 @@ fn expected_type_and_name<'db>( .or_else(|| it.rhs().and_then(|rhs| sema.type_of_expr(&rhs))) .map(TypeInfo::original); (ty, None) + } else if let Some(ast::BinaryOp::LogicOp(_)) = it.op_kind() { + let ty = sema.type_of_expr(&it.clone().into()).map(TypeInfo::original); + (ty, None) } else { (None, None) } @@ -707,9 +710,13 @@ fn expected_type_and_name<'db>( (ty, None) }, ast::IfExpr(it) => { - let ty = it.condition() - .and_then(|e| sema.type_of_expr(&e)) - .map(TypeInfo::original); + let ty = if let Some(body) = it.then_branch() + && token.text_range().end() > body.syntax().text_range().start() + { + sema.type_of_expr(&body.into()) + } else { + it.condition().and_then(|e| sema.type_of_expr(&e)) + }.map(TypeInfo::original); (ty, None) }, ast::IdentPat(it) => { diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs index 445afa75f3..d9ec7915e3 100644 --- a/crates/ide-completion/src/context/tests.rs +++ b/crates/ide-completion/src/context/tests.rs @@ -278,6 +278,62 @@ fn foo() { ) } +#[test] +fn expected_type_if_let_chain_bool() { + check_expected_type_and_name( + r#" +fn foo() { + let f = Foo::Quux; + if let c = f && $0 { } +} +"#, + expect![[r#"ty: bool, name: ?"#]], + ); +} + +#[test] +fn expected_type_if_condition() { + check_expected_type_and_name( + r#" +fn foo() { + if a$0 { } +} +"#, + expect![[r#"ty: bool, name: ?"#]], + ); +} + +#[test] +fn expected_type_if_body() { + check_expected_type_and_name( + r#" +enum Foo { Bar, Baz, Quux } + +fn foo() { + let _: Foo = if true { + $0 + }; +} +"#, + expect![[r#"ty: Foo, name: ?"#]], + ); + + check_expected_type_and_name( + r#" +enum Foo { Bar, Baz, Quux } + +fn foo() { + let _: Foo = if true { + Foo::Bar + } else { + $0 + }; +} +"#, + expect![[r#"ty: Foo, name: ?"#]], + ); +} + #[test] fn expected_type_fn_ret_without_leading_char() { cov_mark::check!(expected_type_fn_ret_without_leading_char); @@ -526,3 +582,16 @@ fn foo() { expect![[r#"ty: State, name: ?"#]], ); } + +#[test] +fn expected_type_logic_op() { + check_expected_type_and_name( + r#" +enum State { Stop } +fn foo() { + true && $0; +} +"#, + expect![[r#"ty: bool, name: ?"#]], + ); +} diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index c420953036..98a6f95f33 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -271,8 +271,6 @@ fn complete_in_block() { sn macro_rules sn pd sn ppd - ex false - ex true "#]], ) } @@ -1668,7 +1666,7 @@ fn foo() { let x = if foo {} $0; let y = 92; } fn foo() { let x = if foo {} $0 else {}; } "#, expect![[r#" - fn foo fn() + fn foo() fn() bt u32 u32 kw async kw const @@ -1710,7 +1708,7 @@ fn foo() { let x = if foo {} $0 else {}; } fn foo() { let x = if foo {} $0 else if true {}; } "#, expect![[r#" - fn foo fn() + fn foo() fn() bt u32 u32 kw async kw const @@ -1795,7 +1793,7 @@ fn foo() { let x = if foo {} el$0 else if true {} else {}; } fn foo() { let x = if foo {} $0 else if true {} else {}; } "#, expect![[r#" - fn foo fn() + fn foo() fn() bt u32 u32 kw async kw const