Skip to content

Commit 7659109

Browse files
committed
Auto merge of rust-lang#16136 - saiintbrisson:fix/completion/a-tad-smarter-with-fns, r=Veykril
fix(completion): make the expected type a tad smarter with `Fn`s This commit changes how the expected type is calculated when working with Fn pointers, making the parenthesis stop vanishing when completing the function name. I've been bugged by the behavior of parenthesis completion for a long while now. R-a assumes that the `LetStmt` type is the same as the function type I've just written. Worse is that all parenthesis vanish, even from functions that have completely different signatures. It will now verify if the signature is the same. While working on this, I noticed that record fields behave the same, so I also made it prioritize the field type instead of the current expression when possible, but I'm unsure if this is OK, so input is appreciated. ImplTraits as return types will still behave weirdly because lowering is disallowed at the time it resolves the function types. ![image](https://github.com/rust-lang/rust-analyzer/assets/29989290/c06d6c93-5cac-4ebe-a93b-923017a6ae8c) ![image](https://github.com/rust-lang/rust-analyzer/assets/29989290/31594d82-fa4d-446c-a77e-47e9de1a9a67) ![image](https://github.com/rust-lang/rust-analyzer/assets/29989290/cf33856e-a485-411b-91af-11090d78a44e)
2 parents 34df296 + 9a36bc3 commit 7659109

File tree

4 files changed

+27
-20
lines changed

4 files changed

+27
-20
lines changed

crates/hir/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -4657,6 +4657,9 @@ impl Callable {
46574657
pub fn return_type(&self) -> Type {
46584658
self.ty.derived(self.sig.ret().clone())
46594659
}
4660+
pub fn sig(&self) -> &CallableSig {
4661+
&self.sig
4662+
}
46604663
}
46614664

46624665
fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {

crates/ide-completion/src/context/analysis.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,12 @@ fn expected_type_and_name(
361361
let ty = it.pat()
362362
.and_then(|pat| sema.type_of_pat(&pat))
363363
.or_else(|| it.initializer().and_then(|it| sema.type_of_expr(&it)))
364-
.map(TypeInfo::original);
364+
.map(TypeInfo::original)
365+
.filter(|ty| {
366+
// don't infer the let type if the expr is a function,
367+
// preventing parenthesis from vanishing
368+
it.ty().is_some() || !ty.is_fn()
369+
});
365370
let name = match it.pat() {
366371
Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
367372
Some(_) | None => None,
@@ -415,20 +420,16 @@ fn expected_type_and_name(
415420
})().unwrap_or((None, None))
416421
},
417422
ast::RecordExprField(it) => {
423+
let field_ty = sema.resolve_record_field(&it).map(|(_, _, ty)| ty);
424+
let field_name = it.field_name().map(NameOrNameRef::NameRef);
418425
if let Some(expr) = it.expr() {
419426
cov_mark::hit!(expected_type_struct_field_with_leading_char);
420-
(
421-
sema.type_of_expr(&expr).map(TypeInfo::original),
422-
it.field_name().map(NameOrNameRef::NameRef),
423-
)
427+
let ty = field_ty
428+
.or_else(|| sema.type_of_expr(&expr).map(TypeInfo::original));
429+
(ty, field_name)
424430
} else {
425431
cov_mark::hit!(expected_type_struct_field_followed_by_comma);
426-
let ty = sema.resolve_record_field(&it)
427-
.map(|(_, _, ty)| ty);
428-
(
429-
ty,
430-
it.field_name().map(NameOrNameRef::NameRef),
431-
)
432+
(field_ty, field_name)
432433
}
433434
},
434435
// match foo { $0 }

crates/ide-completion/src/render.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -837,11 +837,11 @@ fn main() {
837837
}
838838
"#,
839839
expect![[r#"
840-
fn main []
841-
fn test []
840+
fn main() []
841+
fn test(…) []
842842
md dep []
843843
fn function (use dep::test_mod_a::function) [requires_import]
844-
fn function (use dep::test_mod_b::function) [requires_import]
844+
fn function(…) (use dep::test_mod_b::function) [requires_import]
845845
"#]],
846846
);
847847
}

crates/ide-completion/src/render/function.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -305,12 +305,15 @@ fn params(
305305
return None;
306306
}
307307

308-
// Don't add parentheses if the expected type is some function reference.
309-
if let Some(ty) = &ctx.expected_type {
310-
// FIXME: check signature matches?
311-
if ty.is_fn() {
312-
cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
313-
return None;
308+
// Don't add parentheses if the expected type is a function reference with the same signature.
309+
if let Some(expected) = ctx.expected_type.as_ref().filter(|e| e.is_fn()) {
310+
if let Some(expected) = expected.as_callable(ctx.db) {
311+
if let Some(completed) = func.ty(ctx.db).as_callable(ctx.db) {
312+
if expected.sig() == completed.sig() {
313+
cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
314+
return None;
315+
}
316+
}
314317
}
315318
}
316319

0 commit comments

Comments
 (0)