ocaml / ocaml

The core OCaml system: compilers, runtime system, base libraries
https://ocaml.org
Other
5.5k stars 1.11k forks source link

Refactor `Typecore.type_application` #13612

Open voodoos opened 1 week ago

voodoos commented 1 week ago

This PR proposes a refactor of Typecore.type_application. This work was originally done by @lpw25 in Jane Street's fork of the compiler with extensions. Jane Street has asked for help from Tarides to upstream these changes.

This PR introduces a more descriptive type for arguments of a function application:

type expression_desc =
  | ...
  | Texp_apply of expression * (arg_label * apply_arg) list

and apply_arg = (expression, unit) arg_or_omitted

and ('a, 'b) arg_or_omitted =
  | Arg of 'a
  | Omitted of 'b

These were formerly represented with the type expression option.

The typing of applications is now clearly split in two phases: first collect_apply_args maps over the arguments, classify them and collect additional information. Then type_apply_arg and type_omitted_parameters perform the actual typing.

The classification was previously done by imperatively filling lists such as eliminated_optional_arguments and omitted_parameters. Now it uses the type parameters of arg_or_omitted to store additional information and specific type constructors are introduced for these cases:

type untyped_apply_arg =
  | Known_arg of
      { sarg : Parsetree.expression;
        ty_arg : type_expr;
        ty_arg0 : type_expr;
        mode_arg : Alloc_mode.t;
        wrapped_in_some : bool; }
  | Unknown_arg of
      { sarg : Parsetree.expression;
        ty_arg : type_expr;
        mode_arg : Alloc_mode.t; }
  | Eliminated_optional_arg of
      { mode_fun: Alloc_mode.t;
        ty_arg : type_expr;
        mode_arg : Alloc_mode.t;
        level: int;}

type untyped_omitted_param =
  { mode_fun: Alloc_mode.t;
    ty_arg : type_expr;
    mode_arg : Alloc_mode.t;
    level: int; }

(untyped_apply_arg, untyped_omitted_param) arg_or_omitted

Thus, the flow for typing an application can now be summarized with these three functions:

collect_apply_args :
  ... (arg_label * expression) list ->
  ... * (untyped_apply_arg, untyped_omitted_param) arg_or_omitted list

type_apply_arg :
  ... (untyped_apply_arg, untyped_omitted_param) arg_or_omitted ->
  ... * (Typedtree.expression, untyped_omitted_param) arg_or_omitted

type_omitted_parameters :
  ... (Typedtree.expression, untyped_omitted_param) arg_or_omitted list ->
  ... * (Typedtree.expression, unit) arg_or_omitted list

I was not familiar with the typing process of function application before doing this work but my impression is that these changes do make the code clearer and more robust.

cc @OlivierNicole @goldfirere

goldfirere commented 6 days ago

Thanks, @voodoos, for posting this!

gasche commented 1 day ago

(Note: the fact that the change comes in one big commit makes it harder to review than if it was split in a sequence of smaller changes.)