OCaml 5.5.0 released

31 min read Original article ↗

We have the pleasure of celebrating the birthday of Blaise Pascal by announcing the release of OCaml version 5.5.0.

Some of the highlights in OCaml 5.5.0 are:

Module-dependent Functions

Modules can now be used as function arguments in a form of lightweight functors.

For instance, we can define a function for printing a map generated by
the Map.Make functor:

let pp_map (module M: Map.S) pp_key pp_v ppf set =
  if M.is_empty set then
    Format.fprintf ppf "ø"
  else
   let pp_sep ppf () = Format.fprintf ppf ",@ " in
   let pp_binding ppf (k,v) =
     Format.fprintf ppf "@[%a@ =@ %a@]" pp_key k pp_v v
   in
   Format.fprintf ppf "@[{@ %a@ }@]"
     (Format.pp_print_seq ~pp_sep pp_binding) (M.to_seq set)

We can then apply this function on a string map

module String_map = Map.Make(String)

with

let () =
  let m = String_map.of_list ["Zero", "Zero"; "One", "Un"] in
  let pp_str = Format.pp_print_string in
  Format.printf "%a@."
  (pp_map (module String_map) pp_str pp_str) m

Compared to first-class modules, the type of the function pp_map

type 'a printer = Format.formatter -> 'a -> unit
val pp_map: (module M: Map.S) -> M.key printer -> 'a printer -> 'a M.t printer

is dependent over the value of the module S, and thus the function can only
applied over a statically known module:

let f (): (module Map.S) =
  if Random.bool () then
    (module Map.Make(Int))
  else
    (module Map.Make(Float))
let fail = pp_map (f ())
Error: This expression has type
        (module M : Map.S) ->
        (Format.formatter -> M.key -> unit) ->
        (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a M.t -> unit
      but an expression was expected of type (module Map.S) -> 'b
      The module M would escape its scope
This function is module-dependent. The dependency is preserved
when the function is passed a static module argument (module M : S)
or (module M). Its argument here is not static, so the type-checker
tried instead to change the function type to be non-dependent.

Relocatable Compiler

A compiler installation can now be moved or copied with no risk
of hard-to-debug errors due to mixing incompatible bytecode runtime interpreters.

In practice, this means that creating a local switch when there is a
global switch with the same compiler version and configuration
available can be done by cloning the global switch rather than
recompiling the whole compiler.

This should considerably reduce the time required to create
new local opam switches out-of-the-box.

Polymorphic Functions as Function Arguments

Higher-rank polymorphic functions can now be defined directly by
using an explicit type annotation in a function argument

let apply_map (map: 'a 'b. ('a -> 'b) -> 'a list -> 'b list) =
  map string_of_int [1;2;3], map List.singleton ["x"; "y"]
let _ = apply_map List.map

Previously defining such a function required going through either a record or an object
with a polymorphic field or methods

type map = { map: 'a 'b. ('a -> 'b) -> 'a list -> 'b list }
let apply_map {map} =
  map string_of_int [1;2;3], map List.singleton ["x"; "y"]

Search and Replace Substring Functions

The String module has been extended with many functions
for searching and replacing substrings inside a string.

let _true = String.includes ~affix:"aba" "abbaba"
let sentence = String.replace_all ~sub:"𝄽" ~by:"word" "A 𝄽 is re𝄽ed"

The substring search is using the 2-way string matching algorithm
which has the advantage of requiring constant space memory overhead
independently of the needle size.

Generalised Local Definitions

It is now always possible to define locally a type,
a class, a module type or any kind of item that can be defined
globally:

let mandelbrot n x =
  let type t = Converge | Escape of int in
  ...
  match orbit n x with
  | Converge -> 0
  | Exit_at n -> colorize n

External Types

When interfacing with foreign function libraries, it is now possible
to define external type

type int_gmp = external "mpz_t"
type float_gmp = external "mpf_t"

Compared to an abstract type definition, the external type name
“mpz_t” (resp. mpf_t) makes the type distinguishable from any
non-abstract types or external types with a different name.

In particular, this makes FFI types better behaved when combined with
Generalised Abstract Data Types (GADTs). For instance, The typechecker
is able to prove that

let ok: (int_gmp,[` A] ) Type.eq -> _ = function _ -> .

is a total function because the external type int_gmp is not compatible
with a polymorphic variant type.

Warning: Abstract types in the current module

The astute reader has probably noticed in the definition above that,
in OCaml 5.4.0, the typechecker does accept

type int_gmp
let ok: (int_gmp, [` A] ) Type.eq -> _ = function _ -> .

as total.

Indeed until OCaml 5.5.0, abstract types defined in the current module

type a
type b

were considered as unique and provably different

let f: 'x. (a,b) Type.eq -> 'x = function _ -> .

However, this special rule for local definition of abstract types was
very brittle. As soon as one moved outside of the current module, it
was no longer possible to prove that the types were different.

module M = struct
  type a
  type b
end
let fail: 'x. (M.a,M.b) Type.eq -> 'x = function _ -> .
Error: This match case could not be refuted.
      Here is an example of a value that would reach it: Equal

This special typechecking rule has been removed in OCaml 5.5.0. If you were relying on it,
for instance, because you used an abstract type as type-level label in a GADTs, you
can change your abstract type definition to a possibly private abbreviation of a polymorphic variant

type a = private [`A]
type b = [`B]

or a (possibly private) sum type

type a = A
type b = private B

If you were using an abstract type as both a type-level label and a FFI type, you
can now use an external type definition which will give you a provably distinct type
even outside of the current module.

GC improvements

Some of the ongoing work to improve the pacing of the garbage
collector has been integrated in OCaml 5.5.0, two of the important
changes in OCaml 5.5 GC are

  • the addition of a sweep-only phase at the start of major GC
  • the addition of an idle phase to smooth the behaviour of the GC
    at the start.

Many incremental changes

  • The Windows implementation is no more reliant on Winpthreads
  • Around 60 new standard library functions
  • Around 90 various improvements
  • A dozen of documentation updates
  • Around 40 bug fixes

Please report any unexpected behaviours on the OCaml issue
tracker
and post any questions or
comments you might have on our discussion forums.

The full list of changes can be found in the full changelog.

Happy hacking,
Florian Angeletti for the OCaml team.


Installation Instructions

The base compiler can be installed as an opam switch with the following commands:

opam update
opam switch create 5.5.0

The source code for the release is also directly available on:

Fine-Tuned Compiler Configuration

If you want to tweak the configuration of the compiler, you can switch to the option variant with:

opam update
opam switch create <switch_name> ocaml-variants.5.5.0+options <option_list>

where <option_list> is a space separated list of ocaml-option-* packages. For instance, for a flambda and no-flat-float-array switch:

opam switch create 5.5.0+flambda+nffa ocaml-variants.5.5.0+options ocaml-option-flambda ocaml-option-no-flat-float-array

Changes in OCaml 5.5.0

Language features:

  • (breaking change) #13681, #13682, #13683, #13684, #13275 :
    Introduce a new type (module M : S) -> t[M] that corresponds to
    module-dependent functions (also called: modular explicits).
    val mapM: (module M : Monad) (f : 'a → 'b M.t) : 'a list → 'b list M.t
    (Samuel Vivien review by Leo White, Gabriel Scherer, Florian Angeletti,
    Jacques Garrigue and Stephen Dolan)
  • #14040: generalize the constructs let module, let exception and let open
    to most other structure items, for example:
    let type t = … in …
    let type Effect.t += Yield in …
    (Nicolás Ojeda Bär, review by Valentin Gatien-Baron)

  • #13806: Enable the use of function parameters with polymorphic types.
    let extract (getter : 'a . 'a t → 'a) = …
    let runST (m : 's . ('s, 'a) ST.t) : 'a = …
    (Ulysse Gérard, Leo White, review by Florian Angeletti, Samuel Vivien, Gabriel
    Scherer and Jacques Garrigue)

  • (breaking change) #13712: Introduce a new kind Type_external and syntax
    type t = external "name" to discriminate external types from other types
    and each other. This PR turns primitive types into external and removes the
    past behavior of discriminating abstract types defined in the current module.
    (Takafumi Saikawa, Jacques Garrigue, review by Richard Eisenberg)

  • (breaking change) #14009: infix extension points/attributes appearing in local structure items,
    eg let module%foo[@bar] ... in ... are attached to the AST node of the
    corresponding structure item (similar to their global counterparts) and no
    longer to the enclosing let expression. Extension points/attributes that
    are to be attached to the enclosing let expression are to be written next to
    the let keyword, eg let%foo[@bar] module ... in .... The same holds for
    let exception and let open.
    (Nicolás Ojeda Bär, review by Gabriel Scherer)

  • #14029: Recognize %identity as nonexpansive
    (Stephen Dolan and Olivier Nicole, review by Hugo Heuzard, Jacques Garrigue,
    Jeremy Yallop, and Gabriel Scherer)

Standard library:

  • #13372: New Format and Printf printf-like functions that accept a
    heterogeneous list as arguments.
    Format.lprintf “@[%s@ %d@]@.” [ “x =”; 1 ]
    (Leonardo Santos, review by Florian Angeletti and Gabriel Scherer)

  • #14437: Add String.split_{first,last,all} and String.rsplit_all
    split_first: sep:string → string → (string * string) option
    split_all: sep:string → drop:(string → bool) → string → string list
    (Daniel Bünzli, review by Nicolás Ojeda Bär and Florian Angeletti)

  • #14436: Add String.replace_{first,last,all}
    replace_first: sub:string → by:string → ?start:int → string → string
    (Daniel Bünzli, review by Nicolás Ojeda Bär, Ali Caglayan and
    Florian Angeletti)

  • #14439: Add String.includes, to complete the trio:
    starts_with: prefix:string → string → bool
    ends_with: suffix:string → string → bool
    includes: affix:string → string → bool
    (Daniel Bünzli, review by Nicolás Ojeda Bär and Olivier Nicole)

  • #14381: Add String.find_{first,last}index, String.find{first,last},
    String.[r]find_all.
    find_first_index: (char → bool) → ?start:int → string → int option
    (Daniel Bünzli, review by Nicolás Ojeda Bär, Ali Caglayan and
    Florian Angeletti)

  • #14438: Add String.is_empty
    (Daniel Bünzli, review by Nicolás Ojeda Bär and Gabriel Scherer)

  • #14440: Add String.of_char
    (Daniel Bünzli, review by Nicolás Ojeda Bär and Gabriel Scherer)

  • #14352: Add String.{drop,take,cut}_{first,last}.
    take_first: int → string → string
    cut_first: int → string → string * string
    (Daniel Bünzli, review by David Allsopp, Nicolás Ojeda Bär and
    Vincent Laviron)

  • #14362: Add String.{drop,take,cut}_{first,last}_while
    drop_first_while: (char → bool) → string → string
    (Daniel Bünzli, review by Nicolás Ojeda Bär and David Allsopp)

  • #13916: Add Option.product and Option.Syntax.
    (Nicolás Ojeda Bär, review by Daniel Bünzli, Gabriel Scherer and David
    Allsopp)

  • #13995: Option.blend: ('a → 'a → 'a) → 'a option → 'a option → 'a option
    (Kate Deplaix, review by Daniel Bünzli, Gabriel Scherer,
    Nicolás Ojeda Bär, Florian Angeletti and Josh Berdine)

  • #13920: add Option.{for_all, exists}
    (Gabriel Scherer, review by Kate Deplaix, Nicolás Ojeda Bär, Richard Eisenberg
    and Jeremy Yallop)

  • #14185: List.split_map: ('a → 'b * 'c) → 'a list → 'b list * 'c list
    (Jeremy Yallop, review by Daniel Bünzli, Nicolás Ojeda Bär and Damien Doligez)

  • #14043, #14393: Lazy.Mutexed: simple mutex-protected lazy thunks,
    that may block the entire domain/thread on initialization races.
    (Gabriel Scherer, suggestion by Kate Deplaix and Pierre Chambart,
    review by KC Sivaramakrishnan, Florian Angeletti, Kate Deplaix
    and Daniel Bünzli)

  • #14118: Add {Set,Map}.S.is_singleton
    (Kate Deplaix, review by Daniel Bünzli, Vincent Laviron, Nicolás Ojeda Bär
    and Stephen Dolan)

  • #14060: Add Hashtbl.find_and_replace and Hashtbl.find_and_remove.
    find_and_replace: ('k, 'a) Hashtbl.t → 'k → 'a → 'a option
    find_and_remove: ('k, 'a) Hashtbl.t → 'k → 'a option
    (Sacha-Élie Ayoun, review by Nicolás Ojeda Bär and Gabriel Scherer)

  • #14227: Add List.filter_mapi.
    (Émile Trotignon, review by Nicolás Ojeda Bär, Jan Midtgaard and
    Damien Doligez)

  • #14432: Add floor division, ceil division, Euclidean division and remainder
    to the Int, Int32, Int64 and Nativeint modules: fdiv, cdiv, ediv.
    (Xavier Leroy, review by Ali Caglayan, Nicolás Ojeda Bär, Gabriel Scherer)

  • #14433: Add bit-counting functions leading_zeros, leading_sign_bits,
    trailing_zeros, bit_count, unsigned_bitsize, signed_bitsize
    to Int, Int32, Int64, and Nativeint
    (Xavier Leroy, review by Ali Caglayan and David Allsopp)

  • #10177: Seq.(delay : (unit → 'a t) → 'a t)
    (Gabriel Scherer, review by Jeremy Yallop and François Pottier)

  • #13343: Add Array.stable_sort_sub
    (François Pottier, review by Gabriel Scherer, Corentin Leruth and Nicolás
    Ojeda Bär)

  • #14363: Preserve the backtrace at exceptional domain termination. Domain.join
    on an exceptionally terminated domain re-raises the exception with the
    backtrace.
    (KC Sivaramakrishnan, report by Nathan Taylor, review by Gabriel Scherer,
    David Allsopp)

  • #13728: Add Sys.runtime_executable containing the full path (if available) to
    the currently executing runtime.
    (David Allsopp, review by Nicolás Ojeda Bär and Daniel Bünzli)

  • #14086: Add Domain.count.
    (Nicolás Ojeda Bär, review by David Allsopp, Gabriel Scherer, Daniel Bünzli
    and KC Sivaramakrishnan)

  • #12877: Dynarray.rev_iter, Dynarray.rev_iteri
    (Gabriel Scherer, review by Léo Andrès, Jeremy Yallop and Nicolás Ojeda Bär)

  • #14084: Future-proof Dynarray implementation against a smarter compiler
    (Basile Clément, review by Gabriel Scherer)

Tools:

  • #13728, #14014, #14243, #14244, #14245 : The compiler is now relocatable: it
    can be copied/moved to a different directory and everything still
    works.
    (David Allsopp, review by Nicolás Ojeda Bär, Jonah Beckford, Daniel Bünzli,
    Antonin Décimo, Damien Doligez, Hugo Heuzard, Samuel Hym,
    and Vincent Laviron)

  • #14055: Invert BUILD_PATH_PREFIX_MAP in directories loaded at startup
    by the debugger.
    (Pierre Boutillier, review by Gabriel Scherer and Daniel Bünzli)

  • (breaking change) #13638: ocamlmklib exits with code 4 if passed an unrecognised option, as it
    does with an unrecognised file.
    (David Allsopp, review by Antonin Décimo and Sébastien Hinderer)
  • #13941, #13961: Fix ocamltest variable handing.
    (Damien Doligez, report by Olivier Nicole, review by Gabriel Scherer)

  • #13962: Little ocamltest refactors. Fix error handling in C code,
    leaking file descriptors, code style.
    (Antonin Décimo, review by Gabriel Scherer)

  • #14059: Fix flaky TSan tests
    (Fabrice Buoro and Olivier Nicole, review by Gabriel Scherer)

  • #13966, #13969: Enable “generalized polymorphic install_printer
    in the debugger
    (Pierre Boutillier and Gabriel Scherer, review by Florian Angeletti)

  • #14063 : Debugger fallbacks to “looking for ‘module_name’.ml in the
    loadpath” when seeking source files. It improves hit rate for
    sources of installed packages.
    (Pierre Boutillier, review by Gabriel Scherer)

  • #14032, #14034: Update to and require FlexDLL 0.44.
    (Jan Midtgaard, Antonin Décimo, review by David Allsopp)

  • #14239: Fix #show_constructor when printing non-GADT type parameters
    (Takafumi Saikawa, Jacques Garrigue, review by Gabriel Scherer)

  • #14245: ocamlobjinfo now displays the runtime invoked by a bytecode
    executable (either from the RNTM section or by analysing the shebang lines)
    (David Allsopp, review by Damien Doligez and Samuel Hym)

Runtime system:

  • #14365: Add an Idle phase to the GC for better performance on small
    heaps and for a smooth start at program launch and after a forced major GC.
    (Damien Doligez, review by Stephen Dolan and Nick Barnes)

  • #13416: Implement concurrency primitives using WinAPI instead of
    winpthreads on Windows.
    (Antonin Décimo, review by Samuel Hym, Gabriel Scherer, Miod Vallat,
    B. Szilvasy, and Nicolás Ojeda Bär)

  • #14367: Gc.Tweak mechanism to allow named GC parameters
    (Stephen Dolan and Nick Barnes, review by Gabriel Scherer, David Allsopp and
    Antonin Décimo)

  • #13574, #13594: Generational scanning of stack frames for ARM 64 bits, POWER,
    and RISC-V. This reduces minor GC work in the presence of deep call stacks.
    (Xavier Leroy, review by Miod Vallat, Gabriel Scherer and Olivier Nicole)

  • #14416: Spawned domains will record backtraces if the parent domain has
    enabled it.
    (Nathan Taylor, review by Gabriel Scherer)

  • #14275: Add function caml_c_thread_register_in_domain, which makes it
    possible to register “C threads” in another domain than 0 (which is
    what caml_c_thread_register does). The function takes a domain unique
    ID in which to register the thread. The domain must be running
    when the function is called.
    (Jack Nørskov Jørgensen, review by Gabriel Scherer,
    Guillaume Munch-Maccagnoni)

  • #13616: Change free list representation in shared heap
    (Sadiq Jaffer, review by Damien Doligez)

  • #13580: Introduce sweep-only phase at start of major GC cycle,
    to reduce latent-garbage delay and therefore improve GC performance.
    (Stephen Dolan and Nick Barnes, review by KC Sivaramakrishnan)

  • #14053: Statmemprof: it is now possible to replace a profile in the
    current domain without stopping it in all domains.
    Added the function [Gc.Memprof.is_sampling].
    (Guillaume Munch-Maccagnoni, review by Gabriel Scherer)

  • #14168: restore the stack size statistic in Gc.stat and adds a new
    live_stacks_words field tracking the total size in words of live stacks.
    (Florian Angeletti, review by Gabriel Scherer)

  • #14189: Add runtime counters EV_C_MINOR_PROMOTED_WORDS and
    EV_C_MINOR_ALLOCATED_WORDS. EV_C_MINOR_PROMOTED_WORDS reports words promoted
    by minor GC and EV_C_MINOR_ALLOCATED_WORDS reports words allocated by minor
    GC. Both have equivalent bytes counters. Also updated the documentation for
    EV_C_MINOR_PROMOTED and EV_C_MINOR_ALLOCATED to qualify scope of the values
    reported as being per-domain.
    (Tim McGilchrist, review by Nick Barnes, Sadiq Jaffer and
    Gabriel Scherer)

  • (breaking change) #14243: Explicit relative paths in ld.conf (“.”, “..”, “./<path…>”,
    “../<path…>”) are interpreted as being relative to the directory ld.conf
    was loaded from, and the default ld.conf now uses relative paths, rather than
    embedding the absolute path to the Standard Library. The brave may continue to
    put implicit paths in ld.conf. The interpretation of CAML_LD_LIBRARY_PATH is
    unaltered. Additionally, ld.conf is loaded from all of $OCAMLLIB/ld.conf,
    $CAMLLIB/ld.conf and standard_library_default/ld.conf rather than just the
    first one found. ld.conf files with CRLF line endings are now consistently
    normalised on both Windows and Unix.
    (David Allsopp, review by Jonah Beckford, Damien Doligez and Hugo Heuzard)
  • #14244: Added --with-relative-libdir which allows the runtime and the
    compilers to locate the Standard Library relative to where the binaries
    themselves are installed, removing the absolute path previously embedded in
    caml_standard_library_default. Executables linked with ocamlc -custom now
    always attempt to load bytecode from the executable itself, rather than first
    trying argv[0].
    (David Allsopp, review by Jonah Beckford, Antonin Décimo, Damien Doligez,
    Samuel Hym and Vincent Laviron)

  • #14245: Introduce Runtime IDs for use in filename mangling to allow different
    configurations and different versions of the runtime system to coexist
    harmoniously on a single system. The IDs are used, along with the host
    triplet, to provide mangled names for the ocamlrun executable and its variants
    and the DLL versions of both the bytecode and native runtimes, with symlinks
    created for the original names. They are also used to mangle the names of stub
    libraries so that stub libraries compiled for a given configuration of the
    runtime will only be sought by that runtime. The behaviour is disabled by
    configuring with --disable-suffixing.
    (David Allsopp, review by Damien Doligez and Samuel Hym)

  • #12269, #12410, #13063: Fix unsafety, deadlocks, and/or leaks should
    rare errors happen during domain creation and thread
    creation/registration.
    (Guillaume Munch-Maccagnoni, review by Gabriel Scherer, B. Szilvasy,
    Miod Vallat)

  • #14337: Fix potential segfault due to the C callback mechanism dropping
    continuations without calling caml_continuation_use.
    (Max Slater, review by Nick Barnes and Stephen Dolan)

  • #14461: Fix racy socketpair on Windows. Address-in-use errors would sometimes
    occur when concurrent threads or processes were trying to create socketpairs.
    (Jessie Grosen, review by Antonin Décimo and Nicolás Ojeda Bär)

  • #14820: caml_ba_alloc must account for memory it allocated itself.
    CAML_BA_SUBARRAY (introduced in 5.2) with data=NULL would result in the
    Gc accounting for the allocation as 0 bytes, which can eventually lead
    to OOM. This condition never occurs in the compiler itself, but occurs
    in external C bindings that attempt to create a new bigarray in the
    shape of an existing one. For backwards compatibility ignore CAML_BA_SUBARRAY
    when data is NULL.
    (Edwin Török, review by Damien Doligez)

Type system:

  • #13781: Set scope of internal type nodes during abbreviation expansion
    rather than recursing during unification.
    (Jacques Garrigue, review by Gabriel Scherer)
  • (breaking change) #14066: catch invalid aliases introduced by signature constraints during
    merging rather than in subtyping:

      module X = struct end module F (_:sig end) = struct end
      module type T = (sig module X0 : sig end module X1 = X0 end)
        with module X0 := F(X)
    

    Before, it failed with a subtyping error. Now, it fails with a proper error,
    explaining that X1 would keep an invalid alias to F(X)
    (Clement Blaudeau, review by Florian Angeletti)

  • (breaking change) #14100: Do not ignore type-constraints and module-constraints when building
    the approximated signature of recursive modules. Ignoring those constraints
    resulted in incorrect (wrong set of fields, wrong shadowing between fields)
    approximated signatures, failing to typecheck, as in:

    module X0 : sig type t end
    module rec X : ((sig module A : sig end end) with module A := X0)
    and Y : sig type t = X.A.t end (* Unbound type constructor X.A.t *)
    

    Now, type and module constraints are properly merged during approximation ,
    reusing the infrastructure for normal merging of constraints, but disabling
    any wellformedness check.
    (Clement Blaudeau and Ryan Tjoa, review by Florian Angeletti)

  • #14327: Allow retyping as-patterns that contain existentials
    (completing #14229)
    (Jacques Garrigue and Takafumi Saikawa, reported by Olivier Nicole,
    review by Gabriel Scherer)

  • #14434, #14652: Protect check_counter_example_pat against polymorphic types,
    restoring type soundness.
    (Stephen Dolan and Jacques Garrigue, report and review by Alistair O’Brien)

Compiler user-interface and warnings:

  • #14330: add suggestions when a signature mismatch is likely to be be caused by
    spellchecking mistakes, for instance

        module M: sig type albatross end = struct type albatros end
    

    (Malo Monin, Florian Angeletti, review by Gabriel Scherer)

  • #12628: Improved error message for unsafe values: print out the full path for
    the value that is unsafe when they are detected during the compilation of
    recursive modules.
    (Shivam Acharya, review by Gabriel Scherer and Florian Angeletti)

  • #14076, 14111: error messages, add a short explanation for mismatched
    universal variables and universal quantifications.
    (Florian Angeletti, review by Gabriel Scherer)

  • #14126: Document the -i-variance option and +-, -+ variance indicators
    in the reference manual.
    (Takafumi Saikawa, review by Florian Angeletti)

  • #14146: add an error message for external declaration with
    a non-syntactic arity

     external fail: (int -> int as 'a) -> 'a = "%identity"
    

    rather than failing with an internal error.
    (Florian Angeletti, review by Gabriel Scherer)

  • #14147: print row types in error messages when they are a type constructor,
    e.g. < foo : int; .. as $0> when $0 is introduced by a GADT constructor
    (Stefan Muenzel, review by Jacques Garrigue and Florian Angeletti)

  • #14190: ocaml -e now also processes -init (previously it was ignored).
    (Emile Trotignon, review by David Allsopp and @ygrek)

  • #14225: do not raise unused-constructor warning on private
    constructor in type implementations, for example
    type safe = private Safe, which are typically used to
    create new fresh/generative types (here safe) to be used
    as GADT indices.
    (Gabriel Scherer, review by Nicolás Ojeda Bär and Florian Angeletti,
    report by Kate Deplaix)

  • #14244: Add -set-runtime-default option to the compiler, allowing the default
    value of the Standard Library location used by the runtime to be overridden.
    (Antonin Décimo, review by David Allsopp, Jonah Beckford, Damien Doligez and
    Samuel Hym)

  • #14245: New option -launch-method for ocamlc allows the method used by a
    tendered bytecode executable to locate the interpreter to be given explicitly.
    In particular, it makes it easier to specify the use of the executable
    launcher on Unix. New option -runtime-search extends the bytecode executable
    header to be able to search for the runtime interpreter in the directory
    containing the executable and in PATH rather than relying on a single
    hard-coded path.
    (David Allsopp, review by Damien Doligez and Samuel Hym)

  • #14315: enable -i-variance also for classes and extension constructors,
    and add description of -i-variance in manpages and the manual
    (Takafumi Saikawa, review by Florian Angeletti and Jacques Garrigue)

  • #14373: remove the OCAML_BINANNOT_WITHENV environment variable, and
    always strip typing environment in cmt files
    (Florian Angeletti, review by David Allsopp)

Other libraries:

  • #13700, #14454, #14715: Use POSIX thread-safe getgrnam_r, getgrgid_r,
    getpwnam_r, getpwuid_r, gmtime_r, localtime_r, getlogin_r, and fix mktime
    error checking.
    (Antonin Décimo, review by Florian Angeletti, David Allsopp, Stefan Muenzel,
    Gabriel Scherer, and Miod Vallat)

  • #14406: Better handling of address length for unix sockets, improving Haiku
    compatibility.
    (Sylvain Kerjean, review by Antonin Décimo and Nicolás Ojeda Bär)

  • (breaking change) #14046: On Windows, Unix.kill pid Sys.sigkill causes the receiving process
    to exit with code ERROR_PROCESS_ABORTED (1067) instead of 0.
    (Nicolás Ojeda Bär, review by Miod Vallat, Antonin Décimo and David Allsopp)
  • #14020: Add Unix.unsetenv.
    (Nicolás Ojeda Bär, review by Antonin Décimo and David Allsopp)

  • #13447: Symmetrize shared Sys and Unix functions. Apply fixes
    of #12072, #12184, #12320, and #13166, from Sys.rename to
    Unix.rename. Make caml_sys_close raise on error, allowing
    Filename.temp_file retries if close fails. Flush buffers when
    calling caml_sys_system_command on Windows. Error with EINVAL
    instead of ENOENT if the command string is not a valid C string.
    (Antonin Décimo, review by Gabriel Scherer and Nicolás Ojeda Bär)

  • #14310: Deprecate union sock_addr_union for struct sockaddr_storage
    and socklen_param_type for socklen_t.
    (Antonin Décimo, review by Nicolás Ojeda Bär, David Allsopp and Samuel Hym)

  • #14391: unload native dynlinked objects when an error occurs and it is safe to
    do so. (Fixes #14323)
    (Nicolás Ojeda Bär, review by Vincent Laviron)

Code generation and optimizations:

  • #14583: fix bug in linear scan spilling heuristic that in certain situations
    could lead to miscompilations.
    (Nicolás Ojeda Bär, review by Vincent Laviron)

Manual and documentation:

  • #14684, #14782, #14838: Improve ocamlc’s and ocamlopt’s manual pages and fix
    small issues in the manual
    (Samuel Hym, review by Florian Angeletti, Antonin Décimo, Gabriel Scherer and
    Nicolás Ojeda Bär)

  • #14397: Improve documentation of type-directed disambiguation of array
    literals
    (Alicia Michael, review by Olivier Nicole and Florian Angeletti)

  • #14293: Improve documentation of Runtime_events.Timestamp
    (Raphaël Proust, review by Gabriel Scherer)

  • #13747: Document support for native debugging with GDB and LLDB.
    (Tim McGilchrist, review by Daniel Bünzli, Samuel Hym, Olivier Nicole
    and Antonin Décimo)

  • (breaking change) #13975: documented the [@remove_aliases] built-in attribute for signatures
    (introduced by #1652 in 2018). Small refactor of the code that fetches the
    attribute.
    (Clement Blaudeau, review by Gabriel Scherer)
  • #14002: Add anchors to items and headings of the web version of the API
    documentation for easier linking.
    (Nicolás Ojeda Bär, report by Louis Roché, review by Gabriel Scherer and
    Florian Angeletti)

  • #14023: Add documentation for the [row_more] function.
    (Richard Eisenberg, review by Jacques Garrigue)

  • #14038: Fall back immediately to user-agent-defined fonts when web fonts
    fail to load.
    (toastal)

  • #14048: document modular explicits
    (Gabriel Scherer, review by Samuel Vivien, Ali Caglayan,
    Didier Remy and François Pottier)

  • #13994: document external types
    (Gabriel Scherer, review by Jan Midtgaard, Jacques Garrigue
    and Florian Angeletti)

  • #14077: Add missing item-attribute rule for let-bindings in documentation
    for attributes.
    (Shon Feder)

  • #14228: Trim leading spaces from first lines of LaTeX ocamldoccode
    environments.
    (Yukai Chou, review by Nicolás Ojeda Bär)

  • #14248: Added documentation about the way Domain.join triggers a
    Thread.join on the domain’s systhreads.
    (Raphaël Proust, review by Gabriel Scherer)

  • #14392: Fix AsciiDoc files, add more markup, xrefs, documentation.
    (Antonin Décimo, review by Gabriel Scherer and David Allsopp)

  • #13590: Document automatic command-line expansion of * and ? wildcards by
    the runtime under Windows.
    (Benjamin Sigonneau, review by Nicolás Ojeda Bär)

Internal/compiler-libs changes:

  • #13913: Use Blake128 as the hash function for the compiler’s CRCs
    (Vincent Laviron, review by Xavier Leroy and Gabriel Scherer)

  • #13911, #14117, #14127: Refactor the merging of signature constraints, by
    splitting the monolithic merge function into separate, specialized functions
    (for merging types, modules and module types) - sharing only the recursive
    part for handling deep constraints.
    (Clement Blaudeau, review by Florian Angeletti and Samuel Vivien, fix by Ryan
    Tjoa)

  • #14120, #14474, #14476: Associate Uids to items that don’t have a concrete
    definition; improves Merlin’s renaming for functors.
    (Ulysse Gérard, review by Florian Angeletti and Gabriel Scherer)

  • #13839, #14008: Reimplement let open, let module and let exception in
    terms of a single construct.
    (Nicolás Ojeda Bär, review by Gabriel Scherer, Samuel Vivien, Ulysse Gérard
    and Vincent Laviron, temporary regression reported by Antonio Monteiro)

  • #13980 Refactor type-approx and improve some errors’ locations.
    (Leo White, Ulysse Gérard, review by Samuel Vivien and Florian Angeletti)

  • #14024: Fix unterminated-string-initialization warnings from the C compiler.
    (Antonin Décimo, review by David Allsopp and Miod Vallat)

  • #14094: toplevel, simplify check on installed printer types
    (Florian Angeletti, review by Gabriel Scherer)

  • #13656, #14114, #14308: Use C99 stdint.h/inttypes.h fixed-width
    integer types and macros to define OCaml integers.
    (Antonin Décimo, review by Nick Barnes and David Allsopp)

  • #14148: Remove an unused field from package_type in typedtree
    (Samuel Vivien, review by Gabriel Scherer)

  • #14141: Rename cstrs to constraints when it refers to constraints to avoid
    confusing it with constructors.
    (Stefan Muenzel, review by Nicolás Ojeda Bär)

  • #14149: Distinguish (module M : S) from (module M) : (module S) in
    patterns.
    (Samuel Vivien, review by Gabriel Scherer)

  • #14161: refactor the STW-participants machinery to add an intermediate
    category of ‘parked’ domain structures.
    (Gabriel Scherer, review by Sivaramakrishnan)

  • #14198 Constraints on module unpacking are not ghost
    (Thomas Refis, review by Nicolás Ojeda Bär)

  • #14243: ocamlc now uses the same code as the runtime to parse ld.conf (via a
    C primitive), eliminating some highly obscure corner cases.
    (David Allsopp, review by Jonah Beckford, Damien Doligez and Hugo Heuzard)

  • #14260: Refactor Lambda.structured_constant to avoid duplicate
    representations for string constants
    (Vincent Laviron, review by Nicolás Ojeda Bär and Gabriel Scherer)

  • #14297, #14299: Avoid iterating on hash tables to produce types or terms
    (Vincent Laviron, review by Nicolás Ojeda Bär and Gabriel Scherer)

  • (breaking change) #14322: Remove leftover hacks for handling pattern constraints
    As a side effect, let rec (_ as x) = ... is now always rejected instead of
    being treated as equivalent to let rec x = ...
    (Vincent Laviron, review by Alistair O’Brien and Florian Angeletti)
  • #14331: Enforce current_level <= generic_level, and explain create_scope
    (Jacques Garrigue and Takafumi Saikawa, review by Gabriel Scherer)
  • (breaking change) #14388: Remove support for let rec (module M : S) = e1 in e2.
    (Alistair O’Brien, review by Vincent Laviron and Gabriel Scherer)
  • #14422: Refactoring an if match e with p1 -> true | p2 -> false then ...
    into a match in typetexp.
    (Samuel Vivien, review by Gabriel Scherer)

  • #13224: Clarify barriers and spin macros with delayed expansion.
    (Antonin Décimo, review by David Allsopp and Gabriel Scherer)

  • #14435, #14455, #14550: Add the not-root builtin ocamltest action. This
    allows to skip tests that fail if the current user is root (superuser).
    (Kate Deplaix, review by Gabriel Scherer, Nicolás Ojeda Bär, and
    Antonin Décimo)

  • #14457: Handle qualified M.{ x } patterns in untypeast
    (Basile Clément, review by Florian Angeletti)

Build system:

  • #13705, #14444: Cache test results of custom Autoconf tests from aclocal.m4.
    (Antonin Décimo, review by David Allsopp and Miod Vallat)

  • #13810: Support build of cross compilers to native freestanding targets
    (Samuel Hym, review by Antonin Décimo and Romain Calascibetta)

  • #14243: New configure option --with-additional-stublibsdir allows an
    additional directory to be added to the start of ld.conf. Additionally, the
    stublibs subdirectory is no longer created, nor added to ld.conf, when
    building OCaml with --disable-shared.
    (David Allsopp, review by Jonah Beckford, Damien Doligez and Hugo Heuzard)

  • #14244: When targeting native Windows on Cygwin or MSYS2, preserve
    backslashes in the supplied --prefix (in particular, backslashes instead of
    slashes will then be displayed by ocamlopt -config-var standard_library).
    If the supplied prefix contains a slash, then it is normalised, as
    previously.
    (David Allsopp, review by Jonah Beckford, Antonin Décimo, Damien Doligez and
    Samuel Hym)

  • #14245: New --enable-runtime-search configure option controls the
    -runtime-search option used to build the bytecode binaries in the compiler
    distribution. --enable-runtime-search-target controls the default value of
    -runtime-search used for bytecode executables produced by the compiler.
    (David Allsopp, review by Damien Doligez and Samuel Hym)

  • #14484: Set _WIN32_WINNT to require Windows 8/Server 2012 Windows header SDK
    support.
    (Antonin Décimo, review by David Allsopp)

Bug fixes:

  • #14123: Fix integer-overflow problems in heap compaction.
    (Nick Barnes, review by Antonin Décimo).

  • #14035: Fix the alignment of _Atomic long long unsigned int fields
    before GCC 11.1 on i686. Silence GCC note on newer versions.
    (Antonin Décimo, review by Sadiq Jaffer)

  • #14010: Fix miscompilation / liveness errors for string operations
    (Mark Shinwell, Xavier Clerc, review by Xavier Leroy and Gabriel Scherer)

  • #14036: Fix nontermination of cycle printing in recursive modules with
    -short-paths. Add error message for types considered abstract while
    checking recursive modules.
    (Brandon Stride, review by Florian Angeletti)

  • #14065: Fix function signature mismatch of __tsan_func_exit with GCC 15.
    Check in the configure step if the TSan provided internal builtins are the
    same as what we expect, introduce caml_tsan_* wrappers for the __tsan_*
    functions we use.
    (Hari Hara Naveen S, report by Hari Hara Naveen S,
    review by Gabriel Scherer, Antonin Décimo, Olivier Nicole)

  • #14071: Fix exception name in Dynlink.Error printer.
    (Etienne Millon, review by Nicolás Ojeda Bär)

  • #13853: Format breaks some line too early when there
    is a break hint at the end.
    (Florian Angeletti, review by Gabriel Scherer)

  • #10570: Fix handling of caml_sys_argv when exposed directly as an
    external
    (Keryan Didier, review by Vincent Laviron and Gabriel Scherer)

  • #14155: Audit unexecuted phrases in compiler expect tests and
    fix all occurrences
    (Stefan Muenzel, review by Gabriel Scherer)

  • #14163, #14176: add a filename location to the deprecation alert for implicit
    uses of libraries bundled with the compiler (unix,re,threads,dynlink)
    (Florian Angeletti, report by Ali Caglayan, review by Gabriel Scherer)

  • #14210: fix TSan-reported data race in weak pointers runtime
    (Gabriel Scherer and Damien Doligez, report by Olivier Nicole,
    review by KC Sivaramakrishnan)

  • #14213: Fix shadow-stack-related crashes with TSan
    (Olivier Nicole, report by Nathan Taylor, review by Gabriel Scherer and
    Stefan Muenzel)

  • #13658, #14181: Fix handling of recursive function types that can result
    in an unbounded number of labeled or optional arguments.
    (Stefan Muenzel, report by Samuel Vivien, review by Florian Angeletti)

  • #14255: Fix TSan bug with C calls that take many arguments
    (Olivier Nicole and Miod Vallat, report by Nathan Taylor, review by Gabriel
    Scherer)

  • #14230 : ocamltest fails to link test program with -custom in some cases
    (Damien Doligez, review by David Allsopp)

  • #14279: -dsource, preserve (mod) and other escaped infix keyword operators in
    the printed source wherever possible.
    (Florian Angeletti, review by Gabriel Scherer)

  • #14300, #14304: fix a race between memprof and the minor GC, detected by TSan
    (Gabriel Scherer, review by Stephen Dolan and Nick Barnes,
    report by Olivier Nicole)

  • #14332: Fix missing TSan instrumentation in subexpressions
    (Vincent Laviron, review by Gabriel Scherer and Olivier Nicole)

  • #14370, #14429: Fix headers for C++ inclusion.
    (Antonin Décimo, review by Gabriel Scherer)

  • #14417: Fix issue with nested packs on macOS.
    (Vincent Laviron, report by Kate Deplaix, review by Gabriel Scherer)

  • #14423: Fix detection of SetThreadDescription on 32-bit builds, meaning that
    Thread.set_current_thread_name now works on 32-bit MSVC and uses the correct
    mechanism on 32-bit mingw-w64.
    (David Allsopp, review by Antonin Décimo)

  • #14431: Enable native backend for DragonFly BSD. This builds ocamlopt on
    DragonFly.
    (Michael Neumann, review by Gabriel Scherer and Kate Deplaix)

  • #14495: Fix infix-tag bug in the minor collector which could cause SEGVs
    in multi-domain programs.
    (Nick Barnes, review by Gabriel Scherer)

  • #14519: Fix segfault when using Runtime_events under certain
    circumstances due to bad error checking when calling mmap().
    (Mark Elvers, review by Nicolás Ojeda Bär)

  • private, CVE-2026-28364, OSEC-2026-01: robustify intern.c
    (Xavier Leroy and Nicolás Ojeda Bär, review by Olivier Nicole, Mindy Preston,
    Edwin Török, and Gabriel Scherer)

  • #13693, #14514: s390x: fix heap corruption with libasmrun_shared.so caused
    by PLT lazy binding trampoline saving FPRs into OCaml’s fiber stack.
    Replace @PLT calls with GOT-indirect calls in the s390x code emitter.
    (Zane Hambly, review by David Allsopp and Xavier Leroy)

  • #14557, #12150, #14696: ensure that the self type of class cannot escape
    through type constraints.
    (Leo White, review by Florian Angeletti)

  • #14603, #14604: avoid Ctype.apply failures when mixing
    polymorphic types and unboxed constructors.
    (Gabriel Scherer and Stefan Muenzel, report by Brandon Stride,
    review by Florian Angeletti)

  • #14626, #14675: take in account module-dependent functions when
    determining if an optional argument is non-erasable.
    (Alistair O’Brien and Florian Angeletti, review by Gabriel Scherer)

  • #14635: Fix a bug in caml_floatarray_gather that would cause
    the result of Float.Array.sub, Float.Array.append, Float.Array.concat
    (when empty) not to be equal to [||].
    (Marc Lasson, review by Gabriel Scherer)

  • #14644, #14647: Fix a bug related to unhandled effects in bytecode.
    (Vincent Laviron, report by Thibaut Mattio,
    review by Nicolás Ojeda Bär, Stephen Dolan and Olivier Nicole)

  • #14655, #14691: check for size overflow in caml_ba_reshape
    (Stephen Dolan, review by Xavier Leroy)

  • #14667: enable application related warnings for module-dependent functions
    (Florian Angeletti, review by Gabriel Scherer)

  • #14690: Fix Name_type_mismatch error message when the expected type is an
    alias: print the expanded path on the right-hand side of the equality, not
    the alias twice.
    (Weixie Cui, review by Florian Angeletti)

  • #14349, #14718, #14722: runtime, fix in the orphaning of ephemerons
    (Gabriel Scherer, review by Olivier Nicole and Damien Doligez,
    report by Jan Midtgaard)

  • #14702: Fix hidden directory files leaking into the visible load path table.
    When a hidden directory contained a file whose basename was already present,
    the file could be incorrectly added to the visible table.
    (Hugo Heuzard, review by Florian Angeletti)

  • #14719, #14721: compute arity correctly for module-dependent function
    (Florian Angeletti, report by Jeremy Yallop, review by Stefan Muenzel)

  • #14760, #14802, #14846: Correct the detection of argument defaults in
    configure, fixing an incorrect error message when installing OCaml through
    opam on OpenSUSE with the site-config package installed.
    (David Allsopp, report and review by Edwin Török)

  • #14797: avoid dropping attributes attached to package types when pretty
    printing in surface syntax.
    (Chet Murthy, review by Nicolás Ojeda Bär)

  • #14853, CVE-2026-41083, OSEC-2026-05: fix quoting of filenames
    passed to Filename.quote_command on Windows.
    (David Allsopp, report by Andrew Nesbitt, review by Florian Angeletti)