diff options
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/context.rs | 96 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 7 |
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#" | ||
796 | struct Foo<T> { a: T } | ||
797 | fn 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#" | ||
922 | fn foo() { | ||
923 | bar(|| a$0); | ||
924 | } | ||
925 | |||
926 | fn bar(f: impl FnOnce() -> u32) {} | ||
927 | #[lang = "fn_once"] | ||
928 | trait 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#" | ||
938 | fn foo() { | ||
939 | bar::<u32>($0); | ||
940 | } | ||
941 | |||
942 | fn 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#" | ||
952 | fn foo() { | ||
953 | S(1u32).bar($0); | ||
954 | } | ||
955 | |||
956 | struct S<T>(T); | ||
957 | impl<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 | "#]], |