Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir/src/lib.rs3
-rw-r--r--crates/ide-completion/src/context/analysis.rs23
-rw-r--r--crates/ide-completion/src/render/function.rs15
3 files changed, 24 insertions, 17 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 85762603ed..0d0901d89e 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -4657,6 +4657,9 @@ impl Callable {
pub fn return_type(&self) -> Type {
self.ty.derived(self.sig.ret().clone())
}
+ pub fn sig(&self) -> &CallableSig {
+ &self.sig
+ }
}
fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 2d62c45174..7da6648365 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -361,7 +361,12 @@ fn expected_type_and_name(
let ty = it.pat()
.and_then(|pat| sema.type_of_pat(&pat))
.or_else(|| it.initializer().and_then(|it| sema.type_of_expr(&it)))
- .map(TypeInfo::original);
+ .map(TypeInfo::original)
+ .filter(|ty| {
+ // don't infer the let type if the expr is a function,
+ // preventing parenthesis from vanishing
+ it.ty().is_some() || !ty.is_fn()
+ });
let name = match it.pat() {
Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
Some(_) | None => None,
@@ -415,20 +420,16 @@ fn expected_type_and_name(
})().unwrap_or((None, None))
},
ast::RecordExprField(it) => {
+ let field_ty = sema.resolve_record_field(&it).map(|(_, _, ty)| ty);
+ let field_name = it.field_name().map(NameOrNameRef::NameRef);
if let Some(expr) = it.expr() {
cov_mark::hit!(expected_type_struct_field_with_leading_char);
- (
- sema.type_of_expr(&expr).map(TypeInfo::original),
- it.field_name().map(NameOrNameRef::NameRef),
- )
+ let ty = field_ty
+ .or_else(|| sema.type_of_expr(&expr).map(TypeInfo::original));
+ (ty, field_name)
} else {
cov_mark::hit!(expected_type_struct_field_followed_by_comma);
- let ty = sema.resolve_record_field(&it)
- .map(|(_, _, ty)| ty);
- (
- ty,
- it.field_name().map(NameOrNameRef::NameRef),
- )
+ (field_ty, field_name)
}
},
// match foo { $0 }
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index d23ed71fdc..b306bede65 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -305,12 +305,15 @@ fn params(
return None;
}
- // Don't add parentheses if the expected type is some function reference.
- if let Some(ty) = &ctx.expected_type {
- // FIXME: check signature matches?
- if ty.is_fn() {
- cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
- return None;
+ // Don't add parentheses if the expected type is a function reference with the same signature.
+ if let Some(expected) = ctx.expected_type.as_ref().filter(|e| e.is_fn()) {
+ if let Some(expected) = expected.as_callable(ctx.db) {
+ if let Some(completed) = func.ty(ctx.db).as_callable(ctx.db) {
+ if expected.sig() == completed.sig() {
+ cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
+ return None;
+ }
+ }
}
}