@@ -79,8 +79,13 @@ type error =
7979 | Unknown_literal of string * char
8080 | Illegal_letrec_pat
8181 | 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+ }
8489 | Field_not_optional of string * type_expr
8590 | Type_params_not_supported of Longident .t
8691 | Field_access_on_dict_type
@@ -2218,6 +2223,11 @@ let not_function env ty =
22182223 let ls, tvar = list_labels env ty in
22192224 ls = [] && not tvar
22202225
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+
22212231type lazy_args =
22222232 (Asttypes.Noloc .arg_label * (unit -> Typedtree .expression ) option ) list
22232233
@@ -3510,10 +3520,13 @@ and type_application ~context total_app env funct (sargs : sargs) :
35103520 ( funct.exp_loc,
35113521 env,
35123522 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+ } ));
35173530 arity
35183531 | None -> max_int
35193532 in
@@ -3529,10 +3542,13 @@ and type_application ~context total_app env funct (sargs : sargs) :
35293542 ( funct.exp_loc,
35303543 env,
35313544 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+ } )));
35363552 let new_t =
35373553 if fully_applied then new_t
35383554 else
@@ -4230,6 +4246,40 @@ let spellcheck ppf unbound_name valid_names =
42304246let spellcheck_idents ppf unbound valid_idents =
42314247 spellcheck ppf (Ident. name unbound) (List. map Ident. name valid_idents)
42324248
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+
42334283open Format
42344284let longident = Printtyp. longident
42354285let super_report_unification_error = Printtyp. super_report_unification_error
@@ -4489,7 +4539,14 @@ let report_error env loc ppf error =
44894539 fprintf ppf
44904540 " Empty record literal {} should be type annotated or used in a record \
44914541 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+ } ->
44934550 (* We need:
44944551 - Any arg that's required but isn't passed
44954552 - 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 =
45984655 (if args = 1 then " " else " s" )
45994656 arity;
46004657
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+
46014678 fprintf ppf " @]"
46024679 | Field_not_optional (name , typ ) ->
46034680 fprintf ppf " Field @{<info>%s@} is not optional in type %a. Use without ?"
0 commit comments