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