From 5da0c3d50642390d15da099fa5a4e5b57fb7cfe1 Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Wed, 1 Jul 2026 13:06:42 +0200 Subject: [PATCH 1/9] OxCaml: Add tests for modes --- test/generators/cases/oxcaml.mli | 186 ++++++ test/generators/cases/oxcaml_impl.ml | 51 ++ test/generators/html/Oxcaml.html | 790 ++++++++++++++++++++++++ test/generators/html/Oxcaml_impl.html | 255 ++++++++ test/generators/latex/Oxcaml.tex | 123 ++++ test/generators/latex/Oxcaml_impl.tex | 38 ++ test/generators/man/Oxcaml.3o | 422 +++++++++++++ test/generators/man/Oxcaml_impl.3o | 128 ++++ test/generators/markdown/Oxcaml.md | 283 +++++++++ test/generators/markdown/Oxcaml_impl.md | 62 +- 10 files changed, 2337 insertions(+), 1 deletion(-) diff --git a/test/generators/cases/oxcaml.mli b/test/generators/cases/oxcaml.mli index 11db3f653a..0437af1acb 100644 --- a/test/generators/cases/oxcaml.mli +++ b/test/generators/cases/oxcaml.mli @@ -280,3 +280,189 @@ module M3 : sig @@ contended end (** [contended] modality applied to all definitions in the module, except the ones which have already specified this axis. *) + +(** {1 Modes} *) + +val mode_arg : int @ local -> int +(** Mode on a function argument. *) + +val mode_ret : int -> int @ local +(** Mode on a function return. *) + +val mode_both : int @ local -> int @ local +(** Modes on both argument and return. *) + +val mode_multi : string @ local once -> string @ local unique +(** Multiple modes on argument and return. *) + +val mode_labeled : x:int @ local -> int +(** Mode on a labeled argument. *) + +val mode_optional : ?x:int @ local -> unit -> int +(** Mode on an optional argument. *) + +val mode_higher_order : ('a -> 'b) @ local -> 'a -> 'b +(** Mode on a higher-order function argument. *) + +val mode_arrow_result : int -> (int -> int) @ local +(** Mode on a result that is itself an arrow. The arrow must be parenthesized so + the mode does not appear to bind to the inner return type. *) + +(** {2 Curry-implied result modes} + + Closing over an argument constrains the partial-application closure across + several axes, not just locality. When the result mode is the one currying + implies from the argument, it is suppressed (as the compiler does). *) + +val curry_once : (int -> int) @ once -> int -> int +(** [once] argument: the implied [once] result mode is suppressed. *) + +val curry_portable : (int -> int) @ portable -> int -> int +(** [portable] argument: the implied result mode is suppressed. *) + +val curry_contended : (int -> int) @ contended -> int -> int +(** [contended] argument: the implied result mode is suppressed. *) + +(** {2 Result modes that are kept} + + A result mode is only suppressed when it is exactly the one currying + implies. An explicit mode on a different axis is kept (and the arrow result + is parenthesized). *) + +val keep_portable : int @ local -> (int -> int) @ portable +(** [portable] on the result is not implied by a [local] argument, so it is kept. *) + +val keep_once : int @ local -> (int -> int) @ once +(** [once] on the result is not implied by a [local] argument, so it is kept. *) + +val keep_over_once : (int -> int) @ once -> (int -> int) @ portable +(** The curry-implied [once] is suppressed, but the explicit [portable] is kept. *) + +val keep_over_local : (int -> int) @ local -> (int -> int) @ portable +(** The curry-implied [local] is suppressed, but the explicit [portable] is kept. *) + +val keep_portable_over_nonportable : (int -> int) @ nonportable -> (int -> int) @ portable +(** The [nonportable] argument mode is the default and dropped, while the + explicit [portable] result, not implied by currying, is kept. *) + +(** {2 All mode axes} *) + +val mode_global : int @ global -> unit +(** Locality mode (legacy, not rendered). *) + +val mode_local : int @ local -> unit +(** Locality mode. *) + +val mode_aliased : int @ aliased -> unit +(** Uniqueness mode (legacy, not rendered). *) + +val mode_unique : int @ unique -> unit +(** Uniqueness mode. *) + +val mode_many : int @ many -> unit +(** Linearity mode (legacy, not rendered). *) + +val mode_once : int @ once -> unit +(** Linearity mode. *) + +val mode_portable : int @ portable -> unit +(** Portability mode. *) + +val mode_shareable : int @ shareable -> unit +(** Portability mode (intermediate value). *) + +val mode_nonportable : int @ nonportable -> unit +(** Portability mode (legacy, not rendered). *) + +val mode_uncontended : int @ uncontended -> unit +(** Contention mode (legacy, not rendered). *) + +val mode_shared : int @ shared -> unit +(** Contention mode. *) + +val mode_contended : int @ contended -> unit +(** Contention mode. *) + +val mode_yielding : int @ yielding -> unit +(** Yield mode. *) + +val mode_unyielding : int @ unyielding -> unit +(** Yield mode (legacy, not rendered). *) + +val mode_forkable : int @ forkable -> unit +(** Fork mode (identity on a non-[local] argument, not rendered). *) + +val mode_local_forkable : int @ local forkable -> unit +(** Fork mode, rendered because the argument is also [local]. *) + +val mode_unforkable : int @ unforkable -> unit +(** Fork mode. *) + +val mode_local_unforkable : int @ local unforkable -> unit +(** Fork mode (identity for a [local] argument, not rendered). *) + +val mode_stateless : int @ stateless -> unit +(** Statefulness mode. *) + +val mode_observing : int @ observing -> unit +(** Statefulness mode. *) + +val mode_stateful : int @ stateful -> unit +(** Statefulness mode (identity when [portability] is at its default, not rendered). *) + +val mode_immutable : int @ immutable -> unit +(** Visibility mode. *) + +val mode_read : int @ read -> unit +(** Visibility mode. *) + +val mode_read_write : int @ read_write -> unit +(** Visibility mode (legacy, not rendered). *) + +val mode_static : int @ static -> unit +(** Staticity mode. *) + +val mode_dynamic : int @ dynamic -> unit +(** Staticity mode (legacy, not rendered). *) + +(** {2 Cross-axis suppression} + + Some axes have a default value that is implied by another axis; the implied + value is suppressed when rendering. *) + +val mode_local_yielding : int @ local yielding -> unit +(** [yielding] is the default for [local], so it is not rendered. *) + +val mode_local_unyielding : int @ local unyielding -> unit +(** [unyielding] is non-default for [local], so it is rendered. *) + +val mode_immutable_contended : int @ immutable contended -> unit +(** [contended] is the default for [immutable], so it is not rendered. *) + +val mode_immutable_uncontended : int @ immutable uncontended -> unit +(** [uncontended] is non-default for [immutable], so it is rendered. *) + +val mode_stateless_portable : int @ stateless portable -> unit +(** [portable] is the default for [stateless], so it is not rendered. *) + +val mode_stateful_portable : int @ stateful portable -> unit +(** [portable] is non-default for [stateful], so it is rendered. *) + +(** {2 Modes in type definitions} *) + +type mode_alias = int @ local -> int +(** Type alias for an arrow with a mode on its argument. *) + +type mode_record = { + fn : int @ local -> int; (** Record field whose type is an arrow with a mode. *) + fn_both : int @ local -> int @ local; (** Arrow field with modes on both sides. *) + mutable mfn : int @ local -> int; (** Mutable arrow field with a mode. *) +} + +type mode_cstr = + | Mc_arrow of (int @ local -> int) + (** Constructor argument is a parenthesized arrow with a mode. *) + | Mc_nested of ((int @ local -> int) -> unit) + (** Nested arrow: higher-order with a mode on the inner argument. *) + | Mc_gadt : ('a @ once -> 'a) -> mode_cstr + (** GADT constructor *) diff --git a/test/generators/cases/oxcaml_impl.ml b/test/generators/cases/oxcaml_impl.ml index 351121dbe1..3d605794d5 100644 --- a/test/generators/cases/oxcaml_impl.ml +++ b/test/generators/cases/oxcaml_impl.ml @@ -8,3 +8,54 @@ end module Including = struct include To_be_included end + +(* The declarations below exercise reading modes and modalities from an + implementation's [.cmt] file, as opposed to an interface's [.cmti]. *) + +type opaque + +(** {1 Modalities} *) + +(** {2 Modalities on record fields} *) + +type modalities_record = { + f_global : opaque @@ global; (** Locality modality. *) + f_portable : opaque @@ portable; (** Portability modality. *) + f_multi : opaque @@ global portable; (** Multiple modalities. *) + f_plain : opaque; (** No modality, for reference. *) +} + +(** {2 Modalities on constructor arguments} *) + +type modalities_variant = + | A of string @@ global (** Constructor argument with [global] modality. *) + | B of (int -> int) @@ portable + (** Function constructor argument with modality. *) + | C of int @@ portable * string @@ global + (** Per-element modalities in a constructor tuple. *) + +(** {1 Modes} *) + +(** {2 Modes in type definitions} *) + +type mode_alias = int @ local -> int +(** Type alias for an arrow with a mode on its argument. *) + +type mode_record = { + fn : int @ local -> int; (** Field whose type is an arrow with a mode. *) + fn_both : int @ local -> int @ local; (** Modes on both sides. *) +} + +type mode_cstr = + | Mc_arrow of (int @ local -> int) + (** Constructor argument is a parenthesized arrow with a mode. *) + | Mc_nested of ((int @ local -> int) -> unit) + (** Nested arrow: higher-order with a mode on the inner argument. *) + +(** {2 Modes on values} *) + +let mode_arg : int @ local -> int = fun x -> x +(** Mode on a function argument, via a type annotation. *) + +let mode_multi : string @ local once -> string @ local once = fun x -> x +(** Multiple modes on argument and return. *) diff --git a/test/generators/html/Oxcaml.html b/test/generators/html/Oxcaml.html index 88dfb52689..f13c2106e8 100644 --- a/test/generators/html/Oxcaml.html +++ b/test/generators/html/Oxcaml.html @@ -72,6 +72,19 @@

Module Oxcaml

+
  • Modes + +
  • @@ -1181,6 +1194,783 @@

    axis.

    +

    Modes

    +
    +
    + + + val mode_arg : + int -> int + + +

    Mode on a function argument.

    +
    +
    +
    + + + val mode_ret : + int -> int + + +

    Mode on a function return.

    +
    +
    +
    + + + val mode_both : + int -> int + + +
    +

    Modes on both argument and return.

    +
    +
    +
    + + + val mode_multi : + string -> string + + +
    +

    Multiple modes on argument and return.

    +
    +
    +
    + + + val mode_labeled : + x:int + -> + int + + +

    Mode on a labeled argument.

    +
    +
    +
    + + + val mode_optional : + ?x:int + -> + unit -> + int + + +

    Mode on an optional argument.

    +
    +
    +
    + + + val mode_higher_order : + + ( + 'a + -> + 'b) + -> + + 'a + -> + 'b + + +
    +

    Mode on a higher-order function argument.

    +
    +
    +
    +
    + + + val mode_arrow_result : + int -> + int -> int + + +
    +
    +

    Mode on a result that is itself an arrow. The arrow must be + parenthesized so the mode does not appear to bind to the inner + return type. +

    +
    +
    +

    + Curry-implied + result modes +

    +

    Closing over an argument constrains the partial-application closure + across several axes, not just locality. When the result mode is + the one currying implies from the argument, it is suppressed (as + the compiler does). +

    +
    +
    + + + val curry_once : + + (int -> int) + -> + int -> + int + + +
    +
    +

    once argument: the implied once result + mode is suppressed. +

    +
    +
    +
    +
    + + + val curry_portable : + + (int -> int) + -> + int -> + int + + +
    +
    +

    portable argument: the implied result mode is + suppressed. +

    +
    +
    +
    +
    + + + val curry_contended : + + (int -> int) + -> + int -> + int + + +
    +
    +

    contended argument: the implied result mode is + suppressed. +

    +
    +
    +

    + Result modes + that are kept +

    +

    A result mode is only suppressed when it is exactly the one currying + implies. An explicit mode on a different axis is kept (and the arrow + result is parenthesized). +

    +
    +
    + + + val keep_portable : + int -> + int -> int + + +
    +
    +

    portable on the result is not implied by a + local argument, so it is kept. +

    +
    +
    +
    +
    + + + val keep_once : + int -> + int -> int + + +
    +
    +

    once on the result is not implied by a + local argument, so it is kept. +

    +
    +
    +
    +
    + + + val keep_over_once : + + (int -> int) + -> + int -> + int + + +
    +
    +

    The curry-implied once is suppressed, but the explicit + portable is kept. +

    +
    +
    +
    +
    + + + val keep_over_local : + + (int -> int) + -> + int -> + int + + +
    +
    +

    The curry-implied local is suppressed, but the explicit + portable is kept. +

    +
    +
    +
    +
    + + + val keep_portable_over_nonportable + : + + (int -> int) + -> + int -> + int + + +
    +
    +

    The nonportable argument mode is the default and + dropped, while the explicit portable result, not + implied by currying, is kept. +

    +
    +
    +

    + All mode axes +

    +
    +
    + + + val mode_global : + int -> unit + + +
    +

    Locality mode (legacy, not rendered).

    +
    +
    +
    + + + val mode_local : + int -> unit + + +

    Locality mode.

    +
    +
    +
    + + + val mode_aliased : + int -> unit + + +
    +

    Uniqueness mode (legacy, not rendered).

    +
    +
    +
    +
    + + + val mode_unique : + int -> unit + + +

    Uniqueness mode.

    +
    +
    +
    + + + val mode_many : + int -> unit + + +
    +

    Linearity mode (legacy, not rendered).

    +
    +
    +
    + + + val mode_once : + int -> unit + + +

    Linearity mode.

    +
    +
    +
    + + + val mode_portable : + int -> unit + + +

    Portability mode.

    +
    +
    +
    + + + val mode_shareable : + int -> unit + + +
    +

    Portability mode (intermediate value).

    +
    +
    +
    + + + val mode_nonportable : + int -> unit + + +
    +

    Portability mode (legacy, not rendered).

    +
    +
    +
    +
    + + + val mode_uncontended : + int -> unit + + +
    +

    Contention mode (legacy, not rendered).

    +
    +
    +
    +
    + + + val mode_shared : + int -> unit + + +

    Contention mode.

    +
    +
    +
    + + + val mode_contended : + int -> unit + + +

    Contention mode.

    +
    +
    +
    + + + val mode_yielding : + int -> unit + + +

    Yield mode.

    +
    +
    +
    + + + val mode_unyielding : + int -> unit + + +
    +

    Yield mode (legacy, not rendered).

    +
    +
    +
    + + + val mode_forkable : + int -> unit + + +
    +
    +

    Fork mode (identity on a non-local argument, not + rendered). +

    +
    +
    +
    +
    + + + val mode_local_forkable : + int -> unit + + +
    +
    +

    Fork mode, rendered because the argument is also local. +

    +
    +
    +
    +
    + + + val mode_unforkable : + int -> unit + + +

    Fork mode.

    +
    +
    +
    + + + val mode_local_unforkable : + int -> unit + + +
    +
    +

    Fork mode (identity for a local argument, not rendered). +

    +
    +
    +
    +
    + + + val mode_stateless : + int -> unit + + +

    Statefulness mode.

    +
    +
    +
    + + + val mode_observing : + int -> unit + + +

    Statefulness mode.

    +
    +
    +
    + + + val mode_stateful : + int -> unit + + +
    +
    +

    Statefulness mode (identity when portability is + at its default, not rendered). +

    +
    +
    +
    +
    + + + val mode_immutable : + int -> unit + + +

    Visibility mode.

    +
    +
    +
    + + + val mode_read : + int -> unit + + +

    Visibility mode.

    +
    +
    +
    + + + val mode_read_write : + int -> unit + + +
    +

    Visibility mode (legacy, not rendered).

    +
    +
    +
    +
    + + + val mode_static : + int -> unit + + +

    Staticity mode.

    +
    +
    +
    + + + val mode_dynamic : + int -> unit + + +
    +

    Staticity mode (legacy, not rendered).

    +
    +

    + Cross-axis + suppression +

    +

    Some axes have a default value that is implied by another axis; + the implied value is suppressed when rendering. +

    +
    +
    + + + val mode_local_yielding : + int -> unit + + +
    +
    +

    yielding is the default for local, + so it is not rendered. +

    +
    +
    +
    +
    + + + val mode_local_unyielding : + int -> unit + + +
    +
    +

    unyielding is non-default for local + , so it is rendered. +

    +
    +
    +
    +
    + + + val mode_immutable_contended + : int -> unit + + +
    +
    +

    contended is the default for immutable + , so it is not rendered. +

    +
    +
    +
    +
    + + + val mode_immutable_uncontended + : int -> unit + + +
    +
    +

    uncontended is non-default for immutable + , so it is rendered. +

    +
    +
    +
    +
    + + + val mode_stateless_portable : + int -> unit + + +
    +
    +

    portable is the default for stateless + , so it is not rendered. +

    +
    +
    +
    +
    + + + val mode_stateful_portable : + int -> unit + + +
    +
    +

    portable is non-default for stateful + , so it is rendered. +

    +
    +
    +

    + Modes in + type definitions +

    +
    +
    + + type mode_alias + = int -> int + + +
    +
    +

    Type alias for an arrow with a mode on its argument.

    +
    +
    +
    +
    + + type mode_record + = { + +
      +
    1. + + + fn : int -> int; + + +
      (* +

      Record field whose type is an arrow with a mode.

      + *) +
      +
    2. +
    3. + + + fn_both : int -> + int; + + +
      (* +

      Arrow field with modes on both sides.

      + *) +
      +
    4. +
    5. + + + mutable mfn : + int -> int; + + +
      (* +

      Mutable arrow field with a mode.

      + *) +
      +
    6. +
    } +
    +
    +
    +
    + + type mode_cstr + = + +
      +
    1. + | + Mc_arrow + of + int -> int + + +
      (* +

      Constructor argument is a parenthesized arrow with a mode.

      + *) +
      +
    2. +
    3. + | + Mc_nested + of + + (int -> int) + -> + unit + + +
      (* +

      Nested arrow: higher-order with a mode on the inner argument.

      + *) +
      +
    4. +
    5. + | + Mc_gadt : + ( + 'a + -> + 'a) + -> + mode_cstr + + +
      (* +

      GADT constructor

      *) +
      +
    6. +
    +
    diff --git a/test/generators/html/Oxcaml_impl.html b/test/generators/html/Oxcaml_impl.html index 285dc626a8..5050a6c387 100644 --- a/test/generators/html/Oxcaml_impl.html +++ b/test/generators/html/Oxcaml_impl.html @@ -14,6 +14,31 @@

    Module Oxcaml_impl

    +
    + +
    @@ -54,6 +79,236 @@

    Module Oxcaml_impl

    +
    +
    + + type opaque +
    +
    +

    Modalities +

    +

    + Modalities + on record fields +

    +
    +
    + + type modalities_record + = { + +
      +
    1. + + + f_global : opaque @@ global; + +
      (* +

      Locality modality.

      *) +
      +
    2. +
    3. + + + f_portable : opaque @@ portable; + + +
      (* +

      Portability modality.

      *) +
      +
    4. +
    5. + + + f_multi : opaque @@ global portable; + + +
      (* +

      Multiple modalities.

      *) +
      +
    6. +
    7. + + f_plain : opaque; +
      (* +

      No modality, for reference.

      + *) +
      +
    8. +
    } +
    +
    +

    + + Modalities on constructor arguments +

    +
    +
    + + type modalities_variant + = + +
      +
    1. + | + A + of string @@ global + + +
      (* +

      Constructor argument with global modality.

      + *) +
      +
    2. +
    3. + | + B + of + int -> int @@ + portable + + +
      (* +

      Function constructor argument with modality.

      + *) +
      +
    4. +
    5. + | + C + of int @@ portable * string @@ + global + + +
      (* +

      Per-element modalities in a constructor tuple.

      + *) +
      +
    6. +
    +
    +

    Modes

    +

    + Modes in + type definitions +

    +
    +
    + + type mode_alias + = int -> int + + +
    +
    +

    Type alias for an arrow with a mode on its argument.

    +
    +
    +
    +
    + + type mode_record + = { + +
      +
    1. + + + fn : int -> int; + + +
      (* +

      Field whose type is an arrow with a mode.

      + *) +
      +
    2. +
    3. + + + fn_both : int -> + int; + + +
      (* +

      Modes on both sides.

      *) +
      +
    4. +
    } +
    +
    +
    +
    + + type mode_cstr + = + +
      +
    1. + | + Mc_arrow + of + int -> int + + +
      (* +

      Constructor argument is a parenthesized arrow with a mode.

      + *) +
      +
    2. +
    3. + | + Mc_nested + of + + (int -> int) + -> + unit + + +
      (* +

      Nested arrow: higher-order with a mode on the inner argument.

      + *) +
      +
    4. +
    +
    +
    +

    + Modes on values +

    +
    +
    + + + val mode_arg : + int -> int + + +
    +
    +

    Mode on a function argument, via a type annotation.

    +
    +
    +
    +
    + + + val mode_multi : + string -> string + + +
    +

    Multiple modes on argument and return.

    +
    diff --git a/test/generators/latex/Oxcaml.tex b/test/generators/latex/Oxcaml.tex index 86830b7210..eb6a4a3c16 100644 --- a/test/generators/latex/Oxcaml.tex +++ b/test/generators/latex/Oxcaml.tex @@ -240,5 +240,128 @@ \subsubsection{Modalities on module declarations\label{Oxcaml--modalities-on-mod \end{ocamlindent}% \ocamlcodefragment{\ocamltag{keyword}{end}}\begin{ocamlindent}\ocamlinlinecode{contended} modality applied to all definitions in the module, except the ones which have already specified this axis.\end{ocamlindent}% \medbreak +\subsection{Modes\label{Oxcaml--modes}}% +\label{Oxcaml--val-mode_arg}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arg : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function argument.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_ret}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}ret : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function return.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_both}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}both : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Modes on both argument and return.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_multi}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi : string \ocamltag{arrow}{$\rightarrow$} string}\begin{ocamlindent}Multiple modes on argument and return.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_labeled}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}labeled : \ocamltag{label}{x}:int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a labeled argument.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_optional}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}optional : \ocamltag{optlabel}{?x}:int \ocamltag{arrow}{$\rightarrow$} unit \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on an optional argument.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_higher_order}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}higher\_\allowbreak{}order : (\ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'b}) \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'b}}\begin{ocamlindent}Mode on a higher-order function argument.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_arrow_result}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arrow\_\allowbreak{}result : int \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a result that is itself an arrow. The arrow must be parenthesized so the mode does not appear to bind to the inner return type.\end{ocamlindent}% +\medbreak +\subsubsection{Curry-implied result modes\label{Oxcaml--curry-implied-result-modes}}% +Closing over an argument constrains the partial-application closure across several axes, not just locality. When the result mode is the one currying implies from the argument, it is suppressed (as the compiler does). + +\label{Oxcaml--val-curry_once}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}once : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{once} argument: the implied \ocamlinlinecode{once} result mode is suppressed.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-curry_portable}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}portable : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{portable} argument: the implied result mode is suppressed.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-curry_contended}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}contended : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{contended} argument: the implied result mode is suppressed.\end{ocamlindent}% +\medbreak +\subsubsection{Result modes that are kept\label{Oxcaml--result-modes-that-are-kept}}% +A result mode is only suppressed when it is exactly the one currying implies. An explicit mode on a different axis is kept (and the arrow result is parenthesized). + +\label{Oxcaml--val-keep_portable}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{portable} on the result is not implied by a \ocamlinlinecode{local} argument, so it is kept.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-keep_once}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}once : int \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{once} on the result is not implied by a \ocamlinlinecode{local} argument, so it is kept.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-keep_over_once}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}over\_\allowbreak{}once : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}The curry-implied \ocamlinlinecode{once} is suppressed, but the explicit \ocamlinlinecode{portable} is kept.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-keep_over_local}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}over\_\allowbreak{}local : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}The curry-implied \ocamlinlinecode{local} is suppressed, but the explicit \ocamlinlinecode{portable} is kept.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-keep_portable_over_nonportable}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}portable\_\allowbreak{}over\_\allowbreak{}nonportable : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}The \ocamlinlinecode{nonportable} argument mode is the default and dropped, while the explicit \ocamlinlinecode{portable} result, not implied by currying, is kept.\end{ocamlindent}% +\medbreak +\subsubsection{All mode axes\label{Oxcaml--all-mode-axes}}% +\label{Oxcaml--val-mode_global}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}global : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Locality mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_local}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Locality mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_aliased}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}aliased : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Uniqueness mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_unique}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unique : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Uniqueness mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_many}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}many : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Linearity mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_once}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}once : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Linearity mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_shareable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}shareable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode (intermediate value).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_nonportable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}nonportable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_uncontended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}uncontended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_shared}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}shared : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_contended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}contended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_yielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}yielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Yield mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_unyielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unyielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Yield mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_forkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}forkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode (identity on a non-\ocamlinlinecode{local} argument, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_local_forkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}forkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode, rendered because the argument is also \ocamlinlinecode{local}.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_unforkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unforkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_local_unforkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}unforkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode (identity for a \ocamlinlinecode{local} argument, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_stateless}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateless : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_observing}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}observing : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_stateful}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateful : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode (identity when \ocamlinlinecode{portability} is at its default, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_immutable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_read}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}read : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_read_write}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}read\_\allowbreak{}write : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_static}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}static : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Staticity mode.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_dynamic}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}dynamic : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Staticity mode (legacy, not rendered).\end{ocamlindent}% +\medbreak +\subsubsection{Cross-axis suppression\label{Oxcaml--cross-axis-suppression}}% +Some axes have a default value that is implied by another axis; the implied value is suppressed when rendering. + +\label{Oxcaml--val-mode_local_yielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}yielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{yielding} is the default for \ocamlinlinecode{local}, so it is not rendered.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_local_unyielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}unyielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{unyielding} is non-default for \ocamlinlinecode{local}, so it is rendered.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_immutable_contended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable\_\allowbreak{}contended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{contended} is the default for \ocamlinlinecode{immutable}, so it is not rendered.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_immutable_uncontended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable\_\allowbreak{}uncontended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{uncontended} is non-default for \ocamlinlinecode{immutable}, so it is rendered.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_stateless_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateless\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{portable} is the default for \ocamlinlinecode{stateless}, so it is not rendered.\end{ocamlindent}% +\medbreak +\label{Oxcaml--val-mode_stateful_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateful\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{portable} is non-default for \ocamlinlinecode{stateful}, so it is rendered.\end{ocamlindent}% +\medbreak +\subsubsection{Modes in type definitions\label{Oxcaml--modes-in-type-definitions}}% +\label{Oxcaml--type-mode_alias}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}alias = int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Type alias for an arrow with a mode on its argument.\end{ocamlindent}% +\medbreak +\label{Oxcaml--type-mode_record}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}record = \{}\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlinlinecode{fn : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.fn}& Record field whose type is an arrow with a mode.\\ +\ocamlinlinecode{fn\_\allowbreak{}both : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.fn_both}& Arrow field with modes on both sides.\\ +\ocamlinlinecode{\ocamltag{keyword}{mutable} mfn : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.mfn}& Mutable arrow field with a mode.\\ +\end{ocamltabular}% +\\ +\ocamlcodefragment{\}}\\ +\label{Oxcaml--type-mode_cstr}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}cstr = }\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}arrow} \ocamltag{keyword}{of} int \ocamltag{arrow}{$\rightarrow$} int}\label{Oxcaml--type-mode_cstr.Mc_arrow}& Constructor argument is a parenthesized arrow with a mode.\\ +\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}nested} \ocamltag{keyword}{of} (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} unit}\label{Oxcaml--type-mode_cstr.Mc_nested}& Nested arrow: higher-order with a mode on the inner argument.\\ +\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}gadt} : (\ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a}) \ocamltag{arrow}{$\rightarrow$} \hyperref[Oxcaml--type-mode_cstr]{\ocamlinlinecode{mode\_\allowbreak{}cstr}}}\label{Oxcaml--type-mode_cstr.Mc_gadt}& GADT constructor\\ +\end{ocamltabular}% +\\ \input{Oxcaml.M1.tex} diff --git a/test/generators/latex/Oxcaml_impl.tex b/test/generators/latex/Oxcaml_impl.tex index 149a39e20c..f17d359a97 100644 --- a/test/generators/latex/Oxcaml_impl.tex +++ b/test/generators/latex/Oxcaml_impl.tex @@ -6,5 +6,43 @@ \section{Module \ocamlinlinecode{Oxcaml\_\allowbreak{}impl}}\label{Oxcaml_impl}% \label{Oxcaml_impl--module-Including}\ocamlcodefragment{\ocamltag{keyword}{module} \hyperref[Oxcaml_impl-Including]{\ocamlinlinecode{Including}}}\label{Oxcaml_impl-Including}\ocamlcodefragment{ : \ocamltag{keyword}{sig}}\begin{ocamlindent}\ocamltag{keyword}{include} \ocamltag{keyword}{module} \ocamltag{keyword}{type} \ocamltag{keyword}{of} \ocamltag{keyword}{struct} \ocamltag{keyword}{include} \hyperref[Oxcaml_impl-To_be_included]{\ocamlinlinecode{To\_\allowbreak{}be\_\allowbreak{}included}} \ocamltag{keyword}{end}\label{Oxcaml_impl-Including--val-add}\ocamlcodefragment{\ocamltag{keyword}{val} add : bool \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int [@@zero\_\allowbreak{}alloc]}\\ \end{ocamlindent}% \ocamlcodefragment{\ocamltag{keyword}{end}}\\ +\label{Oxcaml_impl--type-opaque}\ocamlcodefragment{\ocamltag{keyword}{type} opaque}\\ +\subsection{Modalities\label{Oxcaml_impl--modalities}}% +\subsubsection{Modalities on record fields\label{Oxcaml_impl--modalities-on-record-fields}}% +\label{Oxcaml_impl--type-modalities_record}\ocamlcodefragment{\ocamltag{keyword}{type} modalities\_\allowbreak{}record = \{}\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlinlinecode{f\_\allowbreak{}global : \hyperref[Oxcaml_impl--type-opaque]{\ocamlinlinecode{opaque}} @@ global;\allowbreak{}}\label{Oxcaml_impl--type-modalities_record.f_global}& Locality modality.\\ +\ocamlinlinecode{f\_\allowbreak{}portable : \hyperref[Oxcaml_impl--type-opaque]{\ocamlinlinecode{opaque}} @@ portable;\allowbreak{}}\label{Oxcaml_impl--type-modalities_record.f_portable}& Portability modality.\\ +\ocamlinlinecode{f\_\allowbreak{}multi : \hyperref[Oxcaml_impl--type-opaque]{\ocamlinlinecode{opaque}} @@ global portable;\allowbreak{}}\label{Oxcaml_impl--type-modalities_record.f_multi}& Multiple modalities.\\ +\ocamlinlinecode{f\_\allowbreak{}plain : \hyperref[Oxcaml_impl--type-opaque]{\ocamlinlinecode{opaque}};\allowbreak{}}\label{Oxcaml_impl--type-modalities_record.f_plain}& No modality, for reference.\\ +\end{ocamltabular}% +\\ +\ocamlcodefragment{\}}\\ +\subsubsection{Modalities on constructor arguments\label{Oxcaml_impl--modalities-on-constructor-arguments}}% +\label{Oxcaml_impl--type-modalities_variant}\ocamlcodefragment{\ocamltag{keyword}{type} modalities\_\allowbreak{}variant = }\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlcodefragment{| \ocamltag{constructor}{A} \ocamltag{keyword}{of} string @@ global}\label{Oxcaml_impl--type-modalities_variant.A}& Constructor argument with \ocamlinlinecode{global} modality.\\ +\ocamlcodefragment{| \ocamltag{constructor}{B} \ocamltag{keyword}{of} int \ocamltag{arrow}{$\rightarrow$} int @@ portable}\label{Oxcaml_impl--type-modalities_variant.B}& Function constructor argument with modality.\\ +\ocamlcodefragment{| \ocamltag{constructor}{C} \ocamltag{keyword}{of} int @@ portable * string @@ global}\label{Oxcaml_impl--type-modalities_variant.C}& Per-element modalities in a constructor tuple.\\ +\end{ocamltabular}% +\\ +\subsection{Modes\label{Oxcaml_impl--modes}}% +\subsubsection{Modes in type definitions\label{Oxcaml_impl--modes-in-type-definitions}}% +\label{Oxcaml_impl--type-mode_alias}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}alias = int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Type alias for an arrow with a mode on its argument.\end{ocamlindent}% +\medbreak +\label{Oxcaml_impl--type-mode_record}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}record = \{}\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlinlinecode{fn : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml_impl--type-mode_record.fn}& Field whose type is an arrow with a mode.\\ +\ocamlinlinecode{fn\_\allowbreak{}both : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml_impl--type-mode_record.fn_both}& Modes on both sides.\\ +\end{ocamltabular}% +\\ +\ocamlcodefragment{\}}\\ +\label{Oxcaml_impl--type-mode_cstr}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}cstr = }\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}arrow} \ocamltag{keyword}{of} int \ocamltag{arrow}{$\rightarrow$} int}\label{Oxcaml_impl--type-mode_cstr.Mc_arrow}& Constructor argument is a parenthesized arrow with a mode.\\ +\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}nested} \ocamltag{keyword}{of} (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} unit}\label{Oxcaml_impl--type-mode_cstr.Mc_nested}& Nested arrow: higher-order with a mode on the inner argument.\\ +\end{ocamltabular}% +\\ +\subsubsection{Modes on values\label{Oxcaml_impl--modes-on-values}}% +\label{Oxcaml_impl--val-mode_arg}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arg : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function argument, via a type annotation.\end{ocamlindent}% +\medbreak +\label{Oxcaml_impl--val-mode_multi}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi : string \ocamltag{arrow}{$\rightarrow$} string}\begin{ocamlindent}Multiple modes on argument and return.\end{ocamlindent}% +\medbreak diff --git a/test/generators/man/Oxcaml.3o b/test/generators/man/Oxcaml.3o index ada6bbb18b..928d7b4962 100644 --- a/test/generators/man/Oxcaml.3o +++ b/test/generators/man/Oxcaml.3o @@ -681,4 +681,426 @@ Module with portable modality\. The modality is applied to all value members of .ti +2 contended modality applied to all definitions in the module, except the ones which have already specified this axis\. .nf +.sp +.in 3 +\fB15 Modes\fR +.in +.sp +\f[CB]val\fR mode_arg : int \f[CB]\->\fR int +.fi +.br +.ti +2 +Mode on a function argument\. +.nf +.sp +\f[CB]val\fR mode_ret : int \f[CB]\->\fR int +.fi +.br +.ti +2 +Mode on a function return\. +.nf +.sp +\f[CB]val\fR mode_both : int \f[CB]\->\fR int +.fi +.br +.ti +2 +Modes on both argument and return\. +.nf +.sp +\f[CB]val\fR mode_multi : string \f[CB]\->\fR string +.fi +.br +.ti +2 +Multiple modes on argument and return\. +.nf +.sp +\f[CB]val\fR mode_labeled : \f[CB]x\fR:int \f[CB]\->\fR int +.fi +.br +.ti +2 +Mode on a labeled argument\. +.nf +.sp +\f[CB]val\fR mode_optional : \f[CB]?x\fR:int \f[CB]\->\fR unit \f[CB]\->\fR int +.fi +.br +.ti +2 +Mode on an optional argument\. +.nf +.sp +\f[CB]val\fR mode_higher_order : (\f[CB]'a\fR \f[CB]\->\fR \f[CB]'b\fR) \f[CB]\->\fR \f[CB]'a\fR \f[CB]\->\fR \f[CB]'b\fR +.fi +.br +.ti +2 +Mode on a higher-order function argument\. +.nf +.sp +\f[CB]val\fR mode_arrow_result : int \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +Mode on a result that is itself an arrow\. The arrow must be parenthesized so the mode does not appear to bind to the inner return type\. +.nf +.sp +.in 4 +\fB15\.1 Curry-implied result modes\fR +.in +.sp +.fi +Closing over an argument constrains the partial-application closure across several axes, not just locality\. When the result mode is the one currying implies from the argument, it is suppressed (as the compiler does)\. +.nf +.sp +\f[CB]val\fR curry_once : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +once argument: the implied once result mode is suppressed\. +.nf +.sp +\f[CB]val\fR curry_portable : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +portable argument: the implied result mode is suppressed\. +.nf +.sp +\f[CB]val\fR curry_contended : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +contended argument: the implied result mode is suppressed\. +.nf +.sp +.in 4 +\fB15\.2 Result modes that are kept\fR +.in +.sp +.fi +A result mode is only suppressed when it is exactly the one currying implies\. An explicit mode on a different axis is kept (and the arrow result is parenthesized)\. +.nf +.sp +\f[CB]val\fR keep_portable : int \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +portable on the result is not implied by a local argument, so it is kept\. +.nf +.sp +\f[CB]val\fR keep_once : int \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +once on the result is not implied by a local argument, so it is kept\. +.nf +.sp +\f[CB]val\fR keep_over_once : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +The curry-implied once is suppressed, but the explicit portable is kept\. +.nf +.sp +\f[CB]val\fR keep_over_local : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +The curry-implied local is suppressed, but the explicit portable is kept\. +.nf +.sp +\f[CB]val\fR keep_portable_over_nonportable : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +.fi +.br +.ti +2 +The nonportable argument mode is the default and dropped, while the explicit portable result, not implied by currying, is kept\. +.nf +.sp +.in 4 +\fB15\.3 All mode axes\fR +.in +.sp +\f[CB]val\fR mode_global : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Locality mode (legacy, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_local : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Locality mode\. +.nf +.sp +\f[CB]val\fR mode_aliased : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Uniqueness mode (legacy, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_unique : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Uniqueness mode\. +.nf +.sp +\f[CB]val\fR mode_many : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Linearity mode (legacy, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_once : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Linearity mode\. +.nf +.sp +\f[CB]val\fR mode_portable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Portability mode\. +.nf +.sp +\f[CB]val\fR mode_shareable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Portability mode (intermediate value)\. +.nf +.sp +\f[CB]val\fR mode_nonportable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Portability mode (legacy, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_uncontended : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Contention mode (legacy, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_shared : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Contention mode\. +.nf +.sp +\f[CB]val\fR mode_contended : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Contention mode\. +.nf +.sp +\f[CB]val\fR mode_yielding : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Yield mode\. +.nf +.sp +\f[CB]val\fR mode_unyielding : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Yield mode (legacy, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_forkable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Fork mode (identity on a non-local argument, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_local_forkable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Fork mode, rendered because the argument is also local\. +.nf +.sp +\f[CB]val\fR mode_unforkable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Fork mode\. +.nf +.sp +\f[CB]val\fR mode_local_unforkable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Fork mode (identity for a local argument, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_stateless : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Statefulness mode\. +.nf +.sp +\f[CB]val\fR mode_observing : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Statefulness mode\. +.nf +.sp +\f[CB]val\fR mode_stateful : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Statefulness mode (identity when portability is at its default, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_immutable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Visibility mode\. +.nf +.sp +\f[CB]val\fR mode_read : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Visibility mode\. +.nf +.sp +\f[CB]val\fR mode_read_write : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Visibility mode (legacy, not rendered)\. +.nf +.sp +\f[CB]val\fR mode_static : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Staticity mode\. +.nf +.sp +\f[CB]val\fR mode_dynamic : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +Staticity mode (legacy, not rendered)\. +.nf +.sp +.in 4 +\fB15\.4 Cross-axis suppression\fR +.in +.sp +.fi +Some axes have a default value that is implied by another axis; the implied value is suppressed when rendering\. +.nf +.sp +\f[CB]val\fR mode_local_yielding : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +yielding is the default for local, so it is not rendered\. +.nf +.sp +\f[CB]val\fR mode_local_unyielding : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +unyielding is non-default for local, so it is rendered\. +.nf +.sp +\f[CB]val\fR mode_immutable_contended : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +contended is the default for immutable, so it is not rendered\. +.nf +.sp +\f[CB]val\fR mode_immutable_uncontended : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +uncontended is non-default for immutable, so it is rendered\. +.nf +.sp +\f[CB]val\fR mode_stateless_portable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +portable is the default for stateless, so it is not rendered\. +.nf +.sp +\f[CB]val\fR mode_stateful_portable : int \f[CB]\->\fR unit +.fi +.br +.ti +2 +portable is non-default for stateful, so it is rendered\. +.nf +.sp +.in 4 +\fB15\.5 Modes in type definitions\fR +.in +.sp +\f[CB]type\fR mode_alias = int \f[CB]\->\fR int +.fi +.br +.ti +2 +Type alias for an arrow with a mode on its argument\. +.nf +.sp +\f[CB]type\fR mode_record = { +.br +.ti +2 +fn : int \f[CB]\->\fR int; +.br +.ti +4 +(* Record field whose type is an arrow with a mode\. *) +.br +.ti +2 +fn_both : int \f[CB]\->\fR int; +.br +.ti +4 +(* Arrow field with modes on both sides\. *) +.br +.ti +2 +\f[CB]mutable\fR mfn : int \f[CB]\->\fR int; +.br +.ti +4 +(* Mutable arrow field with a mode\. *) +.br +} +.sp +\f[CB]type\fR mode_cstr = +.br +.ti +2 +| \f[CB]Mc_arrow\fR \f[CB]of\fR int \f[CB]\->\fR int +.br +.ti +4 +(* Constructor argument is a parenthesized arrow with a mode\. *) +.br +.ti +2 +| \f[CB]Mc_nested\fR \f[CB]of\fR (int \f[CB]\->\fR int) \f[CB]\->\fR unit +.br +.ti +4 +(* Nested arrow: higher-order with a mode on the inner argument\. *) +.br +.ti +2 +| \f[CB]Mc_gadt\fR : (\f[CB]'a\fR \f[CB]\->\fR \f[CB]'a\fR) \f[CB]\->\fR mode_cstr +.br +.ti +4 +(* GADT constructor *) +.br diff --git a/test/generators/man/Oxcaml_impl.3o b/test/generators/man/Oxcaml_impl.3o index c73fcd111f..1d2ea4d112 100644 --- a/test/generators/man/Oxcaml_impl.3o +++ b/test/generators/man/Oxcaml_impl.3o @@ -16,3 +16,131 @@ Oxcaml_impl \f[CB]module\fR To_be_included : \f[CB]sig\fR \.\.\. \f[CB]end\fR .sp \f[CB]module\fR Including : \f[CB]sig\fR \.\.\. \f[CB]end\fR +.sp +\f[CB]type\fR opaque +.sp +.in 3 +\fB1 Modalities\fR +.in +.sp +.in 4 +\fB1\.1 Modalities on record fields\fR +.in +.sp +\f[CB]type\fR modalities_record = { +.br +.ti +2 +f_global : opaque @@ global; +.br +.ti +4 +(* Locality modality\. *) +.br +.ti +2 +f_portable : opaque @@ portable; +.br +.ti +4 +(* Portability modality\. *) +.br +.ti +2 +f_multi : opaque @@ global portable; +.br +.ti +4 +(* Multiple modalities\. *) +.br +.ti +2 +f_plain : opaque; +.br +.ti +4 +(* No modality, for reference\. *) +.br +} +.sp +.in 4 +\fB1\.2 Modalities on constructor arguments\fR +.in +.sp +\f[CB]type\fR modalities_variant = +.br +.ti +2 +| \f[CB]A\fR \f[CB]of\fR string @@ global +.br +.ti +4 +(* Constructor argument with global modality\. *) +.br +.ti +2 +| \f[CB]B\fR \f[CB]of\fR int \f[CB]\->\fR int @@ portable +.br +.ti +4 +(* Function constructor argument with modality\. *) +.br +.ti +2 +| \f[CB]C\fR \f[CB]of\fR int @@ portable * string @@ global +.br +.ti +4 +(* Per-element modalities in a constructor tuple\. *) +.br +.sp +.in 3 +\fB2 Modes\fR +.in +.sp +.in 4 +\fB2\.1 Modes in type definitions\fR +.in +.sp +\f[CB]type\fR mode_alias = int \f[CB]\->\fR int +.fi +.br +.ti +2 +Type alias for an arrow with a mode on its argument\. +.nf +.sp +\f[CB]type\fR mode_record = { +.br +.ti +2 +fn : int \f[CB]\->\fR int; +.br +.ti +4 +(* Field whose type is an arrow with a mode\. *) +.br +.ti +2 +fn_both : int \f[CB]\->\fR int; +.br +.ti +4 +(* Modes on both sides\. *) +.br +} +.sp +\f[CB]type\fR mode_cstr = +.br +.ti +2 +| \f[CB]Mc_arrow\fR \f[CB]of\fR int \f[CB]\->\fR int +.br +.ti +4 +(* Constructor argument is a parenthesized arrow with a mode\. *) +.br +.ti +2 +| \f[CB]Mc_nested\fR \f[CB]of\fR (int \f[CB]\->\fR int) \f[CB]\->\fR unit +.br +.ti +4 +(* Nested arrow: higher-order with a mode on the inner argument\. *) +.br +.sp +.in 4 +\fB2\.2 Modes on values\fR +.in +.sp +\f[CB]val\fR mode_arg : int \f[CB]\->\fR int +.fi +.br +.ti +2 +Mode on a function argument, via a type annotation\. +.nf +.sp +\f[CB]val\fR mode_multi : string \f[CB]\->\fR string +.fi +.br +.ti +2 +Multiple modes on argument and return\. +.nf + diff --git a/test/generators/markdown/Oxcaml.md b/test/generators/markdown/Oxcaml.md index 20ba08da3f..d26575cfd4 100644 --- a/test/generators/markdown/Oxcaml.md +++ b/test/generators/markdown/Oxcaml.md @@ -345,3 +345,286 @@ Module with `portable` modality. The modality is applied to all value members of module M3 : sig ... end ``` `contended` modality applied to all definitions in the module, except the ones which have already specified this axis. + + +## Modes + +```ocaml +val mode_arg : int -> int +``` +Mode on a function argument. + +```ocaml +val mode_ret : int -> int +``` +Mode on a function return. + +```ocaml +val mode_both : int -> int +``` +Modes on both argument and return. + +```ocaml +val mode_multi : string -> string +``` +Multiple modes on argument and return. + +```ocaml +val mode_labeled : x:int -> int +``` +Mode on a labeled argument. + +```ocaml +val mode_optional : ?x:int -> unit -> int +``` +Mode on an optional argument. + +```ocaml +val mode_higher_order : ('a -> 'b) -> 'a -> 'b +``` +Mode on a higher-order function argument. + +```ocaml +val mode_arrow_result : int -> int -> int +``` +Mode on a result that is itself an arrow. The arrow must be parenthesized so the mode does not appear to bind to the inner return type. + + +### Curry-implied result modes + +Closing over an argument constrains the partial-application closure across several axes, not just locality. When the result mode is the one currying implies from the argument, it is suppressed (as the compiler does). + +```ocaml +val curry_once : (int -> int) -> int -> int +``` +`once` argument: the implied `once` result mode is suppressed. + +```ocaml +val curry_portable : (int -> int) -> int -> int +``` +`portable` argument: the implied result mode is suppressed. + +```ocaml +val curry_contended : (int -> int) -> int -> int +``` +`contended` argument: the implied result mode is suppressed. + + +### Result modes that are kept + +A result mode is only suppressed when it is exactly the one currying implies. An explicit mode on a different axis is kept (and the arrow result is parenthesized). + +```ocaml +val keep_portable : int -> int -> int +``` +`portable` on the result is not implied by a `local` argument, so it is kept. + +```ocaml +val keep_once : int -> int -> int +``` +`once` on the result is not implied by a `local` argument, so it is kept. + +```ocaml +val keep_over_once : (int -> int) -> int -> int +``` +The curry-implied `once` is suppressed, but the explicit `portable` is kept. + +```ocaml +val keep_over_local : (int -> int) -> int -> int +``` +The curry-implied `local` is suppressed, but the explicit `portable` is kept. + +```ocaml +val keep_portable_over_nonportable : (int -> int) -> int -> int +``` +The `nonportable` argument mode is the default and dropped, while the explicit `portable` result, not implied by currying, is kept. + + +### All mode axes + +```ocaml +val mode_global : int -> unit +``` +Locality mode (legacy, not rendered). + +```ocaml +val mode_local : int -> unit +``` +Locality mode. + +```ocaml +val mode_aliased : int -> unit +``` +Uniqueness mode (legacy, not rendered). + +```ocaml +val mode_unique : int -> unit +``` +Uniqueness mode. + +```ocaml +val mode_many : int -> unit +``` +Linearity mode (legacy, not rendered). + +```ocaml +val mode_once : int -> unit +``` +Linearity mode. + +```ocaml +val mode_portable : int -> unit +``` +Portability mode. + +```ocaml +val mode_shareable : int -> unit +``` +Portability mode (intermediate value). + +```ocaml +val mode_nonportable : int -> unit +``` +Portability mode (legacy, not rendered). + +```ocaml +val mode_uncontended : int -> unit +``` +Contention mode (legacy, not rendered). + +```ocaml +val mode_shared : int -> unit +``` +Contention mode. + +```ocaml +val mode_contended : int -> unit +``` +Contention mode. + +```ocaml +val mode_yielding : int -> unit +``` +Yield mode. + +```ocaml +val mode_unyielding : int -> unit +``` +Yield mode (legacy, not rendered). + +```ocaml +val mode_forkable : int -> unit +``` +Fork mode (identity on a non-`local` argument, not rendered). + +```ocaml +val mode_local_forkable : int -> unit +``` +Fork mode, rendered because the argument is also `local`. + +```ocaml +val mode_unforkable : int -> unit +``` +Fork mode. + +```ocaml +val mode_local_unforkable : int -> unit +``` +Fork mode (identity for a `local` argument, not rendered). + +```ocaml +val mode_stateless : int -> unit +``` +Statefulness mode. + +```ocaml +val mode_observing : int -> unit +``` +Statefulness mode. + +```ocaml +val mode_stateful : int -> unit +``` +Statefulness mode (identity when `portability` is at its default, not rendered). + +```ocaml +val mode_immutable : int -> unit +``` +Visibility mode. + +```ocaml +val mode_read : int -> unit +``` +Visibility mode. + +```ocaml +val mode_read_write : int -> unit +``` +Visibility mode (legacy, not rendered). + +```ocaml +val mode_static : int -> unit +``` +Staticity mode. + +```ocaml +val mode_dynamic : int -> unit +``` +Staticity mode (legacy, not rendered). + + +### Cross-axis suppression + +Some axes have a default value that is implied by another axis; the implied value is suppressed when rendering. + +```ocaml +val mode_local_yielding : int -> unit +``` +`yielding` is the default for `local`, so it is not rendered. + +```ocaml +val mode_local_unyielding : int -> unit +``` +`unyielding` is non-default for `local`, so it is rendered. + +```ocaml +val mode_immutable_contended : int -> unit +``` +`contended` is the default for `immutable`, so it is not rendered. + +```ocaml +val mode_immutable_uncontended : int -> unit +``` +`uncontended` is non-default for `immutable`, so it is rendered. + +```ocaml +val mode_stateless_portable : int -> unit +``` +`portable` is the default for `stateless`, so it is not rendered. + +```ocaml +val mode_stateful_portable : int -> unit +``` +`portable` is non-default for `stateful`, so it is rendered. + + +### Modes in type definitions + +```ocaml +type mode_alias = int -> int +``` +Type alias for an arrow with a mode on its argument. + +```ocaml +type mode_record = { + fn : int -> int; (* Record field whose type is an arrow with a mode. *) + fn_both : int -> int; (* Arrow field with modes on both sides. *) + mutable mfn : int -> int; (* Mutable arrow field with a mode. *) +} +``` +```ocaml +type mode_cstr = + | Mc_arrow of int -> int (* Constructor argument is a parenthesized arrow with a mode. *) + | Mc_nested of (int -> int) -> unit (* Nested arrow: higher-order with a mode on the inner argument. *) + | Mc_gadt : ('a -> 'a) -> mode_cstr (* GADT constructor *) +``` \ No newline at end of file diff --git a/test/generators/markdown/Oxcaml_impl.md b/test/generators/markdown/Oxcaml_impl.md index f903a30efd..2363ac1fc0 100644 --- a/test/generators/markdown/Oxcaml_impl.md +++ b/test/generators/markdown/Oxcaml_impl.md @@ -9,4 +9,64 @@ module To_be_included : sig ... end ``` ```ocaml module Including : sig ... end -``` \ No newline at end of file +``` +```ocaml +type opaque +``` + +## Modalities + + +### Modalities on record fields + +```ocaml +type modalities_record = { + f_global : opaque @@ global; (* Locality modality. *) + f_portable : opaque @@ portable; (* Portability modality. *) + f_multi : opaque @@ global portable; (* Multiple modalities. *) + f_plain : opaque; (* No modality, for reference. *) +} +``` + +### Modalities on constructor arguments + +```ocaml +type modalities_variant = + | A of string @@ global (* Constructor argument with global modality. *) + | B of int -> int @@ portable (* Function constructor argument with modality. *) + | C of int @@ portable * string @@ global (* Per-element modalities in a constructor tuple. *) +``` + +## Modes + + +### Modes in type definitions + +```ocaml +type mode_alias = int -> int +``` +Type alias for an arrow with a mode on its argument. + +```ocaml +type mode_record = { + fn : int -> int; (* Field whose type is an arrow with a mode. *) + fn_both : int -> int; (* Modes on both sides. *) +} +``` +```ocaml +type mode_cstr = + | Mc_arrow of int -> int (* Constructor argument is a parenthesized arrow with a mode. *) + | Mc_nested of (int -> int) -> unit (* Nested arrow: higher-order with a mode on the inner argument. *) +``` + +### Modes on values + +```ocaml +val mode_arg : int -> int +``` +Mode on a function argument, via a type annotation. + +```ocaml +val mode_multi : string -> string +``` +Multiple modes on argument and return. From 9a5923385e0889277f0bb010f86732fc35a53eb1 Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Wed, 1 Jul 2026 13:07:24 +0200 Subject: [PATCH 2/9] OxCaml: Support for modes --- CHANGES.md | 1 + sherlodoc/index/load_doc.ml | 9 +- sherlodoc/index/type_cache.ml | 3 +- src/document/generator.ml | 52 +++---- src/loader/cmi.ml | 93 ++++++++++- src/loader/cmi.mli | 11 ++ src/loader/cmt.ml | 2 +- src/loader/cmti.ml | 10 +- src/model/lang.ml | 7 +- src/model_desc/lang_desc.ml | 5 +- src/xref2/compile.ml | 20 ++- src/xref2/component.ml | 14 +- src/xref2/component.mli | 5 +- src/xref2/expand_tools.ml | 3 +- src/xref2/lang_of.ml | 4 +- src/xref2/link.ml | 8 +- src/xref2/subst.ml | 7 +- .../html/Oxcaml-module-type-Mode_sig.html | 66 ++++++++ test/generators/html/Oxcaml.html | 144 +++++++++++------- test/generators/html/Oxcaml_impl.html | 25 ++- test/generators/latex/Oxcaml.tex | 90 +++++------ test/generators/latex/Oxcaml_impl.tex | 14 +- test/generators/man/Oxcaml.3o | 90 +++++------ test/generators/man/Oxcaml_impl.3o | 14 +- .../markdown/Oxcaml-module-type-Mode_sig.md | 24 +++ test/generators/markdown/Oxcaml.md | 90 +++++------ test/generators/markdown/Oxcaml_impl.md | 14 +- test/xref2/classes.t/run.t | 66 ++++---- test/xref2/github_issue_1001.t/run.t | 67 ++++---- test/xref2/github_issue_930.t/run.t | 4 +- 30 files changed, 623 insertions(+), 339 deletions(-) create mode 100644 test/generators/html/Oxcaml-module-type-Mode_sig.html create mode 100644 test/generators/markdown/Oxcaml-module-type-Mode_sig.md diff --git a/CHANGES.md b/CHANGES.md index 97420a6389..cafd075db0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ - Support for OxCaml zero alloc definitions (@Leonidas-from-XIV, #1422, #1444) - Support for OxCaml modalities (@art-w, #1420) - Support OxCaml 5.2.0minus39 (@jonludlam, #1469) +- Support for OxCaml modes (@art-w, #1454) ### Fixed - Remove requirement for ppx_expect in tests (@jonludlam, #1445) diff --git a/sherlodoc/index/load_doc.ml b/sherlodoc/index/load_doc.ml index cf417947c7..af2a483889 100644 --- a/sherlodoc/index/load_doc.ml +++ b/sherlodoc/index/load_doc.ml @@ -82,8 +82,9 @@ let searchable_type_of_constructor args res = | TypeDecl.Constructor.Tuple args -> begin match args with | _ :: _ :: _ -> - TypeExpr.Arrow (None, Tuple (List.map (fun (x, _mods) -> None, x) args), res) - | [ (arg, _) ] -> TypeExpr.Arrow (None, arg, res) + TypeExpr.Arrow + (None, (Tuple (List.map (fun (x, _mods) -> None, x) args), []), (res, [])) + | [ (arg, _) ] -> TypeExpr.Arrow (None, (arg, []), (res, [])) | _ -> res end | TypeDecl.Constructor.Record fields -> @@ -91,12 +92,12 @@ let searchable_type_of_constructor args res = (fun res field -> let open TypeDecl.Field in let field_name = Odoc_model.Paths.Identifier.name field.id in - TypeExpr.Arrow (Some (Label field_name), field.type_, res)) + TypeExpr.Arrow (Some (Label field_name), (field.type_, []), (res, []))) res fields let searchable_type_of_record parent_type type_ = - Odoc_model.Lang.TypeExpr.Arrow (None, parent_type, type_) + Odoc_model.Lang.TypeExpr.Arrow (None, (parent_type, []), (type_, [])) let convert_kind ~db (Odoc_index.Entry.{ kind; _ } as entry) = match kind with diff --git a/sherlodoc/index/type_cache.ml b/sherlodoc/index/type_cache.ml index 42d9ed6c94..5a8843bb2c 100644 --- a/sherlodoc/index/type_cache.ml +++ b/sherlodoc/index/type_cache.ml @@ -16,7 +16,8 @@ let rec of_odoc ~cache otyp = match otyp with | Odoc_model.Lang.TypeExpr.Var _str -> Any | Any -> Any - | Arrow (_lbl, left, right) -> cache (Arrow (of_odoc ~cache left, of_odoc ~cache right)) + | Arrow (_lbl, (left, _), (right, _)) -> + cache (Arrow (of_odoc ~cache left, of_odoc ~cache right)) | Constr (name, args) -> cache (Constr (Typename.to_string name, List.map (of_odoc ~cache) args)) | Tuple li -> cache (Tuple (List.map (fun (_, ty) -> of_odoc ~cache ty) li)) diff --git a/src/document/generator.ml b/src/document/generator.ml index 0133714b0f..f8efd42ef8 100644 --- a/src/document/generator.ml +++ b/src/document/generator.ml @@ -325,6 +325,11 @@ module Make (Syntax : SYNTAX) = struct val with_kind_annotation : Odoc_model.Lang.Kind.t -> text -> text end = struct + let format_modes (modes : Odoc_model.Lang.Modes.t) = + match modes with + | [] -> O.noop + | ms -> O.txt " @ " ++ O.txt (String.concat ~sep:" " ms) + let rec te_variant (t : Odoc_model.Lang.TypeExpr.Polymorphic_variant.t) = let style_arguments ~constant arguments = (* Multiple arguments in a polymorphic variant constructor correspond @@ -494,35 +499,26 @@ module Make (Syntax : SYNTAX) = struct enclose_parens_if_needed (type_expr ~needs_parentheses:true te ++ O.txt " " ++ O.keyword "as" ++ O.txt " '" ++ O.txt alias) - | Arrow (None, src, dst) -> - let res = - O.span - ((O.box_hv @@ type_expr ~needs_parentheses:true src) - ++ O.txt " " ++ Syntax.Type.arrow) - ++ O.sp ++ type_expr dst - (* ++ O.end_hv *) - in - enclose_parens_if_needed res - | Arrow (Some (RawOptional _ as lbl), _src, dst) -> - let res = - O.span - (O.box_hv - @@ label lbl ++ O.txt ":" - ++ tag "error" (O.txt "???") - ++ O.txt " " ++ Syntax.Type.arrow) - ++ O.sp ++ type_expr dst + | Arrow (lbl, (src, src_modes), (dst, dst_modes)) -> + let src = + (O.box_hv @@ type_expr ~needs_parentheses:true src) + ++ format_modes src_modes in - enclose_parens_if_needed res - | Arrow (Some lbl, src, dst) -> - let res = - O.span - ((O.box_hv - @@ label lbl ++ O.txt ":" ++ O.cut - ++ (O.box_hv @@ type_expr ~needs_parentheses:true src)) - ++ O.txt " " ++ Syntax.Type.arrow) - ++ O.sp ++ type_expr dst + let labelized_src = + match lbl with + | None -> src + | Some (RawOptional _ as lbl) -> + O.box_hv + @@ label lbl ++ O.txt ":" + ++ tag "error" (O.txt "???") + ++ format_modes src_modes + | Some lbl -> O.box_hv @@ (label lbl ++ O.txt ":" ++ O.cut ++ src) in - enclose_parens_if_needed res + enclose_parens_if_needed + (O.span (labelized_src ++ O.txt " " ++ Syntax.Type.arrow) + ++ O.sp + ++ type_expr ~needs_parentheses:(dst_modes <> []) dst + ++ format_modes dst_modes) | Tuple lst -> tuple ~needs_parentheses ~boxed:true lst | Unboxed_tuple lst -> tuple ~needs_parentheses ~boxed:false lst | Constr (path, args) -> @@ -1053,7 +1049,7 @@ module Make (Syntax : SYNTAX) = struct val value : Lang.Value.t -> Item.t end = struct let rec arity_of_type_expr = function - | Lang.TypeExpr.Arrow (_lbl, _arg, curried) -> + | Lang.TypeExpr.Arrow (_lbl, _arg, (curried, _modes)) -> 1 + arity_of_type_expr curried | _ -> 0 diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index 756ee7ef63..2407b4e05c 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -549,6 +549,84 @@ let read_label_modalities ld = let read_constructor_argument arg = arg.ca_type, read_modalities Immutable arg.ca_modalities +let tree_of_modes (modes : Mode.Alloc.Const.t) : string list = + (* Same as the OxCaml's [Printtyp.tree_of_modes]: axes whose value is legacy + or is implied by another axis are suppressed. *) + let forkable = + match modes.areality, modes.forkable with + | Local, Unforkable | Global, Forkable -> None + | _, _ -> Some modes.forkable + in + let yielding = + match modes.areality, modes.yielding with + | Local, Yielding | Global, Unyielding -> None + | _, _ -> Some modes.yielding + in + let contention = + match modes.visibility, modes.contention with + | Immutable, Contended + | Read, Shared + | Read_write, Uncontended -> None + | _, _ -> Some modes.contention + in + let portability = + match modes.statefulness, modes.portability with + | Stateless, Portable + | Observing, Shareable + | Stateful, Nonportable -> None + | _, _ -> Some modes.portability + in + let diff = Mode.Alloc.Const.diff modes Mode.Alloc.Const.legacy in + let diff = { diff with forkable; yielding; contention; portability } in + let print_opt print a = Option.map (Format_doc.asprintf "%a" print) a in + List.filter_map (fun x -> x) + [ print_opt Mode.Locality.Const.print diff.areality + ; print_opt Mode.Uniqueness.Const.print diff.uniqueness + ; print_opt Mode.Linearity.Const.print diff.linearity + ; print_opt Mode.Portability.Const.print diff.portability + ; print_opt Mode.Contention.Const.print diff.contention + ; print_opt Mode.Forkable.Const.print diff.forkable + ; print_opt Mode.Yielding.Const.print diff.yielding + ; print_opt Mode.Statefulness.Const.print diff.statefulness + ; print_opt Mode.Visibility.Const.print diff.visibility + ; print_opt Mode.Staticity.Const.print diff.staticity ] + +let read_alloc_modes m = tree_of_modes (Mode.Alloc.zap_to_legacy m) + +type modes = Mode.Alloc.Const.t + +let legacy_modes = Mode.Alloc.Const.legacy + +let curried_acc modes arg_mode = + Ctype.curry_mode modes (Mode.Alloc.zap_to_legacy arg_mode) + +let mode_is_implied modes res_mode = + let snap = Btype.snapshot () in + let implied = + match Mode.Alloc.equate (Mode.Alloc.of_const modes) res_mode with + | Ok () -> true + | Error _ -> false + in + Btype.backtrack snap; + implied + +let read_arrow_modes modes typ = + match Compat.get_desc typ with + | Tarrow ((_, arg_mode, res_mode), _, res, _) -> + let arg_modes = read_alloc_modes arg_mode in + let modes = curried_acc modes arg_mode in + let res_is_arrow = + match Compat.get_desc res with + | Tarrow _ -> not (is_aliased (proxy res)) + | _ -> false + in + let res_modes = + if res_is_arrow && mode_is_implied modes res_mode then [] + else read_alloc_modes res_mode + in + (arg_modes, res_modes, modes) + | _ -> ([], [], modes) + #else let jkind_of_type_desc _te = Kind.Default @@ -556,9 +634,17 @@ let read_value_descr_modalities _vd = [] let read_label_modalities _ld = [] let read_constructor_argument arg = arg, [] +type modes = unit + +let legacy_modes : modes = () + +let read_arrow_modes (modes : modes) _typ = ([], [], modes) + #endif -let rec read_type_expr env typ = +let rec read_type_expr env typ = read_type_expr_modal env legacy_modes typ + +and read_type_expr_modal env modes typ = let open TypeExpr in let px = proxy typ in if used_alias px then Var (name_of_type typ) @@ -593,8 +679,9 @@ let rec read_type_expr env typ = | _ -> lbl, read_type_expr env arg in - let res = read_type_expr env res in - Arrow(lbl, arg, res) + let arg_modes, res_modes, modes = read_arrow_modes modes typ in + let res = read_type_expr_modal env modes res in + Arrow(lbl, (arg, arg_modes), (res, res_modes)) | Ttuple typs -> #if OCAML_VERSION >= (5,4,0) || defined OXCAML let typs = List.map (fun (lbl,x) -> lbl, read_type_expr env x) typs in diff --git a/src/loader/cmi.mli b/src/loader/cmi.mli index 76b5b5671b..a19f595fc1 100644 --- a/src/loader/cmi.mli +++ b/src/loader/cmi.mli @@ -108,8 +108,19 @@ val read_modalities : val read_value_modalities : Mode.Modality.t -> Odoc_model.Lang.Modalities.t + +val tree_of_modes : Mode.Alloc.Const.t -> Odoc_model.Lang.Modes.t #endif +type modes + +val legacy_modes : modes + +val read_arrow_modes : + modes -> + Types.type_expr -> + Odoc_model.Lang.Modes.t * Odoc_model.Lang.Modes.t * modes + val read_value_descr_modalities : Types.value_description -> Odoc_model.Lang.Modalities.t diff --git a/src/loader/cmt.ml b/src/loader/cmt.ml index 3681016038..f2f48a4f42 100644 --- a/src/loader/cmt.ml +++ b/src/loader/cmt.ml @@ -292,7 +292,7 @@ let rec read_class_field env parent cf = must keep only the type after the first arrow. *) let type_ = match Cmi.read_type_expr env expr.exp_type with - | Arrow (_, _, t) -> t + | Arrow (_, _, (t, _)) -> t | t -> t in false, type_ diff --git a/src/loader/cmti.ml b/src/loader/cmti.ml index 236478fa7e..fba321a21e 100644 --- a/src/loader/cmti.ml +++ b/src/loader/cmti.ml @@ -41,6 +41,9 @@ let opt_map f = function let read_label = Cmi.read_label let rec read_core_type env container ctyp = + read_core_type_modal env Cmi.legacy_modes container ctyp + +and read_core_type_modal env modes container ctyp = let open TypeExpr in match ctyp.ctyp_desc with #if defined OXCAML @@ -59,8 +62,11 @@ let rec read_core_type env container ctyp = #endif let lbl = read_label lbl in let arg = read_core_type env container arg in - let res = read_core_type env container res in - Arrow(lbl, arg, res) + let arg_modes, res_modes, modes = + Cmi.read_arrow_modes modes ctyp.ctyp_type + in + let res = read_core_type_modal env modes container res in + Arrow(lbl, (arg, arg_modes), (res, res_modes)) | Ttyp_tuple typs -> #if OCAML_VERSION >= (5,4,0) || defined OXCAML let typs = List.map (fun (lbl,x) -> lbl, read_core_type env container x) typs in diff --git a/src/model/lang.ml b/src/model/lang.ml index 4fe5b890ae..5136077c2b 100644 --- a/src/model/lang.ml +++ b/src/model/lang.ml @@ -217,6 +217,11 @@ and Modalities : sig end = Modalities +and Modes : sig + type t = string list +end = + Modes + and TypeDecl : sig module Field : sig type t = { @@ -496,7 +501,7 @@ and TypeExpr : sig | Var of string | Any | Alias of t * string - | Arrow of label option * t * t + | Arrow of label option * (t * Modes.t) * (t * Modes.t) | Tuple of (string option * t) list | Unboxed_tuple of (string option * t) list | Constr of Path.Type.t * t list diff --git a/src/model_desc/lang_desc.ml b/src/model_desc/lang_desc.ml index 75e9bcf7e3..f09fad15bb 100644 --- a/src/model_desc/lang_desc.ml +++ b/src/model_desc/lang_desc.ml @@ -683,7 +683,10 @@ and typeexpr_t = C ( "Arrow", (x1, x2, x3), - Triple (Option typeexpr_label, typeexpr_t, typeexpr_t) ) + Triple + ( Option typeexpr_label, + Pair (typeexpr_t, List string), + Pair (typeexpr_t, List string) ) ) | Tuple x -> C ("Tuple", x, List (Pair (Option string, typeexpr_t))) | Unboxed_tuple x -> C ("Unboxed_tuple", x, List (Pair (Option string, typeexpr_t))) diff --git a/src/xref2/compile.ml b/src/xref2/compile.ml index a6dd9a101d..97401801f9 100644 --- a/src/xref2/compile.ml +++ b/src/xref2/compile.ml @@ -887,14 +887,14 @@ and handle_arrow : Env.t -> Id.Id.label_parent -> TypeExpr.label option -> - TypeExpr.t -> - TypeExpr.t -> + TypeExpr.t * Modes.t -> + TypeExpr.t * Modes.t -> TypeExpr.t = - fun env parent lbl t1 t2 -> - let t2' = type_expression env parent t2 in + fun env parent lbl (t1, m1) (t2, m2) -> + let t2' = (type_expression env parent t2, m2) in match lbl with | Some (Optional _ | Label _) | None -> - Arrow (lbl, type_expression env parent t1, t2') + Arrow (lbl, (type_expression env parent t1, m1), t2') | Some (RawOptional s) -> ( (* s is definitely an option type, but not _obviously_ so. *) match Component.Of_Lang.(type_expression (empty ()) t1) with @@ -916,10 +916,14 @@ and handle_arrow : in match find_option p with | Some t1 -> - Arrow (Some (Optional s), type_expression env parent t1, t2') + Arrow (Some (Optional s), (type_expression env parent t1, m1), t2') | None -> - Arrow (Some (RawOptional s), type_expression env parent t1, t2')) - | _ -> Arrow (Some (RawOptional s), type_expression env parent t1, t2')) + Arrow + (Some (RawOptional s), (type_expression env parent t1, m1), t2') + ) + | _ -> + Arrow (Some (RawOptional s), (type_expression env parent t1, m1), t2') + ) and type_expression : Env.t -> Id.LabelParent.t -> _ -> _ = fun env parent texpr -> diff --git a/src/xref2/component.ml b/src/xref2/component.ml index be23a7b3ea..f132b56729 100644 --- a/src/xref2/component.ml +++ b/src/xref2/component.ml @@ -125,7 +125,10 @@ and TypeExpr : sig | Var of string | Any | Alias of t * string - | Arrow of label option * t * t + | Arrow of + label option + * (t * Odoc_model.Lang.Modes.t) + * (t * Odoc_model.Lang.Modes.t) | Tuple of (string option * t) list | Unboxed_tuple of (string option * t) list | Constr of Cpath.type_ * t list @@ -1201,7 +1204,7 @@ module Fmt = struct | Var x -> Format.fprintf ppf "%s" x | Any -> Format.fprintf ppf "_" | Alias (x, y) -> Format.fprintf ppf "(alias %a %s)" (type_expr c) x y - | Arrow (l, t1, t2) -> + | Arrow (l, (t1, _), (t2, _)) -> Format.fprintf ppf "%a(%a) -> %a" type_expr_label l (type_expr c) t1 (type_expr c) t2 | Tuple ts -> Format.fprintf ppf "(%a)" (type_labeled_tuple c) ts @@ -2362,8 +2365,11 @@ module Of_Lang = struct | Any -> Any | Constr (p, xs) -> Constr (type_path ident_map p, List.map (type_expression ident_map) xs) - | Arrow (lbl, t1, t2) -> - Arrow (lbl, type_expression ident_map t1, type_expression ident_map t2) + | Arrow (lbl, (t1, m1), (t2, m2)) -> + Arrow + ( lbl, + (type_expression ident_map t1, m1), + (type_expression ident_map t2, m2) ) | Tuple ts -> Tuple (List.map (fun (lbl, ty) -> (lbl, type_expression ident_map ty)) ts) diff --git a/src/xref2/component.mli b/src/xref2/component.mli index abda54e140..d9e25394ff 100644 --- a/src/xref2/component.mli +++ b/src/xref2/component.mli @@ -120,7 +120,10 @@ and TypeExpr : sig | Var of string | Any | Alias of t * string - | Arrow of label option * t * t + | Arrow of + label option + * (t * Odoc_model.Lang.Modes.t) + * (t * Odoc_model.Lang.Modes.t) | Tuple of (string option * t) list | Unboxed_tuple of (string option * t) list | Constr of Cpath.type_ * t list diff --git a/src/xref2/expand_tools.ml b/src/xref2/expand_tools.ml index 6ec6930ad4..0688fb5045 100644 --- a/src/xref2/expand_tools.ml +++ b/src/xref2/expand_tools.ml @@ -57,7 +57,8 @@ let rec type_expr map t = | Any -> Any | Alias (t, s) -> if List.mem_assoc s map then raise Clash else Alias (type_expr map t, s) - | Arrow (l, t1, t2) -> Arrow (l, type_expr map t1, type_expr map t2) + | Arrow (l, (t1, m1), (t2, m2)) -> + Arrow (l, (type_expr map t1, m1), (type_expr map t2, m2)) | Tuple ts -> Tuple (List.map (fun (l, ty) -> (l, type_expr map ty)) ts) | Unboxed_tuple ts -> Unboxed_tuple (List.map (fun (l, t) -> (l, type_expr map t)) ts) diff --git a/src/xref2/lang_of.ml b/src/xref2/lang_of.ml index 5c49cb96c9..796bad42e3 100644 --- a/src/xref2/lang_of.ml +++ b/src/xref2/lang_of.ml @@ -1039,8 +1039,8 @@ and type_expr map (parent : Identifier.LabelParent.t) (t : Component.TypeExpr.t) | Var s -> Var s | Any -> Any | Alias (t, str) -> Alias (type_expr map parent t, str) - | Arrow (lbl, t1, t2) -> - Arrow (lbl, type_expr map parent t1, type_expr map parent t2) + | Arrow (lbl, (t1, m1), (t2, m2)) -> + Arrow (lbl, (type_expr map parent t1, m1), (type_expr map parent t2, m2)) | Tuple ts -> Tuple (List.map (fun (lbl, ty) -> (lbl, type_expr map parent ty)) ts) | Unboxed_tuple ts -> diff --git a/src/xref2/link.ml b/src/xref2/link.ml index bd332ee691..2620a49065 100644 --- a/src/xref2/link.ml +++ b/src/xref2/link.ml @@ -442,7 +442,7 @@ let warn_on_hidden_representation (id : Id.Type.t) is_hidden (p :> Paths.Path.t) || List.exists (fun t -> internal_typ_exp t) ts | Poly (_, t) | Alias (t, _) -> internal_typ_exp t - | Arrow (_, t, t2) -> internal_typ_exp t || internal_typ_exp t2 + | Arrow (_, (t, _), (t2, _)) -> internal_typ_exp t || internal_typ_exp t2 | Tuple ts -> List.exists (fun (_, t) -> internal_typ_exp t) ts | Class (_, ts) -> List.exists (fun t -> internal_typ_exp t) ts | _ -> false @@ -1141,11 +1141,11 @@ and type_expression : Env.t -> Id.Signature.t -> _ -> _ = match texpr with | Var _ | Any -> texpr | Alias (t, str) -> Alias (type_expression env parent visited t, str) - | Arrow (lbl, t1, t2) -> + | Arrow (lbl, (t1, m1), (t2, m2)) -> Arrow ( lbl, - type_expression env parent visited t1, - type_expression env parent visited t2 ) + (type_expression env parent visited t1, m1), + (type_expression env parent visited t2, m2) ) | Tuple ts -> Tuple (List.map diff --git a/src/xref2/subst.ml b/src/xref2/subst.ml index 49bbf0205e..5a90ef98cb 100644 --- a/src/xref2/subst.ml +++ b/src/xref2/subst.ml @@ -164,8 +164,8 @@ let rec substitute_vars vars t = | Var s -> ( try List.assoc s vars with Not_found -> t) | Any -> Any | Alias (t, str) -> Alias (substitute_vars vars t, str) - | Arrow (lbl, t1, t2) -> - Arrow (lbl, substitute_vars vars t1, substitute_vars vars t2) + | Arrow (lbl, (t1, m1), (t2, m2)) -> + Arrow (lbl, (substitute_vars vars t1, m1), (substitute_vars vars t2, m2)) | Tuple ts -> Tuple (List.map (fun (lbl, ty) -> (lbl, substitute_vars vars ty)) ts) | Unboxed_tuple ts -> @@ -609,7 +609,8 @@ and type_expr s t = | Var s -> Var s | Any -> Any | Alias (t, str) -> Alias (type_expr s t, str) - | Arrow (lbl, t1, t2) -> Arrow (lbl, type_expr s t1, type_expr s t2) + | Arrow (lbl, (t1, m1), (t2, m2)) -> + Arrow (lbl, (type_expr s t1, m1), (type_expr s t2, m2)) | Tuple ts -> Tuple (List.map (fun (lbl, ty) -> (lbl, type_expr s ty)) ts) | Unboxed_tuple ts -> Unboxed_tuple (List.map (fun (l, t) -> (l, type_expr s t)) ts) diff --git a/test/generators/html/Oxcaml-module-type-Mode_sig.html b/test/generators/html/Oxcaml-module-type-Mode_sig.html new file mode 100644 index 0000000000..cfc273754a --- /dev/null +++ b/test/generators/html/Oxcaml-module-type-Mode_sig.html @@ -0,0 +1,66 @@ + + + Mode_sig (Oxcaml.Mode_sig) + + + + + + + + +
    +

    Module type Oxcaml.Mode_sig

    +

    Module type containing declarations with modes.

    +
    +
    +
    +
    + + + val arg : + int @ local -> + int + + +

    Mode on a function argument.

    +
    +
    +
    + + + val ret : + int -> int @ local + + +

    Mode on a function return.

    +
    +
    +
    + + + val multi : + string @ local once -> + string @ local unique + + +
    +

    Multiple modes on argument and return.

    +
    +
    +
    + + type alias + = int @ local -> + int + + +
    +

    Type alias for an arrow with a mode.

    +
    +
    + + diff --git a/test/generators/html/Oxcaml.html b/test/generators/html/Oxcaml.html index f13c2106e8..304862f666 100644 --- a/test/generators/html/Oxcaml.html +++ b/test/generators/html/Oxcaml.html @@ -1200,7 +1200,8 @@

    val mode_arg : - int -> int + int @ local -> + int

    Mode on a function argument.

    @@ -1210,7 +1211,7 @@

    val mode_ret : - int -> int + int -> int @ local

    Mode on a function return.

    @@ -1220,7 +1221,8 @@

    val mode_both : - int -> int + int @ local -> + int @ local @@ -1231,7 +1233,8 @@

    val mode_multi : - string -> string + string @ local once -> + string @ local unique @@ -1242,7 +1245,7 @@

    val mode_labeled : - x:int + x:int @ local -> int @@ -1254,7 +1257,7 @@

    val mode_optional : - ?x:int + ?x:int @ local -> unit -> int @@ -1272,7 +1275,7 @@

    'a -> 'b) - -> + @ local -> 'a -> @@ -1289,7 +1292,8 @@

    val mode_arrow_result : int -> - int -> int + (int -> int) + @ local @@ -1316,7 +1320,7 @@

    val curry_once : (int -> int) - -> + @ once -> int -> int @@ -1335,7 +1339,7 @@

    val curry_portable : (int -> int) - -> + @ portable -> int -> int @@ -1354,7 +1358,7 @@

    val curry_contended : (int -> int) - -> + @ contended -> int -> int @@ -1379,8 +1383,9 @@

    val keep_portable : - int -> - int -> int + int @ local -> + (int -> int) + @ portable @@ -1395,8 +1400,9 @@

    val keep_once : - int -> - int -> int + int @ local -> + (int -> int) + @ once @@ -1413,9 +1419,10 @@

    val keep_over_once : (int -> int) - -> - int -> - int + @ once -> + + (int -> int) + @ portable @@ -1432,9 +1439,10 @@

    val keep_over_local : (int -> int) - -> - int -> - int + @ local -> + + (int -> int) + @ portable @@ -1453,8 +1461,9 @@

    (int -> int) -> - int -> - int + + (int -> int) + @ portable @@ -1484,7 +1493,8 @@

    val mode_local : - int -> unit + int @ local -> + unit

    Locality mode.

    @@ -1506,7 +1516,8 @@

    val mode_unique : - int -> unit + int @ unique -> + unit

    Uniqueness mode.

    @@ -1527,7 +1538,7 @@

    val mode_once : - int -> unit + int @ once -> unit

    Linearity mode.

    @@ -1537,7 +1548,8 @@

    val mode_portable : - int -> unit + int @ portable -> + unit

    Portability mode.

    @@ -1547,7 +1559,8 @@

    val mode_shareable : - int -> unit + int @ shareable -> + unit @@ -1582,7 +1595,8 @@

    val mode_shared : - int -> unit + int @ shared -> + unit

    Contention mode.

    @@ -1592,7 +1606,8 @@

    val mode_contended : - int -> unit + int @ contended -> + unit

    Contention mode.

    @@ -1602,7 +1617,8 @@

    val mode_yielding : - int -> unit + int @ yielding -> + unit

    Yield mode.

    @@ -1638,7 +1654,8 @@

    val mode_local_forkable : - int -> unit + int @ local forkable -> + unit @@ -1652,7 +1669,8 @@

    val mode_unforkable : - int -> unit + int @ unforkable -> + unit

    Fork mode.

    @@ -1662,7 +1680,8 @@

    val mode_local_unforkable : - int -> unit + int @ local -> + unit @@ -1676,7 +1695,8 @@

    val mode_stateless : - int -> unit + int @ stateless -> + unit

    Statefulness mode.

    @@ -1686,7 +1706,8 @@

    val mode_observing : - int -> unit + int @ observing -> + unit

    Statefulness mode.

    @@ -1711,7 +1732,8 @@

    val mode_immutable : - int -> unit + int @ immutable -> + unit

    Visibility mode.

    @@ -1721,7 +1743,7 @@

    val mode_read : - int -> unit + int @ read -> unit

    Visibility mode.

    @@ -1743,7 +1765,8 @@

    val mode_static : - int -> unit + int @ static -> + unit

    Staticity mode.

    @@ -1771,7 +1794,8 @@

    val mode_local_yielding : - int -> unit + int @ local -> + unit @@ -1786,7 +1810,8 @@

    val mode_local_unyielding : - int -> unit + int @ local unyielding -> + unit @@ -1801,7 +1826,8 @@

    val mode_immutable_contended - : int -> unit + : int @ immutable -> + unit @@ -1816,7 +1842,9 @@

    val mode_immutable_uncontended - : int -> unit + : + int @ uncontended immutable -> + unit @@ -1831,7 +1859,8 @@

    val mode_stateless_portable : - int -> unit + int @ stateless -> + unit @@ -1846,7 +1875,8 @@

    val mode_stateful_portable : - int -> unit + int @ portable -> + unit @@ -1864,7 +1894,8 @@

    type mode_alias - = int -> int + = int @ local -> + int
    @@ -1882,7 +1913,9 @@

  • - fn : int -> int; + fn : + int @ local -> + int;
    (* @@ -1893,8 +1926,9 @@

  • - fn_both : int -> - int; + fn_both : + int @ local -> + int @ local;
    (* @@ -1906,7 +1940,8 @@

    mutable mfn : - int -> int; + int @ local -> + int;
    (* @@ -1929,7 +1964,8 @@

    | Mc_arrow of - int -> int + int @ local -> + int
    (* @@ -1943,7 +1979,9 @@

    Mc_nested of - (int -> int) + ( + int @ local -> + int) -> unit @@ -1958,7 +1996,7 @@

    | Mc_gadt : ( - 'a + 'a @ once -> 'a) -> diff --git a/test/generators/html/Oxcaml_impl.html b/test/generators/html/Oxcaml_impl.html index 5050a6c387..9fde4ca6d5 100644 --- a/test/generators/html/Oxcaml_impl.html +++ b/test/generators/html/Oxcaml_impl.html @@ -203,7 +203,8 @@

    type mode_alias - = int -> int + = int @ local -> + int
    @@ -221,7 +222,9 @@

  • - fn : int -> int; + fn : + int @ local -> + int;
    (* @@ -232,8 +235,9 @@

  • - fn_both : int -> - int; + fn_both : + int @ local -> + int @ local;
    (* @@ -255,7 +259,8 @@

    | Mc_arrow of - int -> int + int @ local -> + int
    (* @@ -269,7 +274,9 @@

    Mc_nested of - (int -> int) + ( + int @ local -> + int) -> unit @@ -290,7 +297,8 @@

    val mode_arg : - int -> int + int @ local -> + int

    @@ -303,7 +311,8 @@

    val mode_multi : - string -> string + string @ local once -> + string @ local once

    diff --git a/test/generators/latex/Oxcaml.tex b/test/generators/latex/Oxcaml.tex index eb6a4a3c16..f7b5884ac0 100644 --- a/test/generators/latex/Oxcaml.tex +++ b/test/generators/latex/Oxcaml.tex @@ -241,126 +241,126 @@ \subsubsection{Modalities on module declarations\label{Oxcaml--modalities-on-mod \ocamlcodefragment{\ocamltag{keyword}{end}}\begin{ocamlindent}\ocamlinlinecode{contended} modality applied to all definitions in the module, except the ones which have already specified this axis.\end{ocamlindent}% \medbreak \subsection{Modes\label{Oxcaml--modes}}% -\label{Oxcaml--val-mode_arg}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arg : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function argument.\end{ocamlindent}% +\label{Oxcaml--val-mode_arg}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arg : int @ local \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function argument.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_ret}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}ret : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function return.\end{ocamlindent}% +\label{Oxcaml--val-mode_ret}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}ret : int \ocamltag{arrow}{$\rightarrow$} int @ local}\begin{ocamlindent}Mode on a function return.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_both}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}both : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Modes on both argument and return.\end{ocamlindent}% +\label{Oxcaml--val-mode_both}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}both : int @ local \ocamltag{arrow}{$\rightarrow$} int @ local}\begin{ocamlindent}Modes on both argument and return.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_multi}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi : string \ocamltag{arrow}{$\rightarrow$} string}\begin{ocamlindent}Multiple modes on argument and return.\end{ocamlindent}% +\label{Oxcaml--val-mode_multi}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi : string @ local once \ocamltag{arrow}{$\rightarrow$} string @ local unique}\begin{ocamlindent}Multiple modes on argument and return.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_labeled}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}labeled : \ocamltag{label}{x}:int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a labeled argument.\end{ocamlindent}% +\label{Oxcaml--val-mode_labeled}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}labeled : \ocamltag{label}{x}:int @ local \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a labeled argument.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_optional}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}optional : \ocamltag{optlabel}{?x}:int \ocamltag{arrow}{$\rightarrow$} unit \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on an optional argument.\end{ocamlindent}% +\label{Oxcaml--val-mode_optional}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}optional : \ocamltag{optlabel}{?x}:int @ local \ocamltag{arrow}{$\rightarrow$} unit \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on an optional argument.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_higher_order}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}higher\_\allowbreak{}order : (\ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'b}) \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'b}}\begin{ocamlindent}Mode on a higher-order function argument.\end{ocamlindent}% +\label{Oxcaml--val-mode_higher_order}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}higher\_\allowbreak{}order : (\ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'b}) @ local \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'b}}\begin{ocamlindent}Mode on a higher-order function argument.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_arrow_result}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arrow\_\allowbreak{}result : int \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a result that is itself an arrow. The arrow must be parenthesized so the mode does not appear to bind to the inner return type.\end{ocamlindent}% +\label{Oxcaml--val-mode_arrow_result}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arrow\_\allowbreak{}result : int \ocamltag{arrow}{$\rightarrow$} (int \ocamltag{arrow}{$\rightarrow$} int) @ local}\begin{ocamlindent}Mode on a result that is itself an arrow. The arrow must be parenthesized so the mode does not appear to bind to the inner return type.\end{ocamlindent}% \medbreak \subsubsection{Curry-implied result modes\label{Oxcaml--curry-implied-result-modes}}% Closing over an argument constrains the partial-application closure across several axes, not just locality. When the result mode is the one currying implies from the argument, it is suppressed (as the compiler does). -\label{Oxcaml--val-curry_once}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}once : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{once} argument: the implied \ocamlinlinecode{once} result mode is suppressed.\end{ocamlindent}% +\label{Oxcaml--val-curry_once}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}once : (int \ocamltag{arrow}{$\rightarrow$} int) @ once \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{once} argument: the implied \ocamlinlinecode{once} result mode is suppressed.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-curry_portable}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}portable : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{portable} argument: the implied result mode is suppressed.\end{ocamlindent}% +\label{Oxcaml--val-curry_portable}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}portable : (int \ocamltag{arrow}{$\rightarrow$} int) @ portable \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{portable} argument: the implied result mode is suppressed.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-curry_contended}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}contended : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{contended} argument: the implied result mode is suppressed.\end{ocamlindent}% +\label{Oxcaml--val-curry_contended}\ocamlcodefragment{\ocamltag{keyword}{val} curry\_\allowbreak{}contended : (int \ocamltag{arrow}{$\rightarrow$} int) @ contended \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{contended} argument: the implied result mode is suppressed.\end{ocamlindent}% \medbreak \subsubsection{Result modes that are kept\label{Oxcaml--result-modes-that-are-kept}}% A result mode is only suppressed when it is exactly the one currying implies. An explicit mode on a different axis is kept (and the arrow result is parenthesized). -\label{Oxcaml--val-keep_portable}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{portable} on the result is not implied by a \ocamlinlinecode{local} argument, so it is kept.\end{ocamlindent}% +\label{Oxcaml--val-keep_portable}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}portable : int @ local \ocamltag{arrow}{$\rightarrow$} (int \ocamltag{arrow}{$\rightarrow$} int) @ portable}\begin{ocamlindent}\ocamlinlinecode{portable} on the result is not implied by a \ocamlinlinecode{local} argument, so it is kept.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-keep_once}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}once : int \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}\ocamlinlinecode{once} on the result is not implied by a \ocamlinlinecode{local} argument, so it is kept.\end{ocamlindent}% +\label{Oxcaml--val-keep_once}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}once : int @ local \ocamltag{arrow}{$\rightarrow$} (int \ocamltag{arrow}{$\rightarrow$} int) @ once}\begin{ocamlindent}\ocamlinlinecode{once} on the result is not implied by a \ocamlinlinecode{local} argument, so it is kept.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-keep_over_once}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}over\_\allowbreak{}once : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}The curry-implied \ocamlinlinecode{once} is suppressed, but the explicit \ocamlinlinecode{portable} is kept.\end{ocamlindent}% +\label{Oxcaml--val-keep_over_once}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}over\_\allowbreak{}once : (int \ocamltag{arrow}{$\rightarrow$} int) @ once \ocamltag{arrow}{$\rightarrow$} (int \ocamltag{arrow}{$\rightarrow$} int) @ portable}\begin{ocamlindent}The curry-implied \ocamlinlinecode{once} is suppressed, but the explicit \ocamlinlinecode{portable} is kept.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-keep_over_local}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}over\_\allowbreak{}local : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}The curry-implied \ocamlinlinecode{local} is suppressed, but the explicit \ocamlinlinecode{portable} is kept.\end{ocamlindent}% +\label{Oxcaml--val-keep_over_local}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}over\_\allowbreak{}local : (int \ocamltag{arrow}{$\rightarrow$} int) @ local \ocamltag{arrow}{$\rightarrow$} (int \ocamltag{arrow}{$\rightarrow$} int) @ portable}\begin{ocamlindent}The curry-implied \ocamlinlinecode{local} is suppressed, but the explicit \ocamlinlinecode{portable} is kept.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-keep_portable_over_nonportable}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}portable\_\allowbreak{}over\_\allowbreak{}nonportable : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}The \ocamlinlinecode{nonportable} argument mode is the default and dropped, while the explicit \ocamlinlinecode{portable} result, not implied by currying, is kept.\end{ocamlindent}% +\label{Oxcaml--val-keep_portable_over_nonportable}\ocamlcodefragment{\ocamltag{keyword}{val} keep\_\allowbreak{}portable\_\allowbreak{}over\_\allowbreak{}nonportable : (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} (int \ocamltag{arrow}{$\rightarrow$} int) @ portable}\begin{ocamlindent}The \ocamlinlinecode{nonportable} argument mode is the default and dropped, while the explicit \ocamlinlinecode{portable} result, not implied by currying, is kept.\end{ocamlindent}% \medbreak \subsubsection{All mode axes\label{Oxcaml--all-mode-axes}}% \label{Oxcaml--val-mode_global}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}global : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Locality mode (legacy, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_local}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Locality mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_local}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local : int @ local \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Locality mode.\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_aliased}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}aliased : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Uniqueness mode (legacy, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_unique}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unique : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Uniqueness mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_unique}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unique : int @ unique \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Uniqueness mode.\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_many}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}many : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Linearity mode (legacy, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_once}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}once : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Linearity mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_once}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}once : int @ once \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Linearity mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}portable : int @ portable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_shareable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}shareable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode (intermediate value).\end{ocamlindent}% +\label{Oxcaml--val-mode_shareable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}shareable : int @ shareable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode (intermediate value).\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_nonportable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}nonportable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Portability mode (legacy, not rendered).\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_uncontended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}uncontended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode (legacy, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_shared}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}shared : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_shared}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}shared : int @ shared \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_contended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}contended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_contended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}contended : int @ contended \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Contention mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_yielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}yielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Yield mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_yielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}yielding : int @ yielding \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Yield mode.\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_unyielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unyielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Yield mode (legacy, not rendered).\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_forkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}forkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode (identity on a non-\ocamlinlinecode{local} argument, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_local_forkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}forkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode, rendered because the argument is also \ocamlinlinecode{local}.\end{ocamlindent}% +\label{Oxcaml--val-mode_local_forkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}forkable : int @ local forkable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode, rendered because the argument is also \ocamlinlinecode{local}.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_unforkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unforkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_unforkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}unforkable : int @ unforkable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_local_unforkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}unforkable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode (identity for a \ocamlinlinecode{local} argument, not rendered).\end{ocamlindent}% +\label{Oxcaml--val-mode_local_unforkable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}unforkable : int @ local \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Fork mode (identity for a \ocamlinlinecode{local} argument, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_stateless}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateless : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_stateless}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateless : int @ stateless \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_observing}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}observing : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_observing}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}observing : int @ observing \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_stateful}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateful : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode (identity when \ocamlinlinecode{portability} is at its default, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_immutable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_immutable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable : int @ immutable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_read}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}read : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_read}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}read : int @ read \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode.\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_read_write}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}read\_\allowbreak{}write : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode (legacy, not rendered).\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_static}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}static : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Staticity mode.\end{ocamlindent}% +\label{Oxcaml--val-mode_static}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}static : int @ static \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Staticity mode.\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_dynamic}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}dynamic : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Staticity mode (legacy, not rendered).\end{ocamlindent}% \medbreak \subsubsection{Cross-axis suppression\label{Oxcaml--cross-axis-suppression}}% Some axes have a default value that is implied by another axis; the implied value is suppressed when rendering. -\label{Oxcaml--val-mode_local_yielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}yielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{yielding} is the default for \ocamlinlinecode{local}, so it is not rendered.\end{ocamlindent}% +\label{Oxcaml--val-mode_local_yielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}yielding : int @ local \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{yielding} is the default for \ocamlinlinecode{local}, so it is not rendered.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_local_unyielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}unyielding : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{unyielding} is non-default for \ocamlinlinecode{local}, so it is rendered.\end{ocamlindent}% +\label{Oxcaml--val-mode_local_unyielding}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}local\_\allowbreak{}unyielding : int @ local unyielding \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{unyielding} is non-default for \ocamlinlinecode{local}, so it is rendered.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_immutable_contended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable\_\allowbreak{}contended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{contended} is the default for \ocamlinlinecode{immutable}, so it is not rendered.\end{ocamlindent}% +\label{Oxcaml--val-mode_immutable_contended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable\_\allowbreak{}contended : int @ immutable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{contended} is the default for \ocamlinlinecode{immutable}, so it is not rendered.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_immutable_uncontended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable\_\allowbreak{}uncontended : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{uncontended} is non-default for \ocamlinlinecode{immutable}, so it is rendered.\end{ocamlindent}% +\label{Oxcaml--val-mode_immutable_uncontended}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable\_\allowbreak{}uncontended : int @ uncontended immutable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{uncontended} is non-default for \ocamlinlinecode{immutable}, so it is rendered.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_stateless_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateless\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{portable} is the default for \ocamlinlinecode{stateless}, so it is not rendered.\end{ocamlindent}% +\label{Oxcaml--val-mode_stateless_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateless\_\allowbreak{}portable : int @ stateless \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{portable} is the default for \ocamlinlinecode{stateless}, so it is not rendered.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_stateful_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateful\_\allowbreak{}portable : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{portable} is non-default for \ocamlinlinecode{stateful}, so it is rendered.\end{ocamlindent}% +\label{Oxcaml--val-mode_stateful_portable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateful\_\allowbreak{}portable : int @ portable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}\ocamlinlinecode{portable} is non-default for \ocamlinlinecode{stateful}, so it is rendered.\end{ocamlindent}% \medbreak \subsubsection{Modes in type definitions\label{Oxcaml--modes-in-type-definitions}}% -\label{Oxcaml--type-mode_alias}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}alias = int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Type alias for an arrow with a mode on its argument.\end{ocamlindent}% +\label{Oxcaml--type-mode_alias}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}alias = int @ local \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Type alias for an arrow with a mode on its argument.\end{ocamlindent}% \medbreak \label{Oxcaml--type-mode_record}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}record = \{}\\ -\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlinlinecode{fn : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.fn}& Record field whose type is an arrow with a mode.\\ -\ocamlinlinecode{fn\_\allowbreak{}both : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.fn_both}& Arrow field with modes on both sides.\\ -\ocamlinlinecode{\ocamltag{keyword}{mutable} mfn : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.mfn}& Mutable arrow field with a mode.\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlinlinecode{fn : int @ local \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.fn}& Record field whose type is an arrow with a mode.\\ +\ocamlinlinecode{fn\_\allowbreak{}both : int @ local \ocamltag{arrow}{$\rightarrow$} int @ local;\allowbreak{}}\label{Oxcaml--type-mode_record.fn_both}& Arrow field with modes on both sides.\\ +\ocamlinlinecode{\ocamltag{keyword}{mutable} mfn : int @ local \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml--type-mode_record.mfn}& Mutable arrow field with a mode.\\ \end{ocamltabular}% \\ \ocamlcodefragment{\}}\\ \label{Oxcaml--type-mode_cstr}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}cstr = }\\ -\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}arrow} \ocamltag{keyword}{of} int \ocamltag{arrow}{$\rightarrow$} int}\label{Oxcaml--type-mode_cstr.Mc_arrow}& Constructor argument is a parenthesized arrow with a mode.\\ -\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}nested} \ocamltag{keyword}{of} (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} unit}\label{Oxcaml--type-mode_cstr.Mc_nested}& Nested arrow: higher-order with a mode on the inner argument.\\ -\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}gadt} : (\ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a}) \ocamltag{arrow}{$\rightarrow$} \hyperref[Oxcaml--type-mode_cstr]{\ocamlinlinecode{mode\_\allowbreak{}cstr}}}\label{Oxcaml--type-mode_cstr.Mc_gadt}& GADT constructor\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}arrow} \ocamltag{keyword}{of} int @ local \ocamltag{arrow}{$\rightarrow$} int}\label{Oxcaml--type-mode_cstr.Mc_arrow}& Constructor argument is a parenthesized arrow with a mode.\\ +\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}nested} \ocamltag{keyword}{of} (int @ local \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} unit}\label{Oxcaml--type-mode_cstr.Mc_nested}& Nested arrow: higher-order with a mode on the inner argument.\\ +\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}gadt} : (\ocamltag{type-var}{'a} @ once \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a}) \ocamltag{arrow}{$\rightarrow$} \hyperref[Oxcaml--type-mode_cstr]{\ocamlinlinecode{mode\_\allowbreak{}cstr}}}\label{Oxcaml--type-mode_cstr.Mc_gadt}& GADT constructor\\ \end{ocamltabular}% \\ diff --git a/test/generators/latex/Oxcaml_impl.tex b/test/generators/latex/Oxcaml_impl.tex index f17d359a97..ef632140c6 100644 --- a/test/generators/latex/Oxcaml_impl.tex +++ b/test/generators/latex/Oxcaml_impl.tex @@ -26,23 +26,23 @@ \subsubsection{Modalities on constructor arguments\label{Oxcaml_impl--modalities \\ \subsection{Modes\label{Oxcaml_impl--modes}}% \subsubsection{Modes in type definitions\label{Oxcaml_impl--modes-in-type-definitions}}% -\label{Oxcaml_impl--type-mode_alias}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}alias = int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Type alias for an arrow with a mode on its argument.\end{ocamlindent}% +\label{Oxcaml_impl--type-mode_alias}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}alias = int @ local \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Type alias for an arrow with a mode on its argument.\end{ocamlindent}% \medbreak \label{Oxcaml_impl--type-mode_record}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}record = \{}\\ -\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlinlinecode{fn : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml_impl--type-mode_record.fn}& Field whose type is an arrow with a mode.\\ -\ocamlinlinecode{fn\_\allowbreak{}both : int \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml_impl--type-mode_record.fn_both}& Modes on both sides.\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlinlinecode{fn : int @ local \ocamltag{arrow}{$\rightarrow$} int;\allowbreak{}}\label{Oxcaml_impl--type-mode_record.fn}& Field whose type is an arrow with a mode.\\ +\ocamlinlinecode{fn\_\allowbreak{}both : int @ local \ocamltag{arrow}{$\rightarrow$} int @ local;\allowbreak{}}\label{Oxcaml_impl--type-mode_record.fn_both}& Modes on both sides.\\ \end{ocamltabular}% \\ \ocamlcodefragment{\}}\\ \label{Oxcaml_impl--type-mode_cstr}\ocamlcodefragment{\ocamltag{keyword}{type} mode\_\allowbreak{}cstr = }\\ -\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}arrow} \ocamltag{keyword}{of} int \ocamltag{arrow}{$\rightarrow$} int}\label{Oxcaml_impl--type-mode_cstr.Mc_arrow}& Constructor argument is a parenthesized arrow with a mode.\\ -\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}nested} \ocamltag{keyword}{of} (int \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} unit}\label{Oxcaml_impl--type-mode_cstr.Mc_nested}& Nested arrow: higher-order with a mode on the inner argument.\\ +\begin{ocamltabular}{p{0.500\textwidth}p{0.500\textwidth}}\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}arrow} \ocamltag{keyword}{of} int @ local \ocamltag{arrow}{$\rightarrow$} int}\label{Oxcaml_impl--type-mode_cstr.Mc_arrow}& Constructor argument is a parenthesized arrow with a mode.\\ +\ocamlcodefragment{| \ocamltag{constructor}{Mc\_\allowbreak{}nested} \ocamltag{keyword}{of} (int @ local \ocamltag{arrow}{$\rightarrow$} int) \ocamltag{arrow}{$\rightarrow$} unit}\label{Oxcaml_impl--type-mode_cstr.Mc_nested}& Nested arrow: higher-order with a mode on the inner argument.\\ \end{ocamltabular}% \\ \subsubsection{Modes on values\label{Oxcaml_impl--modes-on-values}}% -\label{Oxcaml_impl--val-mode_arg}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arg : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function argument, via a type annotation.\end{ocamlindent}% +\label{Oxcaml_impl--val-mode_arg}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}arg : int @ local \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a function argument, via a type annotation.\end{ocamlindent}% \medbreak -\label{Oxcaml_impl--val-mode_multi}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi : string \ocamltag{arrow}{$\rightarrow$} string}\begin{ocamlindent}Multiple modes on argument and return.\end{ocamlindent}% +\label{Oxcaml_impl--val-mode_multi}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi : string @ local once \ocamltag{arrow}{$\rightarrow$} string @ local once}\begin{ocamlindent}Multiple modes on argument and return.\end{ocamlindent}% \medbreak diff --git a/test/generators/man/Oxcaml.3o b/test/generators/man/Oxcaml.3o index 928d7b4962..e52d282b85 100644 --- a/test/generators/man/Oxcaml.3o +++ b/test/generators/man/Oxcaml.3o @@ -686,56 +686,56 @@ contended modality applied to all definitions in the module, except the ones whi \fB15 Modes\fR .in .sp -\f[CB]val\fR mode_arg : int \f[CB]\->\fR int +\f[CB]val\fR mode_arg : int @ local \f[CB]\->\fR int .fi .br .ti +2 Mode on a function argument\. .nf .sp -\f[CB]val\fR mode_ret : int \f[CB]\->\fR int +\f[CB]val\fR mode_ret : int \f[CB]\->\fR int @ local .fi .br .ti +2 Mode on a function return\. .nf .sp -\f[CB]val\fR mode_both : int \f[CB]\->\fR int +\f[CB]val\fR mode_both : int @ local \f[CB]\->\fR int @ local .fi .br .ti +2 Modes on both argument and return\. .nf .sp -\f[CB]val\fR mode_multi : string \f[CB]\->\fR string +\f[CB]val\fR mode_multi : string @ local once \f[CB]\->\fR string @ local unique .fi .br .ti +2 Multiple modes on argument and return\. .nf .sp -\f[CB]val\fR mode_labeled : \f[CB]x\fR:int \f[CB]\->\fR int +\f[CB]val\fR mode_labeled : \f[CB]x\fR:int @ local \f[CB]\->\fR int .fi .br .ti +2 Mode on a labeled argument\. .nf .sp -\f[CB]val\fR mode_optional : \f[CB]?x\fR:int \f[CB]\->\fR unit \f[CB]\->\fR int +\f[CB]val\fR mode_optional : \f[CB]?x\fR:int @ local \f[CB]\->\fR unit \f[CB]\->\fR int .fi .br .ti +2 Mode on an optional argument\. .nf .sp -\f[CB]val\fR mode_higher_order : (\f[CB]'a\fR \f[CB]\->\fR \f[CB]'b\fR) \f[CB]\->\fR \f[CB]'a\fR \f[CB]\->\fR \f[CB]'b\fR +\f[CB]val\fR mode_higher_order : (\f[CB]'a\fR \f[CB]\->\fR \f[CB]'b\fR) @ local \f[CB]\->\fR \f[CB]'a\fR \f[CB]\->\fR \f[CB]'b\fR .fi .br .ti +2 Mode on a higher-order function argument\. .nf .sp -\f[CB]val\fR mode_arrow_result : int \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR mode_arrow_result : int \f[CB]\->\fR (int \f[CB]\->\fR int) @ local .fi .br .ti +2 @@ -750,21 +750,21 @@ Mode on a result that is itself an arrow\. The arrow must be parenthesized so th Closing over an argument constrains the partial-application closure across several axes, not just locality\. When the result mode is the one currying implies from the argument, it is suppressed (as the compiler does)\. .nf .sp -\f[CB]val\fR curry_once : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR curry_once : (int \f[CB]\->\fR int) @ once \f[CB]\->\fR int \f[CB]\->\fR int .fi .br .ti +2 once argument: the implied once result mode is suppressed\. .nf .sp -\f[CB]val\fR curry_portable : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR curry_portable : (int \f[CB]\->\fR int) @ portable \f[CB]\->\fR int \f[CB]\->\fR int .fi .br .ti +2 portable argument: the implied result mode is suppressed\. .nf .sp -\f[CB]val\fR curry_contended : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR curry_contended : (int \f[CB]\->\fR int) @ contended \f[CB]\->\fR int \f[CB]\->\fR int .fi .br .ti +2 @@ -779,35 +779,35 @@ contended argument: the implied result mode is suppressed\. A result mode is only suppressed when it is exactly the one currying implies\. An explicit mode on a different axis is kept (and the arrow result is parenthesized)\. .nf .sp -\f[CB]val\fR keep_portable : int \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR keep_portable : int @ local \f[CB]\->\fR (int \f[CB]\->\fR int) @ portable .fi .br .ti +2 portable on the result is not implied by a local argument, so it is kept\. .nf .sp -\f[CB]val\fR keep_once : int \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR keep_once : int @ local \f[CB]\->\fR (int \f[CB]\->\fR int) @ once .fi .br .ti +2 once on the result is not implied by a local argument, so it is kept\. .nf .sp -\f[CB]val\fR keep_over_once : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR keep_over_once : (int \f[CB]\->\fR int) @ once \f[CB]\->\fR (int \f[CB]\->\fR int) @ portable .fi .br .ti +2 The curry-implied once is suppressed, but the explicit portable is kept\. .nf .sp -\f[CB]val\fR keep_over_local : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR keep_over_local : (int \f[CB]\->\fR int) @ local \f[CB]\->\fR (int \f[CB]\->\fR int) @ portable .fi .br .ti +2 The curry-implied local is suppressed, but the explicit portable is kept\. .nf .sp -\f[CB]val\fR keep_portable_over_nonportable : (int \f[CB]\->\fR int) \f[CB]\->\fR int \f[CB]\->\fR int +\f[CB]val\fR keep_portable_over_nonportable : (int \f[CB]\->\fR int) \f[CB]\->\fR (int \f[CB]\->\fR int) @ portable .fi .br .ti +2 @@ -825,7 +825,7 @@ The nonportable argument mode is the default and dropped, while the explicit por Locality mode (legacy, not rendered)\. .nf .sp -\f[CB]val\fR mode_local : int \f[CB]\->\fR unit +\f[CB]val\fR mode_local : int @ local \f[CB]\->\fR unit .fi .br .ti +2 @@ -839,7 +839,7 @@ Locality mode\. Uniqueness mode (legacy, not rendered)\. .nf .sp -\f[CB]val\fR mode_unique : int \f[CB]\->\fR unit +\f[CB]val\fR mode_unique : int @ unique \f[CB]\->\fR unit .fi .br .ti +2 @@ -853,21 +853,21 @@ Uniqueness mode\. Linearity mode (legacy, not rendered)\. .nf .sp -\f[CB]val\fR mode_once : int \f[CB]\->\fR unit +\f[CB]val\fR mode_once : int @ once \f[CB]\->\fR unit .fi .br .ti +2 Linearity mode\. .nf .sp -\f[CB]val\fR mode_portable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_portable : int @ portable \f[CB]\->\fR unit .fi .br .ti +2 Portability mode\. .nf .sp -\f[CB]val\fR mode_shareable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_shareable : int @ shareable \f[CB]\->\fR unit .fi .br .ti +2 @@ -888,21 +888,21 @@ Portability mode (legacy, not rendered)\. Contention mode (legacy, not rendered)\. .nf .sp -\f[CB]val\fR mode_shared : int \f[CB]\->\fR unit +\f[CB]val\fR mode_shared : int @ shared \f[CB]\->\fR unit .fi .br .ti +2 Contention mode\. .nf .sp -\f[CB]val\fR mode_contended : int \f[CB]\->\fR unit +\f[CB]val\fR mode_contended : int @ contended \f[CB]\->\fR unit .fi .br .ti +2 Contention mode\. .nf .sp -\f[CB]val\fR mode_yielding : int \f[CB]\->\fR unit +\f[CB]val\fR mode_yielding : int @ yielding \f[CB]\->\fR unit .fi .br .ti +2 @@ -923,35 +923,35 @@ Yield mode (legacy, not rendered)\. Fork mode (identity on a non-local argument, not rendered)\. .nf .sp -\f[CB]val\fR mode_local_forkable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_local_forkable : int @ local forkable \f[CB]\->\fR unit .fi .br .ti +2 Fork mode, rendered because the argument is also local\. .nf .sp -\f[CB]val\fR mode_unforkable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_unforkable : int @ unforkable \f[CB]\->\fR unit .fi .br .ti +2 Fork mode\. .nf .sp -\f[CB]val\fR mode_local_unforkable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_local_unforkable : int @ local \f[CB]\->\fR unit .fi .br .ti +2 Fork mode (identity for a local argument, not rendered)\. .nf .sp -\f[CB]val\fR mode_stateless : int \f[CB]\->\fR unit +\f[CB]val\fR mode_stateless : int @ stateless \f[CB]\->\fR unit .fi .br .ti +2 Statefulness mode\. .nf .sp -\f[CB]val\fR mode_observing : int \f[CB]\->\fR unit +\f[CB]val\fR mode_observing : int @ observing \f[CB]\->\fR unit .fi .br .ti +2 @@ -965,14 +965,14 @@ Statefulness mode\. Statefulness mode (identity when portability is at its default, not rendered)\. .nf .sp -\f[CB]val\fR mode_immutable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_immutable : int @ immutable \f[CB]\->\fR unit .fi .br .ti +2 Visibility mode\. .nf .sp -\f[CB]val\fR mode_read : int \f[CB]\->\fR unit +\f[CB]val\fR mode_read : int @ read \f[CB]\->\fR unit .fi .br .ti +2 @@ -986,7 +986,7 @@ Visibility mode\. Visibility mode (legacy, not rendered)\. .nf .sp -\f[CB]val\fR mode_static : int \f[CB]\->\fR unit +\f[CB]val\fR mode_static : int @ static \f[CB]\->\fR unit .fi .br .ti +2 @@ -1008,42 +1008,42 @@ Staticity mode (legacy, not rendered)\. Some axes have a default value that is implied by another axis; the implied value is suppressed when rendering\. .nf .sp -\f[CB]val\fR mode_local_yielding : int \f[CB]\->\fR unit +\f[CB]val\fR mode_local_yielding : int @ local \f[CB]\->\fR unit .fi .br .ti +2 yielding is the default for local, so it is not rendered\. .nf .sp -\f[CB]val\fR mode_local_unyielding : int \f[CB]\->\fR unit +\f[CB]val\fR mode_local_unyielding : int @ local unyielding \f[CB]\->\fR unit .fi .br .ti +2 unyielding is non-default for local, so it is rendered\. .nf .sp -\f[CB]val\fR mode_immutable_contended : int \f[CB]\->\fR unit +\f[CB]val\fR mode_immutable_contended : int @ immutable \f[CB]\->\fR unit .fi .br .ti +2 contended is the default for immutable, so it is not rendered\. .nf .sp -\f[CB]val\fR mode_immutable_uncontended : int \f[CB]\->\fR unit +\f[CB]val\fR mode_immutable_uncontended : int @ uncontended immutable \f[CB]\->\fR unit .fi .br .ti +2 uncontended is non-default for immutable, so it is rendered\. .nf .sp -\f[CB]val\fR mode_stateless_portable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_stateless_portable : int @ stateless \f[CB]\->\fR unit .fi .br .ti +2 portable is the default for stateless, so it is not rendered\. .nf .sp -\f[CB]val\fR mode_stateful_portable : int \f[CB]\->\fR unit +\f[CB]val\fR mode_stateful_portable : int @ portable \f[CB]\->\fR unit .fi .br .ti +2 @@ -1054,7 +1054,7 @@ portable is non-default for stateful, so it is rendered\. \fB15\.5 Modes in type definitions\fR .in .sp -\f[CB]type\fR mode_alias = int \f[CB]\->\fR int +\f[CB]type\fR mode_alias = int @ local \f[CB]\->\fR int .fi .br .ti +2 @@ -1064,19 +1064,19 @@ Type alias for an arrow with a mode on its argument\. \f[CB]type\fR mode_record = { .br .ti +2 -fn : int \f[CB]\->\fR int; +fn : int @ local \f[CB]\->\fR int; .br .ti +4 (* Record field whose type is an arrow with a mode\. *) .br .ti +2 -fn_both : int \f[CB]\->\fR int; +fn_both : int @ local \f[CB]\->\fR int @ local; .br .ti +4 (* Arrow field with modes on both sides\. *) .br .ti +2 -\f[CB]mutable\fR mfn : int \f[CB]\->\fR int; +\f[CB]mutable\fR mfn : int @ local \f[CB]\->\fR int; .br .ti +4 (* Mutable arrow field with a mode\. *) @@ -1086,19 +1086,19 @@ fn_both : int \f[CB]\->\fR int; \f[CB]type\fR mode_cstr = .br .ti +2 -| \f[CB]Mc_arrow\fR \f[CB]of\fR int \f[CB]\->\fR int +| \f[CB]Mc_arrow\fR \f[CB]of\fR int @ local \f[CB]\->\fR int .br .ti +4 (* Constructor argument is a parenthesized arrow with a mode\. *) .br .ti +2 -| \f[CB]Mc_nested\fR \f[CB]of\fR (int \f[CB]\->\fR int) \f[CB]\->\fR unit +| \f[CB]Mc_nested\fR \f[CB]of\fR (int @ local \f[CB]\->\fR int) \f[CB]\->\fR unit .br .ti +4 (* Nested arrow: higher-order with a mode on the inner argument\. *) .br .ti +2 -| \f[CB]Mc_gadt\fR : (\f[CB]'a\fR \f[CB]\->\fR \f[CB]'a\fR) \f[CB]\->\fR mode_cstr +| \f[CB]Mc_gadt\fR : (\f[CB]'a\fR @ once \f[CB]\->\fR \f[CB]'a\fR) \f[CB]\->\fR mode_cstr .br .ti +4 (* GADT constructor *) diff --git a/test/generators/man/Oxcaml_impl.3o b/test/generators/man/Oxcaml_impl.3o index 1d2ea4d112..2db71c4dbb 100644 --- a/test/generators/man/Oxcaml_impl.3o +++ b/test/generators/man/Oxcaml_impl.3o @@ -88,7 +88,7 @@ f_plain : opaque; \fB2\.1 Modes in type definitions\fR .in .sp -\f[CB]type\fR mode_alias = int \f[CB]\->\fR int +\f[CB]type\fR mode_alias = int @ local \f[CB]\->\fR int .fi .br .ti +2 @@ -98,13 +98,13 @@ Type alias for an arrow with a mode on its argument\. \f[CB]type\fR mode_record = { .br .ti +2 -fn : int \f[CB]\->\fR int; +fn : int @ local \f[CB]\->\fR int; .br .ti +4 (* Field whose type is an arrow with a mode\. *) .br .ti +2 -fn_both : int \f[CB]\->\fR int; +fn_both : int @ local \f[CB]\->\fR int @ local; .br .ti +4 (* Modes on both sides\. *) @@ -114,13 +114,13 @@ fn_both : int \f[CB]\->\fR int; \f[CB]type\fR mode_cstr = .br .ti +2 -| \f[CB]Mc_arrow\fR \f[CB]of\fR int \f[CB]\->\fR int +| \f[CB]Mc_arrow\fR \f[CB]of\fR int @ local \f[CB]\->\fR int .br .ti +4 (* Constructor argument is a parenthesized arrow with a mode\. *) .br .ti +2 -| \f[CB]Mc_nested\fR \f[CB]of\fR (int \f[CB]\->\fR int) \f[CB]\->\fR unit +| \f[CB]Mc_nested\fR \f[CB]of\fR (int @ local \f[CB]\->\fR int) \f[CB]\->\fR unit .br .ti +4 (* Nested arrow: higher-order with a mode on the inner argument\. *) @@ -130,14 +130,14 @@ fn_both : int \f[CB]\->\fR int; \fB2\.2 Modes on values\fR .in .sp -\f[CB]val\fR mode_arg : int \f[CB]\->\fR int +\f[CB]val\fR mode_arg : int @ local \f[CB]\->\fR int .fi .br .ti +2 Mode on a function argument, via a type annotation\. .nf .sp -\f[CB]val\fR mode_multi : string \f[CB]\->\fR string +\f[CB]val\fR mode_multi : string @ local once \f[CB]\->\fR string @ local once .fi .br .ti +2 diff --git a/test/generators/markdown/Oxcaml-module-type-Mode_sig.md b/test/generators/markdown/Oxcaml-module-type-Mode_sig.md new file mode 100644 index 0000000000..9fb7ab2621 --- /dev/null +++ b/test/generators/markdown/Oxcaml-module-type-Mode_sig.md @@ -0,0 +1,24 @@ + +# Module type `Oxcaml.Mode_sig` + +Module type containing declarations with modes. + +```ocaml +val arg : int @ local -> int +``` +Mode on a function argument. + +```ocaml +val ret : int -> int @ local +``` +Mode on a function return. + +```ocaml +val multi : string @ local once -> string @ local unique +``` +Multiple modes on argument and return. + +```ocaml +type alias = int @ local -> int +``` +Type alias for an arrow with a mode. diff --git a/test/generators/markdown/Oxcaml.md b/test/generators/markdown/Oxcaml.md index d26575cfd4..4c81c1a6dc 100644 --- a/test/generators/markdown/Oxcaml.md +++ b/test/generators/markdown/Oxcaml.md @@ -350,42 +350,42 @@ module M3 : sig ... end ## Modes ```ocaml -val mode_arg : int -> int +val mode_arg : int @ local -> int ``` Mode on a function argument. ```ocaml -val mode_ret : int -> int +val mode_ret : int -> int @ local ``` Mode on a function return. ```ocaml -val mode_both : int -> int +val mode_both : int @ local -> int @ local ``` Modes on both argument and return. ```ocaml -val mode_multi : string -> string +val mode_multi : string @ local once -> string @ local unique ``` Multiple modes on argument and return. ```ocaml -val mode_labeled : x:int -> int +val mode_labeled : x:int @ local -> int ``` Mode on a labeled argument. ```ocaml -val mode_optional : ?x:int -> unit -> int +val mode_optional : ?x:int @ local -> unit -> int ``` Mode on an optional argument. ```ocaml -val mode_higher_order : ('a -> 'b) -> 'a -> 'b +val mode_higher_order : ('a -> 'b) @ local -> 'a -> 'b ``` Mode on a higher-order function argument. ```ocaml -val mode_arrow_result : int -> int -> int +val mode_arrow_result : int -> (int -> int) @ local ``` Mode on a result that is itself an arrow. The arrow must be parenthesized so the mode does not appear to bind to the inner return type. @@ -395,17 +395,17 @@ Mode on a result that is itself an arrow. The arrow must be parenthesized so the Closing over an argument constrains the partial-application closure across several axes, not just locality. When the result mode is the one currying implies from the argument, it is suppressed (as the compiler does). ```ocaml -val curry_once : (int -> int) -> int -> int +val curry_once : (int -> int) @ once -> int -> int ``` `once` argument: the implied `once` result mode is suppressed. ```ocaml -val curry_portable : (int -> int) -> int -> int +val curry_portable : (int -> int) @ portable -> int -> int ``` `portable` argument: the implied result mode is suppressed. ```ocaml -val curry_contended : (int -> int) -> int -> int +val curry_contended : (int -> int) @ contended -> int -> int ``` `contended` argument: the implied result mode is suppressed. @@ -415,27 +415,27 @@ val curry_contended : (int -> int) -> int -> int A result mode is only suppressed when it is exactly the one currying implies. An explicit mode on a different axis is kept (and the arrow result is parenthesized). ```ocaml -val keep_portable : int -> int -> int +val keep_portable : int @ local -> (int -> int) @ portable ``` `portable` on the result is not implied by a `local` argument, so it is kept. ```ocaml -val keep_once : int -> int -> int +val keep_once : int @ local -> (int -> int) @ once ``` `once` on the result is not implied by a `local` argument, so it is kept. ```ocaml -val keep_over_once : (int -> int) -> int -> int +val keep_over_once : (int -> int) @ once -> (int -> int) @ portable ``` The curry-implied `once` is suppressed, but the explicit `portable` is kept. ```ocaml -val keep_over_local : (int -> int) -> int -> int +val keep_over_local : (int -> int) @ local -> (int -> int) @ portable ``` The curry-implied `local` is suppressed, but the explicit `portable` is kept. ```ocaml -val keep_portable_over_nonportable : (int -> int) -> int -> int +val keep_portable_over_nonportable : (int -> int) -> (int -> int) @ portable ``` The `nonportable` argument mode is the default and dropped, while the explicit `portable` result, not implied by currying, is kept. @@ -448,7 +448,7 @@ val mode_global : int -> unit Locality mode (legacy, not rendered). ```ocaml -val mode_local : int -> unit +val mode_local : int @ local -> unit ``` Locality mode. @@ -458,7 +458,7 @@ val mode_aliased : int -> unit Uniqueness mode (legacy, not rendered). ```ocaml -val mode_unique : int -> unit +val mode_unique : int @ unique -> unit ``` Uniqueness mode. @@ -468,17 +468,17 @@ val mode_many : int -> unit Linearity mode (legacy, not rendered). ```ocaml -val mode_once : int -> unit +val mode_once : int @ once -> unit ``` Linearity mode. ```ocaml -val mode_portable : int -> unit +val mode_portable : int @ portable -> unit ``` Portability mode. ```ocaml -val mode_shareable : int -> unit +val mode_shareable : int @ shareable -> unit ``` Portability mode (intermediate value). @@ -493,17 +493,17 @@ val mode_uncontended : int -> unit Contention mode (legacy, not rendered). ```ocaml -val mode_shared : int -> unit +val mode_shared : int @ shared -> unit ``` Contention mode. ```ocaml -val mode_contended : int -> unit +val mode_contended : int @ contended -> unit ``` Contention mode. ```ocaml -val mode_yielding : int -> unit +val mode_yielding : int @ yielding -> unit ``` Yield mode. @@ -518,27 +518,27 @@ val mode_forkable : int -> unit Fork mode (identity on a non-`local` argument, not rendered). ```ocaml -val mode_local_forkable : int -> unit +val mode_local_forkable : int @ local forkable -> unit ``` Fork mode, rendered because the argument is also `local`. ```ocaml -val mode_unforkable : int -> unit +val mode_unforkable : int @ unforkable -> unit ``` Fork mode. ```ocaml -val mode_local_unforkable : int -> unit +val mode_local_unforkable : int @ local -> unit ``` Fork mode (identity for a `local` argument, not rendered). ```ocaml -val mode_stateless : int -> unit +val mode_stateless : int @ stateless -> unit ``` Statefulness mode. ```ocaml -val mode_observing : int -> unit +val mode_observing : int @ observing -> unit ``` Statefulness mode. @@ -548,12 +548,12 @@ val mode_stateful : int -> unit Statefulness mode (identity when `portability` is at its default, not rendered). ```ocaml -val mode_immutable : int -> unit +val mode_immutable : int @ immutable -> unit ``` Visibility mode. ```ocaml -val mode_read : int -> unit +val mode_read : int @ read -> unit ``` Visibility mode. @@ -563,7 +563,7 @@ val mode_read_write : int -> unit Visibility mode (legacy, not rendered). ```ocaml -val mode_static : int -> unit +val mode_static : int @ static -> unit ``` Staticity mode. @@ -578,32 +578,32 @@ Staticity mode (legacy, not rendered). Some axes have a default value that is implied by another axis; the implied value is suppressed when rendering. ```ocaml -val mode_local_yielding : int -> unit +val mode_local_yielding : int @ local -> unit ``` `yielding` is the default for `local`, so it is not rendered. ```ocaml -val mode_local_unyielding : int -> unit +val mode_local_unyielding : int @ local unyielding -> unit ``` `unyielding` is non-default for `local`, so it is rendered. ```ocaml -val mode_immutable_contended : int -> unit +val mode_immutable_contended : int @ immutable -> unit ``` `contended` is the default for `immutable`, so it is not rendered. ```ocaml -val mode_immutable_uncontended : int -> unit +val mode_immutable_uncontended : int @ uncontended immutable -> unit ``` `uncontended` is non-default for `immutable`, so it is rendered. ```ocaml -val mode_stateless_portable : int -> unit +val mode_stateless_portable : int @ stateless -> unit ``` `portable` is the default for `stateless`, so it is not rendered. ```ocaml -val mode_stateful_portable : int -> unit +val mode_stateful_portable : int @ portable -> unit ``` `portable` is non-default for `stateful`, so it is rendered. @@ -611,20 +611,20 @@ val mode_stateful_portable : int -> unit ### Modes in type definitions ```ocaml -type mode_alias = int -> int +type mode_alias = int @ local -> int ``` Type alias for an arrow with a mode on its argument. ```ocaml type mode_record = { - fn : int -> int; (* Record field whose type is an arrow with a mode. *) - fn_both : int -> int; (* Arrow field with modes on both sides. *) - mutable mfn : int -> int; (* Mutable arrow field with a mode. *) + fn : int @ local -> int; (* Record field whose type is an arrow with a mode. *) + fn_both : int @ local -> int @ local; (* Arrow field with modes on both sides. *) + mutable mfn : int @ local -> int; (* Mutable arrow field with a mode. *) } ``` ```ocaml type mode_cstr = - | Mc_arrow of int -> int (* Constructor argument is a parenthesized arrow with a mode. *) - | Mc_nested of (int -> int) -> unit (* Nested arrow: higher-order with a mode on the inner argument. *) - | Mc_gadt : ('a -> 'a) -> mode_cstr (* GADT constructor *) + | Mc_arrow of int @ local -> int (* Constructor argument is a parenthesized arrow with a mode. *) + | Mc_nested of (int @ local -> int) -> unit (* Nested arrow: higher-order with a mode on the inner argument. *) + | Mc_gadt : ('a @ once -> 'a) -> mode_cstr (* GADT constructor *) ``` \ No newline at end of file diff --git a/test/generators/markdown/Oxcaml_impl.md b/test/generators/markdown/Oxcaml_impl.md index 2363ac1fc0..6504572984 100644 --- a/test/generators/markdown/Oxcaml_impl.md +++ b/test/generators/markdown/Oxcaml_impl.md @@ -43,30 +43,30 @@ type modalities_variant = ### Modes in type definitions ```ocaml -type mode_alias = int -> int +type mode_alias = int @ local -> int ``` Type alias for an arrow with a mode on its argument. ```ocaml type mode_record = { - fn : int -> int; (* Field whose type is an arrow with a mode. *) - fn_both : int -> int; (* Modes on both sides. *) + fn : int @ local -> int; (* Field whose type is an arrow with a mode. *) + fn_both : int @ local -> int @ local; (* Modes on both sides. *) } ``` ```ocaml type mode_cstr = - | Mc_arrow of int -> int (* Constructor argument is a parenthesized arrow with a mode. *) - | Mc_nested of (int -> int) -> unit (* Nested arrow: higher-order with a mode on the inner argument. *) + | Mc_arrow of int @ local -> int (* Constructor argument is a parenthesized arrow with a mode. *) + | Mc_nested of (int @ local -> int) -> unit (* Nested arrow: higher-order with a mode on the inner argument. *) ``` ### Modes on values ```ocaml -val mode_arg : int -> int +val mode_arg : int @ local -> int ``` Mode on a function argument, via a type annotation. ```ocaml -val mode_multi : string -> string +val mode_multi : string @ local once -> string @ local once ``` Multiple modes on argument and return. diff --git a/test/xref2/classes.t/run.t b/test/xref2/classes.t/run.t index c241e1bb6e..ca0f54b0c8 100644 --- a/test/xref2/classes.t/run.t +++ b/test/xref2/classes.t/run.t @@ -121,36 +121,42 @@ resolve correctly. All of the 'Class' json objects should contain { "Arrow": [ "None", - { - "Class": [ - { - "`Resolved": { - "`ClassType": [ - { - "`Identifier": { - "`Root": [ - "None", - "B" - ] - } - }, - "u" - ] - } - }, - [] - ] - }, - { - "Constr": [ - { - "`Resolved": { - "`CoreType": "unit" - } - }, - [] - ] - } + [ + { + "Class": [ + { + "`Resolved": { + "`ClassType": [ + { + "`Identifier": { + "`Root": [ + "None", + "B" + ] + } + }, + "u" + ] + } + }, + [] + ] + }, + [] + ], + [ + { + "Constr": [ + { + "`Resolved": { + "`CoreType": "unit" + } + }, + [] + ] + }, + [] + ] ] } diff --git a/test/xref2/github_issue_1001.t/run.t b/test/xref2/github_issue_1001.t/run.t index b29f054c0c..880260e22d 100644 --- a/test/xref2/github_issue_1001.t/run.t +++ b/test/xref2/github_issue_1001.t/run.t @@ -14,14 +14,20 @@ We should have an 'Optional' argument (as opposed to a 'RawOptional' one) "type_": { "Arrow": [ { "Some": { "Optional": "optional" } }, - { "Constr": [ { "`Resolved": { "`CoreType": "int" } }, [] ] }, - { - "Arrow": [ - "None", - { "Constr": [ { "`Resolved": { "`CoreType": "unit" } }, [] ] }, - { "Var": "a" } - ] - } + [ { "Constr": [ { "`Resolved": { "`CoreType": "int" } }, [] ] }, [] ], + [ + { + "Arrow": [ + "None", + [ + { "Constr": [ { "`Resolved": { "`CoreType": "unit" } }, [] ] }, + [] + ], + [ { "Var": "a" }, [] ] + ] + }, + [] + ] ] }, "value": "Abstract", @@ -38,25 +44,34 @@ Harder case contains a "RawOptional": "type_": { "Arrow": [ { "Some": { "RawOptional": "optional" } }, - { - "Constr": [ - { - "`Resolved": { - "`Identifier": { - "`Type": [ { "`Root": [ "None", "Test" ] }, "hard" ] + [ + { + "Constr": [ + { + "`Resolved": { + "`Identifier": { + "`Type": [ { "`Root": [ "None", "Test" ] }, "hard" ] + } } - } - }, - [] - ] - }, - { - "Arrow": [ - "None", - { "Constr": [ { "`Resolved": { "`CoreType": "unit" } }, [] ] }, - { "Var": "a" } - ] - } + }, + [] + ] + }, + [] + ], + [ + { + "Arrow": [ + "None", + [ + { "Constr": [ { "`Resolved": { "`CoreType": "unit" } }, [] ] }, + [] + ], + [ { "Var": "a" }, [] ] + ] + }, + [] + ] ] }, "value": "Abstract", diff --git a/test/xref2/github_issue_930.t/run.t b/test/xref2/github_issue_930.t/run.t index 22a97fea5a..dbc59f9502 100644 --- a/test/xref2/github_issue_930.t/run.t +++ b/test/xref2/github_issue_930.t/run.t @@ -30,10 +30,10 @@ S1 is included in S2 and S2 is included in S3: Check that S0_with_creators_base compiles without crashing and has the concat function with simplified types (t -> t): - $ odoc_print test.odocl -r S0_with_creators_base.concat | jq -c '.type_.Arrow[1].Constr[0]' + $ odoc_print test.odocl -r S0_with_creators_base.concat | jq -c '.type_.Arrow[1][0].Constr[0]' {"`Resolved":{"`Identifier":{"`Type":[{"`ModuleType":[{"`Root":["None","Test"]},"S0_with_creators_base"]},"t"]}}} - $ odoc_print test.odocl -r S0_with_creators_base.concat | jq -c '.type_.Arrow[2].Constr[0]' + $ odoc_print test.odocl -r S0_with_creators_base.concat | jq -c '.type_.Arrow[2][0].Constr[0]' {"`Resolved":{"`Identifier":{"`Type":[{"`ModuleType":[{"`Root":["None","Test"]},"S0_with_creators_base"]},"t"]}}} === Test 3: Deeply nested includes === From 75ecad7850015afeef38bad693ccc6b78e5c9fc1 Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Tue, 25 Aug 2026 13:45:33 +0200 Subject: [PATCH 3/9] OxCaml: type alias for type-with-modes --- src/model/lang.ml | 4 +++- src/xref2/compile.ml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/model/lang.ml b/src/model/lang.ml index 5136077c2b..9dabb70404 100644 --- a/src/model/lang.ml +++ b/src/model/lang.ml @@ -501,7 +501,7 @@ and TypeExpr : sig | Var of string | Any | Alias of t * string - | Arrow of label option * (t * Modes.t) * (t * Modes.t) + | Arrow of label option * with_modes * with_modes | Tuple of (string option * t) list | Unboxed_tuple of (string option * t) list | Constr of Path.Type.t * t list @@ -513,6 +513,8 @@ and TypeExpr : sig | Splice of t | Package of TypeExpr.Package.t | Arrow_functor of label option * Module.t * t + + and with_modes = t * Modes.t end = TypeExpr diff --git a/src/xref2/compile.ml b/src/xref2/compile.ml index 97401801f9..3c64d74b2b 100644 --- a/src/xref2/compile.ml +++ b/src/xref2/compile.ml @@ -887,8 +887,8 @@ and handle_arrow : Env.t -> Id.Id.label_parent -> TypeExpr.label option -> - TypeExpr.t * Modes.t -> - TypeExpr.t * Modes.t -> + TypeExpr.with_modes -> + TypeExpr.with_modes -> TypeExpr.t = fun env parent lbl (t1, m1) (t2, m2) -> let t2' = (type_expression env parent t2, m2) in From 363de4f68798d3e829485ce5a69cf445171a89d4 Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Tue, 25 Aug 2026 13:54:51 +0200 Subject: [PATCH 4/9] OxCaml: Note why the implicit self arrow's modes are dropped --- src/loader/cmt.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/loader/cmt.ml b/src/loader/cmt.ml index f2f48a4f42..fa92b0744f 100644 --- a/src/loader/cmt.ml +++ b/src/loader/cmt.ml @@ -289,7 +289,9 @@ let rec read_class_field env parent cf = | Tcfk_concrete(_, expr) -> (* Types of concrete methods in class implementation begin with the object as first (implicit) argument, so we - must keep only the type after the first arrow. *) + must keep only the type after the first arrow. That + arrow's modes are always legacy, since a method type + cannot carry a mode annotation. *) let type_ = match Cmi.read_type_expr env expr.exp_type with | Arrow (_, _, (t, _)) -> t From b601465bd783af2674544b6125d0d2803097eab4 Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Tue, 25 Aug 2026 14:27:04 +0200 Subject: [PATCH 5/9] OxCaml: enforce known mode axes --- src/loader/cmi.ml | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index 2407b4e05c..258651e335 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -550,7 +550,7 @@ let read_constructor_argument arg = arg.ca_type, read_modalities Immutable arg.ca_modalities let tree_of_modes (modes : Mode.Alloc.Const.t) : string list = - (* Same as the OxCaml's [Printtyp.tree_of_modes]: axes whose value is legacy + (* Same as the OxCaml's [tree_of_modes]: axes whose value is legacy or is implied by another axis are suppressed. *) let forkable = match modes.areality, modes.forkable with @@ -576,20 +576,30 @@ let tree_of_modes (modes : Mode.Alloc.Const.t) : string list = | Stateful, Nonportable -> None | _, _ -> Some modes.portability in - let diff = Mode.Alloc.Const.diff modes Mode.Alloc.Const.legacy in - let diff = { diff with forkable; yielding; contention; portability } in + let { Mode.Alloc.areality; + linearity; + uniqueness; + portability = _; + contention = _; + forkable = _; + yielding = _; + statefulness; + visibility; + staticity + } = Mode.Alloc.Const.diff modes Mode.Alloc.Const.legacy + in let print_opt print a = Option.map (Format_doc.asprintf "%a" print) a in List.filter_map (fun x -> x) - [ print_opt Mode.Locality.Const.print diff.areality - ; print_opt Mode.Uniqueness.Const.print diff.uniqueness - ; print_opt Mode.Linearity.Const.print diff.linearity - ; print_opt Mode.Portability.Const.print diff.portability - ; print_opt Mode.Contention.Const.print diff.contention - ; print_opt Mode.Forkable.Const.print diff.forkable - ; print_opt Mode.Yielding.Const.print diff.yielding - ; print_opt Mode.Statefulness.Const.print diff.statefulness - ; print_opt Mode.Visibility.Const.print diff.visibility - ; print_opt Mode.Staticity.Const.print diff.staticity ] + [ print_opt Mode.Locality.Const.print areality + ; print_opt Mode.Uniqueness.Const.print uniqueness + ; print_opt Mode.Linearity.Const.print linearity + ; print_opt Mode.Portability.Const.print portability + ; print_opt Mode.Contention.Const.print contention + ; print_opt Mode.Forkable.Const.print forkable + ; print_opt Mode.Yielding.Const.print yielding + ; print_opt Mode.Statefulness.Const.print statefulness + ; print_opt Mode.Visibility.Const.print visibility + ; print_opt Mode.Staticity.Const.print staticity ] let read_alloc_modes m = tree_of_modes (Mode.Alloc.zap_to_legacy m) From 93c4a489145f331f372d34945150d3e6c17ed652 Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Tue, 25 Aug 2026 14:29:21 +0200 Subject: [PATCH 6/9] OxCaml: fix modes tests --- test/generators/cases/oxcaml.mli | 3 + .../html/Oxcaml-module-type-Mode_sig.html | 66 ------------------- test/generators/html/Oxcaml.html | 16 +++++ test/generators/latex/Oxcaml.tex | 2 + test/generators/man/Oxcaml.3o | 7 ++ .../markdown/Oxcaml-module-type-Mode_sig.md | 24 ------- test/generators/markdown/Oxcaml.md | 5 ++ 7 files changed, 33 insertions(+), 90 deletions(-) delete mode 100644 test/generators/html/Oxcaml-module-type-Mode_sig.html delete mode 100644 test/generators/markdown/Oxcaml-module-type-Mode_sig.md diff --git a/test/generators/cases/oxcaml.mli b/test/generators/cases/oxcaml.mli index 0437af1acb..61b39cfb6e 100644 --- a/test/generators/cases/oxcaml.mli +++ b/test/generators/cases/oxcaml.mli @@ -295,6 +295,9 @@ val mode_both : int @ local -> int @ local val mode_multi : string @ local once -> string @ local unique (** Multiple modes on argument and return. *) +val mode_multi_flipped : string @ once local -> string @ unique local +(** Same as [mode_multi], to show that modes order is normalized. *) + val mode_labeled : x:int @ local -> int (** Mode on a labeled argument. *) diff --git a/test/generators/html/Oxcaml-module-type-Mode_sig.html b/test/generators/html/Oxcaml-module-type-Mode_sig.html deleted file mode 100644 index cfc273754a..0000000000 --- a/test/generators/html/Oxcaml-module-type-Mode_sig.html +++ /dev/null @@ -1,66 +0,0 @@ - - - Mode_sig (Oxcaml.Mode_sig) - - - - - - - - -
    -

    Module type Oxcaml.Mode_sig

    -

    Module type containing declarations with modes.

    -
    -
    -
    -
    - - - val arg : - int @ local -> - int - - -

    Mode on a function argument.

    -
    -
    -
    - - - val ret : - int -> int @ local - - -

    Mode on a function return.

    -
    -
    -
    - - - val multi : - string @ local once -> - string @ local unique - - -
    -

    Multiple modes on argument and return.

    -
    -
    -
    - - type alias - = int @ local -> - int - - -
    -

    Type alias for an arrow with a mode.

    -
    -
    - - diff --git a/test/generators/html/Oxcaml.html b/test/generators/html/Oxcaml.html index 304862f666..6a01015c55 100644 --- a/test/generators/html/Oxcaml.html +++ b/test/generators/html/Oxcaml.html @@ -1240,6 +1240,22 @@

  • Multiple modes on argument and return.

  • +
    +
    + + + val mode_multi_flipped : + string @ local once -> + string @ local unique + + +
    +
    +

    Same as mode_multi, to show that modes order is + normalized. +

    +
    +
    diff --git a/test/generators/latex/Oxcaml.tex b/test/generators/latex/Oxcaml.tex index f7b5884ac0..8ae5c07ffc 100644 --- a/test/generators/latex/Oxcaml.tex +++ b/test/generators/latex/Oxcaml.tex @@ -249,6 +249,8 @@ \subsection{Modes\label{Oxcaml--modes}}% \medbreak \label{Oxcaml--val-mode_multi}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi : string @ local once \ocamltag{arrow}{$\rightarrow$} string @ local unique}\begin{ocamlindent}Multiple modes on argument and return.\end{ocamlindent}% \medbreak +\label{Oxcaml--val-mode_multi_flipped}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}multi\_\allowbreak{}flipped : string @ local once \ocamltag{arrow}{$\rightarrow$} string @ local unique}\begin{ocamlindent}Same as \ocamlinlinecode{mode\_\allowbreak{}multi}, to show that modes order is normalized.\end{ocamlindent}% +\medbreak \label{Oxcaml--val-mode_labeled}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}labeled : \ocamltag{label}{x}:int @ local \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on a labeled argument.\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_optional}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}optional : \ocamltag{optlabel}{?x}:int @ local \ocamltag{arrow}{$\rightarrow$} unit \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}Mode on an optional argument.\end{ocamlindent}% diff --git a/test/generators/man/Oxcaml.3o b/test/generators/man/Oxcaml.3o index e52d282b85..23cf7db859 100644 --- a/test/generators/man/Oxcaml.3o +++ b/test/generators/man/Oxcaml.3o @@ -714,6 +714,13 @@ Modes on both argument and return\. Multiple modes on argument and return\. .nf .sp +\f[CB]val\fR mode_multi_flipped : string @ local once \f[CB]\->\fR string @ local unique +.fi +.br +.ti +2 +Same as mode_multi, to show that modes order is normalized\. +.nf +.sp \f[CB]val\fR mode_labeled : \f[CB]x\fR:int @ local \f[CB]\->\fR int .fi .br diff --git a/test/generators/markdown/Oxcaml-module-type-Mode_sig.md b/test/generators/markdown/Oxcaml-module-type-Mode_sig.md deleted file mode 100644 index 9fb7ab2621..0000000000 --- a/test/generators/markdown/Oxcaml-module-type-Mode_sig.md +++ /dev/null @@ -1,24 +0,0 @@ - -# Module type `Oxcaml.Mode_sig` - -Module type containing declarations with modes. - -```ocaml -val arg : int @ local -> int -``` -Mode on a function argument. - -```ocaml -val ret : int -> int @ local -``` -Mode on a function return. - -```ocaml -val multi : string @ local once -> string @ local unique -``` -Multiple modes on argument and return. - -```ocaml -type alias = int @ local -> int -``` -Type alias for an arrow with a mode. diff --git a/test/generators/markdown/Oxcaml.md b/test/generators/markdown/Oxcaml.md index 4c81c1a6dc..d1f6dad452 100644 --- a/test/generators/markdown/Oxcaml.md +++ b/test/generators/markdown/Oxcaml.md @@ -369,6 +369,11 @@ val mode_multi : string @ local once -> string @ local unique ``` Multiple modes on argument and return. +```ocaml +val mode_multi_flipped : string @ local once -> string @ local unique +``` +Same as `mode_multi`, to show that modes order is normalized. + ```ocaml val mode_labeled : x:int @ local -> int ``` From 4d3947c35a4de1c4fa59404bd5edb3237ab02d4f Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Tue, 25 Aug 2026 14:35:41 +0200 Subject: [PATCH 7/9] OxCaml: guard method from modes --- src/loader/cmt.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/loader/cmt.ml b/src/loader/cmt.ml index fa92b0744f..5c225a6c8b 100644 --- a/src/loader/cmt.ml +++ b/src/loader/cmt.ml @@ -294,7 +294,8 @@ let rec read_class_field env parent cf = cannot carry a mode annotation. *) let type_ = match Cmi.read_type_expr env expr.exp_type with - | Arrow (_, _, (t, _)) -> t + | Arrow (_, _, (t, [])) -> t + | Arrow (_, _, (_, _ :: _)) -> invalid_arg "unexpected modes on method" | t -> t in false, type_ From f9fb02e56a3145cf94acfe7aeb5f031c9957fc6d Mon Sep 17 00:00:00 2001 From: Arthur Wendling Date: Tue, 25 Aug 2026 14:39:31 +0200 Subject: [PATCH 8/9] OxCaml: rename to implied_modes --- src/loader/cmi.ml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index 258651e335..cef0f31b04 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -610,32 +610,32 @@ let legacy_modes = Mode.Alloc.Const.legacy let curried_acc modes arg_mode = Ctype.curry_mode modes (Mode.Alloc.zap_to_legacy arg_mode) -let mode_is_implied modes res_mode = +let mode_is_implied implied_modes res_mode = let snap = Btype.snapshot () in let implied = - match Mode.Alloc.equate (Mode.Alloc.of_const modes) res_mode with + match Mode.Alloc.equate (Mode.Alloc.of_const implied_modes) res_mode with | Ok () -> true | Error _ -> false in Btype.backtrack snap; implied -let read_arrow_modes modes typ = +let read_arrow_modes implied_modes typ = match Compat.get_desc typ with | Tarrow ((_, arg_mode, res_mode), _, res, _) -> let arg_modes = read_alloc_modes arg_mode in - let modes = curried_acc modes arg_mode in + let implied_modes = curried_acc implied_modes arg_mode in let res_is_arrow = match Compat.get_desc res with | Tarrow _ -> not (is_aliased (proxy res)) | _ -> false in let res_modes = - if res_is_arrow && mode_is_implied modes res_mode then [] + if res_is_arrow && mode_is_implied implied_modes res_mode then [] else read_alloc_modes res_mode in - (arg_modes, res_modes, modes) - | _ -> ([], [], modes) + (arg_modes, res_modes, implied_modes) + | _ -> ([], [], implied_modes) #else @@ -648,13 +648,13 @@ type modes = unit let legacy_modes : modes = () -let read_arrow_modes (modes : modes) _typ = ([], [], modes) +let read_arrow_modes (implied_modes : modes) _typ = ([], [], implied_modes) #endif let rec read_type_expr env typ = read_type_expr_modal env legacy_modes typ -and read_type_expr_modal env modes typ = +and read_type_expr_modal env implied_modes typ = let open TypeExpr in let px = proxy typ in if used_alias px then Var (name_of_type typ) @@ -689,8 +689,8 @@ and read_type_expr_modal env modes typ = | _ -> lbl, read_type_expr env arg in - let arg_modes, res_modes, modes = read_arrow_modes modes typ in - let res = read_type_expr_modal env modes res in + let arg_modes, res_modes, modes = read_arrow_modes implied_modes typ in + let res = read_type_expr_modal env implied_modes res in Arrow(lbl, (arg, arg_modes), (res, res_modes)) | Ttuple typs -> #if OCAML_VERSION >= (5,4,0) || defined OXCAML From 092d5a5d1163d1bff16a0d6659ea7647a6eccb47 Mon Sep 17 00:00:00 2001 From: Jon Ludlam Date: Thu, 27 Aug 2026 22:05:42 +0100 Subject: [PATCH 9/9] OxCaml: adapt modes to 5.2.0minus39 Remove 'Observing' that's gone in between minus31 and minus39 Co-Authored-By: Claude Opus 5 (1M context) --- src/loader/cmi.ml | 1 - test/generators/cases/oxcaml.mli | 3 --- test/generators/html/Oxcaml.html | 11 ----------- test/generators/latex/Oxcaml.tex | 2 -- test/generators/man/Oxcaml.3o | 7 ------- test/generators/markdown/Oxcaml.md | 5 ----- 6 files changed, 29 deletions(-) diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index cef0f31b04..b0cf333675 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -572,7 +572,6 @@ let tree_of_modes (modes : Mode.Alloc.Const.t) : string list = let portability = match modes.statefulness, modes.portability with | Stateless, Portable - | Observing, Shareable | Stateful, Nonportable -> None | _, _ -> Some modes.portability in diff --git a/test/generators/cases/oxcaml.mli b/test/generators/cases/oxcaml.mli index 61b39cfb6e..8b5ccd0938 100644 --- a/test/generators/cases/oxcaml.mli +++ b/test/generators/cases/oxcaml.mli @@ -407,9 +407,6 @@ val mode_local_unforkable : int @ local unforkable -> unit val mode_stateless : int @ stateless -> unit (** Statefulness mode. *) -val mode_observing : int @ observing -> unit -(** Statefulness mode. *) - val mode_stateful : int @ stateful -> unit (** Statefulness mode (identity when [portability] is at its default, not rendered). *) diff --git a/test/generators/html/Oxcaml.html b/test/generators/html/Oxcaml.html index 6a01015c55..b4a4a676ee 100644 --- a/test/generators/html/Oxcaml.html +++ b/test/generators/html/Oxcaml.html @@ -1717,17 +1717,6 @@

    Statefulness mode.

    -
    -
    - - - val mode_observing : - int @ observing -> - unit - - -

    Statefulness mode.

    -
    diff --git a/test/generators/latex/Oxcaml.tex b/test/generators/latex/Oxcaml.tex index 8ae5c07ffc..e3b29d5158 100644 --- a/test/generators/latex/Oxcaml.tex +++ b/test/generators/latex/Oxcaml.tex @@ -320,8 +320,6 @@ \subsubsection{All mode axes\label{Oxcaml--all-mode-axes}}% \medbreak \label{Oxcaml--val-mode_stateless}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateless : int @ stateless \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% \medbreak -\label{Oxcaml--val-mode_observing}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}observing : int @ observing \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode.\end{ocamlindent}% -\medbreak \label{Oxcaml--val-mode_stateful}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}stateful : int \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Statefulness mode (identity when \ocamlinlinecode{portability} is at its default, not rendered).\end{ocamlindent}% \medbreak \label{Oxcaml--val-mode_immutable}\ocamlcodefragment{\ocamltag{keyword}{val} mode\_\allowbreak{}immutable : int @ immutable \ocamltag{arrow}{$\rightarrow$} unit}\begin{ocamlindent}Visibility mode.\end{ocamlindent}% diff --git a/test/generators/man/Oxcaml.3o b/test/generators/man/Oxcaml.3o index 23cf7db859..9290c04198 100644 --- a/test/generators/man/Oxcaml.3o +++ b/test/generators/man/Oxcaml.3o @@ -958,13 +958,6 @@ Fork mode (identity for a local argument, not rendered)\. Statefulness mode\. .nf .sp -\f[CB]val\fR mode_observing : int @ observing \f[CB]\->\fR unit -.fi -.br -.ti +2 -Statefulness mode\. -.nf -.sp \f[CB]val\fR mode_stateful : int \f[CB]\->\fR unit .fi .br diff --git a/test/generators/markdown/Oxcaml.md b/test/generators/markdown/Oxcaml.md index d1f6dad452..132cd6b4c6 100644 --- a/test/generators/markdown/Oxcaml.md +++ b/test/generators/markdown/Oxcaml.md @@ -542,11 +542,6 @@ val mode_stateless : int @ stateless -> unit ``` Statefulness mode. -```ocaml -val mode_observing : int @ observing -> unit -``` -Statefulness mode. - ```ocaml val mode_stateful : int -> unit ```