aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-23 22:55:51 +0100
committerGitHub <[email protected]>2021-05-23 22:55:51 +0100
commit495c9586ec51e0cf9b06397d99ec4f65c55e7a28 (patch)
treec18eb1b1568ab0f0251339f7995b6ea177b3285f /crates/ide_completion/src
parenta2ce091fd7e149f809bdf0ee0d960d9e185ee5fb (diff)
parentb8262099cc51065259daf10b4b23ff49ce74434f (diff)
Merge #8945
8945: fix: Make expected type work in more situations r=flodiebold a=flodiebold Also makes call info show the correct types for generic methods. ![2021-05-23-182952_1134x616_scrot](https://user-images.githubusercontent.com/906069/119269023-dd5a5b00-bbf5-11eb-993a-b6e122c3b9a6.png) ![2021-05-23-183117_922x696_scrot](https://user-images.githubusercontent.com/906069/119269025-dfbcb500-bbf5-11eb-983c-fc415b8428e0.png) Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r--crates/ide_completion/src/context.rs96
-rw-r--r--crates/ide_completion/src/render.rs7
2 files changed, 88 insertions, 15 deletions
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 787eb2fd3..1ec59ff80 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -337,25 +337,24 @@ impl<'a> CompletionContext<'a> {
337 }, 337 },
338 ast::RecordExprFieldList(_it) => { 338 ast::RecordExprFieldList(_it) => {
339 cov_mark::hit!(expected_type_struct_field_without_leading_char); 339 cov_mark::hit!(expected_type_struct_field_without_leading_char);
340 self.token.prev_sibling_or_token() 340 // wouldn't try {} be nice...
341 .and_then(|se| se.into_node()) 341 (|| {
342 .and_then(|node| ast::RecordExprField::cast(node)) 342 let expr_field = self.token.prev_sibling_or_token()?
343 .and_then(|rf| self.sema.resolve_record_field(&rf).zip(Some(rf))) 343 .into_node()
344 .map(|(f, rf)|( 344 .and_then(|node| ast::RecordExprField::cast(node))?;
345 Some(f.0.ty(self.db)), 345 let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?;
346 rf.field_name().map(NameOrNameRef::NameRef), 346 Some((
347 Some(ty),
348 expr_field.field_name().map(NameOrNameRef::NameRef),
347 )) 349 ))
348 .unwrap_or((None, None)) 350 })().unwrap_or((None, None))
349 }, 351 },
350 ast::RecordExprField(it) => { 352 ast::RecordExprField(it) => {
351 cov_mark::hit!(expected_type_struct_field_with_leading_char); 353 cov_mark::hit!(expected_type_struct_field_with_leading_char);
352 self.sema 354 (
353 .resolve_record_field(&it) 355 it.expr().as_ref().and_then(|e| self.sema.type_of_expr(e)),
354 .map(|f|( 356 it.field_name().map(NameOrNameRef::NameRef),
355 Some(f.0.ty(self.db)), 357 )
356 it.field_name().map(NameOrNameRef::NameRef),
357 ))
358 .unwrap_or((None, None))
359 }, 358 },
360 ast::MatchExpr(it) => { 359 ast::MatchExpr(it) => {
361 cov_mark::hit!(expected_type_match_arm_without_leading_char); 360 cov_mark::hit!(expected_type_match_arm_without_leading_char);
@@ -382,6 +381,12 @@ impl<'a> CompletionContext<'a> {
382 let def = self.sema.to_def(&it); 381 let def = self.sema.to_def(&it);
383 (def.map(|def| def.ret_type(self.db)), None) 382 (def.map(|def| def.ret_type(self.db)), None)
384 }, 383 },
384 ast::ClosureExpr(it) => {
385 let ty = self.sema.type_of_expr(&it.into());
386 ty.and_then(|ty| ty.as_callable(self.db))
387 .map(|c| (Some(c.return_type()), None))
388 .unwrap_or((None, None))
389 },
385 ast::Stmt(_it) => (None, None), 390 ast::Stmt(_it) => (None, None),
386 _ => { 391 _ => {
387 match node.parent() { 392 match node.parent() {
@@ -785,6 +790,19 @@ fn foo() {
785 } 790 }
786 791
787 #[test] 792 #[test]
793 fn expected_type_generic_struct_field() {
794 check_expected_type_and_name(
795 r#"
796struct Foo<T> { a: T }
797fn foo() -> Foo<u32> {
798 Foo { a: $0 }
799}
800"#,
801 expect![[r#"ty: u32, name: a"#]],
802 )
803 }
804
805 #[test]
788 fn expected_type_struct_field_with_leading_char() { 806 fn expected_type_struct_field_with_leading_char() {
789 cov_mark::check!(expected_type_struct_field_with_leading_char); 807 cov_mark::check!(expected_type_struct_field_with_leading_char);
790 check_expected_type_and_name( 808 check_expected_type_and_name(
@@ -895,4 +913,52 @@ fn foo() -> u32 {
895 expect![[r#"ty: u32, name: ?"#]], 913 expect![[r#"ty: u32, name: ?"#]],
896 ) 914 )
897 } 915 }
916
917 #[test]
918 fn expected_type_closure_param_return() {
919 // FIXME: make this work with `|| $0`
920 check_expected_type_and_name(
921 r#"
922fn foo() {
923 bar(|| a$0);
924}
925
926fn bar(f: impl FnOnce() -> u32) {}
927#[lang = "fn_once"]
928trait FnOnce { type Output; }
929"#,
930 expect![[r#"ty: u32, name: ?"#]],
931 );
932 }
933
934 #[test]
935 fn expected_type_generic_function() {
936 check_expected_type_and_name(
937 r#"
938fn foo() {
939 bar::<u32>($0);
940}
941
942fn bar<T>(t: T) {}
943"#,
944 expect![[r#"ty: u32, name: t"#]],
945 );
946 }
947
948 #[test]
949 fn expected_type_generic_method() {
950 check_expected_type_and_name(
951 r#"
952fn foo() {
953 S(1u32).bar($0);
954}
955
956struct S<T>(T);
957impl<T> S<T> {
958 fn bar(self, t: T) {}
959}
960"#,
961 expect![[r#"ty: u32, name: t"#]],
962 );
963 }
898} 964}
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 6b04ee164..d7f96b864 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -667,6 +667,13 @@ fn foo() { A { the$0 } }
667 ), 667 ),
668 detail: "u32", 668 detail: "u32",
669 deprecated: true, 669 deprecated: true,
670 relevance: CompletionRelevance {
671 exact_name_match: false,
672 type_match: Some(
673 CouldUnify,
674 ),
675 is_local: false,
676 },
670 }, 677 },
671 ] 678 ]
672 "#]], 679 "#]],