Unnamed repository; edit this file 'description' to name the repository.
Fix match arm nested body invalid expected type
Example --- ```rust struct Foo; enum E { X } fn foo() -> Foo { match E::X { Foo::X => { $0 } } } ``` **Before this PR** ```text ty: E, name: ? ``` **After this PR** ```text ty: Foo, name: ? ```
A4-Tacks 4 months ago
parent 2a40241 · commit e1747f9
-rw-r--r--crates/ide-completion/src/context/analysis.rs17
-rw-r--r--crates/ide-completion/src/context/tests.rs16
2 files changed, 33 insertions, 0 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index b65c68a240..e48c433fa4 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -734,6 +734,23 @@ fn expected_type_and_name<'db>(
}.map(TypeInfo::original);
(ty, None)
},
+ ast::MatchArm(it) => {
+ let on_arrow = previous_non_trivia_token(token.clone()).is_some_and(|it| T![=>] == it.kind());
+ let in_body = it.expr().is_some_and(|it| it.syntax().text_range().contains_range(token.text_range()));
+ let match_expr = it.syntax().ancestors().nth(2).and_then(ast::MatchExpr::cast);
+
+ let ty = if on_arrow || in_body {
+ // match foo { ..., pat => $0 }
+ cov_mark::hit!(expected_type_match_arm_body_without_leading_char);
+ cov_mark::hit!(expected_type_match_arm_body_with_leading_char);
+ match_expr.and_then(|it| sema.type_of_expr(&it.into()))
+ } else {
+ // match foo { $0 }
+ cov_mark::hit!(expected_type_match_arm_without_leading_char);
+ match_expr.and_then(|it| it.expr()).and_then(|e| sema.type_of_expr(&e))
+ }.map(TypeInfo::original);
+ (ty, None)
+ },
ast::IfExpr(it) => {
let ty = if let Some(body) = it.then_branch()
&& token.text_range().end() > body.syntax().text_range().start()
diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs
index b929d36ce6..09a9b6f112 100644
--- a/crates/ide-completion/src/context/tests.rs
+++ b/crates/ide-completion/src/context/tests.rs
@@ -257,6 +257,22 @@ fn foo() -> Foo {
}
#[test]
+fn expected_type_match_arm_block_body_without_leading_char() {
+ cov_mark::check!(expected_type_match_arm_body_without_leading_char);
+ cov_mark::check!(expected_type_match_arm_body_with_leading_char);
+ check_expected_type_and_name(
+ r#"
+struct Foo;
+enum E { X }
+fn foo() -> Foo {
+ match E::X { Foo::X => { $0 } }
+}
+"#,
+ expect![[r#"ty: Foo, name: ?"#]],
+ );
+}
+
+#[test]
fn expected_type_match_body_arm_with_leading_char() {
cov_mark::check!(expected_type_match_arm_body_with_leading_char);
check_expected_type_and_name(