@@ -84,8 +84,13 @@ type error =
84
84
| Unknown_literal of string * char
85
85
| Illegal_letrec_pat
86
86
| Empty_record_literal
87
- | Uncurried_arity_mismatch of
88
- type_expr * int * int * Asttypes.Noloc .arg_label list
87
+ | Uncurried_arity_mismatch of {
88
+ function_type : type_expr ;
89
+ expected_arity : int ;
90
+ provided_arity : int ;
91
+ provided_args : Asttypes.Noloc .arg_label list ;
92
+ function_name : Longident .t option ;
93
+ }
89
94
| Field_not_optional of string * type_expr
90
95
| Type_params_not_supported of Longident .t
91
96
| Field_access_on_dict_type
@@ -2230,6 +2235,11 @@ let not_function env ty =
2230
2235
let ls, tvar = list_labels env ty in
2231
2236
ls = [] && not tvar
2232
2237
2238
+ let extract_function_name funct =
2239
+ match funct.exp_desc with
2240
+ | Texp_ident (path , _ , _ ) -> Some (Longident. parse (Path. name path))
2241
+ | _ -> None
2242
+
2233
2243
type lazy_args =
2234
2244
(Asttypes.Noloc .arg_label * (unit -> Typedtree .expression ) option ) list
2235
2245
@@ -3522,10 +3532,13 @@ and type_application ~context total_app env funct (sargs : sargs) :
3522
3532
( funct.exp_loc,
3523
3533
env,
3524
3534
Uncurried_arity_mismatch
3525
- ( funct.exp_type,
3526
- arity,
3527
- List. length sargs,
3528
- sargs |> List. map (fun (a , _ ) -> to_noloc a) ) ));
3535
+ {
3536
+ function_type = funct.exp_type;
3537
+ expected_arity = arity;
3538
+ provided_arity = List. length sargs;
3539
+ provided_args = sargs |> List. map (fun (a , _ ) -> to_noloc a);
3540
+ function_name = extract_function_name funct;
3541
+ } ));
3529
3542
arity
3530
3543
| None -> max_int
3531
3544
in
@@ -3541,10 +3554,13 @@ and type_application ~context total_app env funct (sargs : sargs) :
3541
3554
( funct.exp_loc,
3542
3555
env,
3543
3556
Uncurried_arity_mismatch
3544
- ( funct.exp_type,
3545
- required_args + newarity,
3546
- required_args,
3547
- sargs |> List. map (fun (a , _ ) -> to_noloc a) ) )));
3557
+ {
3558
+ function_type = funct.exp_type;
3559
+ expected_arity = required_args + newarity;
3560
+ provided_arity = required_args;
3561
+ provided_args = sargs |> List. map (fun (a , _ ) -> to_noloc a);
3562
+ function_name = extract_function_name funct;
3563
+ } )));
3548
3564
let new_t =
3549
3565
if fully_applied then new_t
3550
3566
else
@@ -4247,6 +4263,40 @@ let spellcheck ppf unbound_name valid_names =
4247
4263
let spellcheck_idents ppf unbound valid_idents =
4248
4264
spellcheck ppf (Ident. name unbound) (List. map Ident. name valid_idents)
4249
4265
4266
+ let strip_arity_suffix name =
4267
+ let len = String. length name in
4268
+ let rec scan_back i =
4269
+ if i < 0 || name.[i] < '0' || name.[i] > '9' then i + 1
4270
+ else scan_back (i - 1 )
4271
+ in
4272
+ let start_of_digits = scan_back (len - 1 ) in
4273
+ if start_of_digits > 0 && start_of_digits < len then
4274
+ String. sub name 0 start_of_digits
4275
+ else name
4276
+
4277
+ let find_arity_suggestion env function_name target_arity =
4278
+ let base_name = strip_arity_suffix function_name in
4279
+ let candidate =
4280
+ if target_arity = 1 then base_name
4281
+ else base_name ^ string_of_int target_arity
4282
+ in
4283
+ try
4284
+ let path, desc = Env. lookup_value (Longident. parse candidate) env in
4285
+ if Builtin_attributes. deprecated_of_attrs desc.val_attributes <> None then
4286
+ None
4287
+ else
4288
+ let expanded_type = Ctype. expand_head env desc.val_type in
4289
+ let actual_arity =
4290
+ match Ctype. get_arity env expanded_type with
4291
+ | Some arity -> arity
4292
+ | None -> 0
4293
+ in
4294
+ if actual_arity = target_arity then Some (Printtyp. string_of_path path)
4295
+ else None
4296
+ with
4297
+ | Not_found -> None
4298
+ | _ -> None
4299
+
4250
4300
open Format
4251
4301
let longident = Printtyp. longident
4252
4302
let super_report_unification_error = Printtyp. super_report_unification_error
@@ -4516,7 +4566,14 @@ let report_error env loc ppf error =
4516
4566
fprintf ppf
4517
4567
" Empty record literal {} should be type annotated or used in a record \
4518
4568
context."
4519
- | Uncurried_arity_mismatch (typ , arity , args , sargs ) ->
4569
+ | Uncurried_arity_mismatch
4570
+ {
4571
+ function_type = typ;
4572
+ expected_arity = arity;
4573
+ provided_arity = args;
4574
+ provided_args = sargs;
4575
+ function_name = function_name_opt;
4576
+ } ->
4520
4577
(* We need:
4521
4578
- Any arg that's required but isn't passed
4522
4579
- Any arg that is passed but isn't in the fn definition (optional or labelled)
@@ -4625,6 +4682,26 @@ let report_error env loc ppf error =
4625
4682
(if args = 1 then " " else " s" )
4626
4683
arity;
4627
4684
4685
+ (* Add suggestions for related functions with correct arity *)
4686
+ (match function_name_opt with
4687
+ | Some function_name -> (
4688
+ let function_name_str =
4689
+ let buffer = Buffer. create 16 in
4690
+ let formatter = Format. formatter_of_buffer buffer in
4691
+ Printtyp. longident formatter function_name;
4692
+ Format. pp_print_flush formatter () ;
4693
+ Buffer. contents buffer
4694
+ in
4695
+ let suggestion = find_arity_suggestion env function_name_str args in
4696
+ match suggestion with
4697
+ | None -> ()
4698
+ | Some suggestion_str ->
4699
+ fprintf ppf
4700
+ " @,@,Hint: Try @{<info>%s@} instead (takes @{<info>%d@} argument%s)."
4701
+ suggestion_str args
4702
+ (if args = 1 then " " else " s" ))
4703
+ | None -> () );
4704
+
4628
4705
fprintf ppf " @]"
4629
4706
| Field_not_optional (name , typ ) ->
4630
4707
fprintf ppf " Field @{<info>%s@} is not optional in type %a. Use without ?"
0 commit comments