Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22947 from kivancgnlp/fn-trait-arg-count
hir-ty, ide-diagnostics: use E0057/E0061 for arg-count mismatch (was E0107)
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 5 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 8 | ||||
| -rw-r--r-- | crates/hir/src/diagnostics.rs | 18 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs | 30 |
4 files changed, 53 insertions, 8 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index c838fcc3a7..a5a82209c6 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( |