@@ -79,8 +79,13 @@ type error =
79
79
| Unknown_literal of string * char
80
80
| Illegal_letrec_pat
81
81
| Empty_record_literal
82
- | Uncurried_arity_mismatch of
83
- type_expr * int * int * Asttypes.Noloc .arg_label list
82
+ | Uncurried_arity_mismatch of {
83
+ function_type : type_expr ;
84
+ expected_arity : int ;
85
+ provided_arity : int ;
86
+ provided_args : Asttypes.Noloc .arg_label list ;
87
+ function_name : Longident .t option ;
88
+ }
84
89
| Field_not_optional of string * type_expr
85
90
| Type_params_not_supported of Longident .t
86
91
| Field_access_on_dict_type
@@ -2218,6 +2223,11 @@ let not_function env ty =
2218
2223
let ls, tvar = list_labels env ty in
2219
2224
ls = [] && not tvar
2220
2225
2226
+ let extract_function_name funct =
2227
+ match funct.exp_desc with
2228
+ | Texp_ident (path , _ , _ ) -> Some (Longident. parse (Path. name path))
2229
+ | _ -> None
2230
+
2221
2231
type lazy_args =
2222
2232
(Asttypes.Noloc .arg_label * (unit -> Typedtree .expression ) option ) list
2223
2233
@@ -3510,10 +3520,13 @@ and type_application ~context total_app env funct (sargs : sargs) :
3510
3520
( funct.exp_loc,
3511
3521
env,
3512
3522
Uncurried_arity_mismatch
3513
- ( funct.exp_type,
3514
- arity,
3515
- List. length sargs,
3516
- sargs |> List. map (fun (a , _ ) -> to_noloc a) ) ));
3523
+ {
3524
+ function_type = funct.exp_type;
3525
+ expected_arity = arity;
3526
+ provided_arity = List. length sargs;
3527
+ provided_args = sargs |> List. map (fun (a , _ ) -> to_noloc a);
3528
+ function_name = extract_function_name funct;
3529
+ } ));
3517
3530
arity
3518
3531
| None -> max_int
3519
3532
in
@@ -3529,10 +3542,13 @@ and type_application ~context total_app env funct (sargs : sargs) :
3529
3542
( funct.exp_loc,
3530
3543
env,
3531
3544
Uncurried_arity_mismatch
3532
- ( funct.exp_type,
3533
- required_args + newarity,
3534
- required_args,
3535
- sargs |> List. map (fun (a , _ ) -> to_noloc a) ) )));
3545
+ {
3546
+ function_type = funct.exp_type;
3547
+ expected_arity = required_args + newarity;
3548
+ provided_arity = required_args;
3549
+ provided_args = sargs |> List. map (fun (a , _ ) -> to_noloc a);
3550
+ function_name = extract_function_name funct;
3551
+ } )));
3536
3552
let new_t =
3537
3553
if fully_applied then new_t
3538
3554
else
@@ -4230,6 +4246,40 @@ let spellcheck ppf unbound_name valid_names =
4230
4246
let spellcheck_idents ppf unbound valid_idents =
4231
4247
spellcheck ppf (Ident. name unbound) (List. map Ident. name valid_idents)
4232
4248
4249
+ let strip_arity_suffix name =
4250
+ let len = String. length name in
4251
+ let rec scan_back i =
4252
+ if i < 0 || name.[i] < '0' || name.[i] > '9' then i + 1
4253
+ else scan_back (i - 1 )
4254
+ in
4255
+ let start_of_digits = scan_back (len - 1 ) in
4256
+ if start_of_digits > 0 && start_of_digits < len then
4257
+ String. sub name 0 start_of_digits
4258
+ else name
4259
+
4260
+ let find_arity_suggestion env function_name target_arity =
4261
+ let base_name = strip_arity_suffix function_name in
4262
+ let candidate =
4263
+ if target_arity = 1 then base_name
4264
+ else base_name ^ string_of_int target_arity
4265
+ in
4266
+ try
4267
+ let path, desc = Env. lookup_value (Longident. parse candidate) env in
4268
+ if Builtin_attributes. deprecated_of_attrs desc.val_attributes <> None then
4269
+ None
4270
+ else
4271
+ let expanded_type = Ctype. expand_head env desc.val_type in
4272
+ let actual_arity =
4273
+ match Ctype. get_arity env expanded_type with
4274
+ | Some arity -> arity
4275
+ | None -> 0
4276
+ in
4277
+ if actual_arity = target_arity then Some (Printtyp. string_of_path path)
4278
+ else None
4279
+ with
4280
+ | Not_found -> None
4281
+ | _ -> None
4282
+
4233
4283
open Format
4234
4284
let longident = Printtyp. longident
4235
4285
let super_report_unification_error = Printtyp. super_report_unification_error
@@ -4489,7 +4539,14 @@ let report_error env loc ppf error =
4489
4539
fprintf ppf
4490
4540
" Empty record literal {} should be type annotated or used in a record \
4491
4541
context."
4492
- | Uncurried_arity_mismatch (typ , arity , args , sargs ) ->
4542
+ | Uncurried_arity_mismatch
4543
+ {
4544
+ function_type = typ;
4545
+ expected_arity = arity;
4546
+ provided_arity = args;
4547
+ provided_args = sargs;
4548
+ function_name = function_name_opt;
4549
+ } ->
4493
4550
(* We need:
4494
4551
- Any arg that's required but isn't passed
4495
4552
- Any arg that is passed but isn't in the fn definition (optional or labelled)
@@ -4598,6 +4655,26 @@ let report_error env loc ppf error =
4598
4655
(if args = 1 then " " else " s" )
4599
4656
arity;
4600
4657
4658
+ (* Add suggestions for functions with correct arity *)
4659
+ (match function_name_opt with
4660
+ | Some function_name -> (
4661
+ let function_name_str =
4662
+ let buffer = Buffer. create 16 in
4663
+ let formatter = Format. formatter_of_buffer buffer in
4664
+ Printtyp. longident formatter function_name;
4665
+ Format. pp_print_flush formatter () ;
4666
+ Buffer. contents buffer
4667
+ in
4668
+ let suggestion = find_arity_suggestion env function_name_str args in
4669
+ match suggestion with
4670
+ | None -> () (* No suggestion found *)
4671
+ | Some suggestion_str ->
4672
+ fprintf ppf
4673
+ " @,@,Hint: Try @{<info>%s@} instead (takes @{<info>%d@} argument%s)."
4674
+ suggestion_str args
4675
+ (if args = 1 then " " else " s" ))
4676
+ | None -> () (* Function name not available *) );
4677
+
4601
4678
fprintf ppf " @]"
4602
4679
| Field_not_optional (name , typ ) ->
4603
4680
fprintf ppf " Field @{<info>%s@} is not optional in type %a. Use without ?"
0 commit comments