Unnamed repository; edit this file 'description' to name the repository.
hir-ty, ide-diagnostics: use E0057 vs E0061 for arg-count mismatch
The MismatchedArgCount diagnostic previously used code E0107, which is actually 'wrong number of generic arguments'. Split it based on how the call is made: - E0057 for calls through the Fn/FnMut/FnOnce traits (arguments bundled into a tuple via TupleArgumentsFlag::TupleArguments in the inference code) - E0061 for regular function calls This adds an is_fn_trait_call flag on InferenceDiagnostic::MismatchedArgCount and the hir-surface MismatchedArgCount struct, populated from the tuple_arguments flag already tracked by check_call_arguments. The downstream 'if !args_count_matches' push in infer/expr.rs already covers both paths, so the two FIXMEs at the top of the tuple branch are addressed by threading the kind through rather than by adding a new push site. The nightly-only fallback FIXME below (E0059-ish) is left alone per discussion on rust-lang/rust-analyzer#22140. Adds a test 'arg_count_multi_arg_closure' that exercises the multi-argument tuple case via a closure with signature |_a: u8, _b: u8|. This complements the existing 'arg_count_lambda' test (1-tuple case). Refs rust-lang/rust-analyzer#22140
Kivanc Gunalp 12 days ago
parent bec6681 · commit a779751
-rw-r--r--crates/hir-ty/src/infer.rs5
-rw-r--r--crates/hir-ty/src/infer/expr.rs8
-rw-r--r--crates/hir/src/diagnostics.rs18
-rw-r--r--crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs30
4 files changed, 53 insertions, 8 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index bd00da84ca..4036722baf 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -410,6 +410,11 @@ pub enum InferenceDiagnostic {
expected: usize,
#[type_visitable(ignore)]
found: usize,
+ /// True when the call goes through the `Fn`/`FnMut`/`FnOnce` trait
+ /// (i.e. arguments were bundled into a tuple). Determines whether the
+ /// diagnostic surface uses E0057 (Fn-trait call) or E0061 (regular call).
+ #[type_visitable(ignore)]
+ is_fn_trait_call: bool,
},
MismatchedTupleStructPatArgCount {
#[type_visitable(ignore)]
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 20cfc9008a..570df6b871 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -2015,10 +2015,9 @@ impl<'db> InferenceContext<'db> {
match tuple_type.kind() {
// We expected a tuple and got a tuple
TyKind::Tuple(arg_types) => {
- // Argument length differs
- if arg_types.len() != provided_args.len() {
- // FIXME: Emit an error.
- }
+ // Argument length differs. The mismatch is reported below by the
+ // shared `MismatchedArgCount` push (with `is_fn_trait_call = true`,
+ // which the diagnostic surface renders as E0057).
let expected_input_tys = match expected_input_tys {
Some(expected_input_tys) => match expected_input_tys.first() {
Some(ty) => match ty.kind() {
@@ -2068,6 +2067,7 @@ impl<'db> InferenceContext<'db> {
call_expr,
expected: expected_input_tys.len() + skip_indices.len(),
found: provided_args.len(),
+ is_fn_trait_call: tuple_arguments == TupleArgumentsFlag::TupleArguments,
});
}
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index d0801d8efd..0c4191ce2d 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -441,6 +441,9 @@ pub struct MismatchedArgCount {
pub call_expr: InFile<ExprOrPatPtr>,
pub expected: usize,
pub found: usize,
+ /// True when the call is through a `Fn`/`FnMut`/`FnOnce` trait (E0057)
+ /// rather than a regular function call (E0061).
+ pub is_fn_trait_call: bool,
}
#[derive(Debug)]
@@ -885,9 +888,18 @@ impl<'db> AnyDiagnostic<'db> {
};
DuplicateField { field: expr_or_pat, variant: variant.into() }.into()
}
- &InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
- MismatchedArgCount { call_expr: expr_syntax(call_expr)?, expected, found }.into()
- }
+ &InferenceDiagnostic::MismatchedArgCount {
+ call_expr,
+ expected,
+ found,
+ is_fn_trait_call,
+ } => MismatchedArgCount {
+ call_expr: expr_syntax(call_expr)?,
+ expected,
+ found,
+ is_fn_trait_call,
+ }
+ .into(),
&InferenceDiagnostic::PrivateField { expr, field } => {
let expr = expr_syntax(expr)?;
let field = field.into();
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 844431c1e5..fb9095e0f4 100644
--- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -38,8 +38,12 @@ pub(crate) fn mismatched_arg_count(
) -> Diagnostic {
let s = if d.expected == 1 { "" } else { "s" };
let message = format!("expected {} argument{s}, found {}", d.expected, d.found);
+ // E0057 is the code rustc emits when calling something via the `Fn`/`FnMut`/`FnOnce`
+ // traits with the wrong number of arguments; E0061 is used for direct function calls.
+ // (Previously this used E0107, which is actually "wrong number of generic arguments".)
+ let code = if d.is_fn_trait_call { "E0057" } else { "E0061" };
Diagnostic::new(
- DiagnosticCode::RustcHardError("E0107"),
+ DiagnosticCode::RustcHardError(code),
message,
invalid_args_range(ctx, d.call_expr, d.expected, d.found),
)
@@ -395,6 +399,30 @@ fn main() {
)
}
+ // A multi-argument closure exercises the same tuple-arguments code path in
+ // hir-ty (`TupleArgumentsFlag::TupleArguments` in `crates/hir-ty/src/infer/expr.rs`)
+ // as calls through `Fn`/`FnMut`/`FnOnce`. The mismatch is reported with error
+ // code E0057 (rustc's Fn-trait code), not E0061 which is reserved for direct
+ // function calls. `arg_count_lambda` above covers the 1-tuple case; this one
+ // covers the multi-argument case to make sure the tuple size is reported
+ // correctly.
+ #[test]
+ fn arg_count_multi_arg_closure() {
+ check_diagnostics(
+ r#"
+//- minicore: fn
+fn main() {
+ let f = |_a: u8, _b: u8| ();
+ f();
+ //^^ error: expected 2 arguments, found 0
+ f(1, 2);
+ f(1, 2, 3);
+ //^^ error: expected 2 arguments, found 3
+}
+"#,
+ )
+ }
+
#[test]
fn cfgd_out_call_arguments() {
check_diagnostics(