From 4a6cdd776d403bacce0a5471d77e8c76695c5bc5 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 May 2021 16:59:23 +0200 Subject: Record method call substs and use them in call info --- crates/ide_completion/src/context.rs | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'crates/ide_completion/src') diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 787eb2fd3..c929d7394 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -784,6 +784,19 @@ fn foo() { ) } + #[test] + fn expected_type_generic_struct_field() { + check_expected_type_and_name( + r#" +struct Foo { a: T } +fn foo() -> Foo { + Foo { a: $0 } +} +"#, + expect![[r#"ty: u32, name: a"#]], + ) + } + #[test] fn expected_type_struct_field_with_leading_char() { cov_mark::check!(expected_type_struct_field_with_leading_char); @@ -895,4 +908,51 @@ fn foo() -> u32 { expect![[r#"ty: u32, name: ?"#]], ) } + + #[test] + fn expected_type_closure_param() { + check_expected_type_and_name( + r#" +fn foo() { + bar(|| $0); +} + +fn bar(f: impl FnOnce() -> u32) {} +#[lang = "fn_once"] +trait FnOnce { type Output; } +"#, + expect![[r#"ty: u32, name: ?"#]], + ); + } + + #[test] + fn expected_type_generic_function() { + check_expected_type_and_name( + r#" +fn foo() { + bar::($0); +} + +fn bar(t: T) {} +"#, + expect![[r#"ty: u32, name: t"#]], + ); + } + + #[test] + fn expected_type_generic_method() { + check_expected_type_and_name( + r#" +fn foo() { + S(1u32).bar($0); +} + +struct S(T); +impl S { + fn bar(self, t: T) {} +} +"#, + expect![[r#"ty: u32, name: t"#]], + ); + } } -- cgit v1.2.3 From 7a0c93c58ac17b089edd8c9763fef303b7a81414 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 May 2021 18:10:40 +0200 Subject: Infer correct expected type for generic struct fields --- crates/ide_completion/src/context.rs | 32 ++++++++++++++++---------------- crates/ide_completion/src/render.rs | 7 +++++++ 2 files changed, 23 insertions(+), 16 deletions(-) (limited to 'crates/ide_completion/src') diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index c929d7394..4a88a6e88 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -337,25 +337,25 @@ impl<'a> CompletionContext<'a> { }, ast::RecordExprFieldList(_it) => { cov_mark::hit!(expected_type_struct_field_without_leading_char); - self.token.prev_sibling_or_token() - .and_then(|se| se.into_node()) - .and_then(|node| ast::RecordExprField::cast(node)) - .and_then(|rf| self.sema.resolve_record_field(&rf).zip(Some(rf))) - .map(|(f, rf)|( - Some(f.0.ty(self.db)), - rf.field_name().map(NameOrNameRef::NameRef), + // wouldn't try {} be nice... + (|| { + let record_ty = self.sema.type_of_expr(&ast::Expr::cast(node.parent()?)?)?; + let expr_field = self.token.prev_sibling_or_token()? + .into_node() + .and_then(|node| ast::RecordExprField::cast(node))?; + let field = self.sema.resolve_record_field(&expr_field)?.0; + Some(( + record_ty.field_type(self.db, field), + expr_field.field_name().map(NameOrNameRef::NameRef), )) - .unwrap_or((None, None)) + })().unwrap_or((None, None)) }, ast::RecordExprField(it) => { cov_mark::hit!(expected_type_struct_field_with_leading_char); - self.sema - .resolve_record_field(&it) - .map(|f|( - Some(f.0.ty(self.db)), - it.field_name().map(NameOrNameRef::NameRef), - )) - .unwrap_or((None, None)) + ( + it.expr().as_ref().and_then(|e| self.sema.type_of_expr(e)), + it.field_name().map(NameOrNameRef::NameRef), + ) }, ast::MatchExpr(it) => { cov_mark::hit!(expected_type_match_arm_without_leading_char); @@ -910,7 +910,7 @@ fn foo() -> u32 { } #[test] - fn expected_type_closure_param() { + fn expected_type_closure_param_return() { check_expected_type_and_name( r#" fn foo() { 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 } } ), detail: "u32", deprecated: true, + relevance: CompletionRelevance { + exact_name_match: false, + type_match: Some( + CouldUnify, + ), + is_local: false, + }, }, ] "#]], -- cgit v1.2.3 From e65803748d3a4c940b54071caa85b2b71e9d8697 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 May 2021 18:23:03 +0200 Subject: Infer correct expected type in closure Sadly currently only works if the closure body isn't completely missing. --- crates/ide_completion/src/context.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'crates/ide_completion/src') diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 4a88a6e88..efaf4792f 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -382,6 +382,12 @@ impl<'a> CompletionContext<'a> { let def = self.sema.to_def(&it); (def.map(|def| def.ret_type(self.db)), None) }, + ast::ClosureExpr(it) => { + let ty = self.sema.type_of_expr(&it.into()); + ty.and_then(|ty| ty.as_callable(self.db)) + .map(|c| (Some(c.return_type()), None)) + .unwrap_or((None, None)) + }, ast::Stmt(_it) => (None, None), _ => { match node.parent() { @@ -911,10 +917,11 @@ fn foo() -> u32 { #[test] fn expected_type_closure_param_return() { + // FIXME: make this work with `|| $0` check_expected_type_and_name( r#" fn foo() { - bar(|| $0); + bar(|| a$0); } fn bar(f: impl FnOnce() -> u32) {} -- cgit v1.2.3 From b8262099cc51065259daf10b4b23ff49ce74434f Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 May 2021 23:54:35 +0200 Subject: Get rid of field_type again --- crates/ide_completion/src/context.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'crates/ide_completion/src') diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index efaf4792f..1ec59ff80 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -339,13 +339,12 @@ impl<'a> CompletionContext<'a> { cov_mark::hit!(expected_type_struct_field_without_leading_char); // wouldn't try {} be nice... (|| { - let record_ty = self.sema.type_of_expr(&ast::Expr::cast(node.parent()?)?)?; let expr_field = self.token.prev_sibling_or_token()? - .into_node() + .into_node() .and_then(|node| ast::RecordExprField::cast(node))?; - let field = self.sema.resolve_record_field(&expr_field)?.0; + let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?; Some(( - record_ty.field_type(self.db, field), + Some(ty), expr_field.field_name().map(NameOrNameRef::NameRef), )) })().unwrap_or((None, None)) -- cgit v1.2.3