Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Unreleased

- Support for OCaml 5.6 (@jonludlam, #1472)
- Support for OxCaml unboxed named types (@art-w, #1407)
- Support for OxCaml zero alloc definitions (@Leonidas-from-XIV, #1422, #1444)
- Remove requirement for ppx_expect in tests (@jonludlam, #1445)
Expand Down
2 changes: 1 addition & 1 deletion odoc.opam
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ depends: [
"cppo" {build & >= "1.1.0"}
"dune" {>= "3.21.0"}
"fpath" {>= "0.7.3"}
"ocaml" {>= "4.08.0" & < "5.6"}
"ocaml" {>= "4.08.0" & < "5.7"}
"tyxml" {>= "4.4.0"}
"fmt"
"crunch" {>= "1.4.1"}
Expand Down
22 changes: 21 additions & 1 deletion src/loader/cmi.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,18 @@ module Compat = struct
versions *)
let repr x = Transient_expr.repr x

#if OCAML_VERSION >= (5,6,0)
(** Since 5.6, abbreviation expansion happens in place in the type graph and
the original abbreviation is remembered in the [Texpand] edge that
replaced it. [Types.get_desc] walks past those edges and would hand us
the expanded type, so use the same accessor the compiler's own printer
uses ([Out_type.printer_get_desc]) to recover the abbreviation. *)
let get_desc ty = Btype.get_folded_desc ~keep_Tvar:true ty
let deep_occur = Btype.deep_occur
#else
let get_desc = Types.get_desc
let deep_occur = Ctype.deep_occur
#endif
let get_row_name = Types.row_name
let row_field_repr = Types.row_field_repr
let field_kind_repr = Types.field_kind_repr
Expand All @@ -69,6 +80,7 @@ module Compat = struct
type repr_type_node = Types.type_expr
let repr = Btype.repr
let get_desc x = (repr x).Types.desc
let deep_occur = Ctype.deep_occur
let get_row_name x = x.Types.row_name
let row_field_repr = Btype.row_field_repr
let field_kind_repr = Btype.field_kind_repr
Expand Down Expand Up @@ -313,6 +325,10 @@ let mark_type ty =
| Tsubst (ty,_) -> loop visited ty
#endif
| Tlink _ -> assert false
#if OCAML_VERSION >= (5,6,0)
(* [Compat.get_desc] walks past [Texpand] just as it does [Tlink]. *)
| Texpand _ -> assert false
#endif
#if defined OXCAML
| Tquote typ -> loop visited typ
| Tsplice typ -> loop visited typ
Expand Down Expand Up @@ -459,7 +475,7 @@ let rec mark_class_type params = function
let sty = Compat.self_type cty in
if is_row_visited (proxy sty)
|| List.exists aliasable params
|| List.exists (Ctype.deep_occur sty) tyl
|| List.exists (Compat.deep_occur sty) tyl
then mark_class_type params cty
else List.iter mark_type tyl
| Cty_signature sign ->
Expand Down Expand Up @@ -663,6 +679,10 @@ let rec read_type_expr env typ =

#endif
| Tlink _ -> assert false
#if OCAML_VERSION >= (5,6,0)
(* [Compat.get_desc] walks past [Texpand] just as it does [Tlink]. *)
| Texpand _ -> assert false
#endif
#if defined OXCAML
| Tquote typ -> Quote (read_type_expr env typ)
| Tsplice typ -> Splice (read_type_expr env typ)
Expand Down
5 changes: 5 additions & 0 deletions src/loader/cmt.ml
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,13 @@ and read_structure_item env parent item =
| Tstr_eval _ -> []
| Tstr_value(_, vbs) ->
read_value_bindings env parent vbs
#if OCAML_VERSION >= (5,6,0)
| Tstr_primitive pd ->
[Cmti.read_primitive_description env parent pd]
#else
| Tstr_primitive vd ->
[Cmti.read_value_description env parent vd]
#endif
| Tstr_type (rec_flag, decls) ->
let rec_flag =
match rec_flag with
Expand Down
54 changes: 54 additions & 0 deletions src/loader/cmti.ml
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,64 @@ let read_value_description env parent vd =
let doc = Doc_attr.attached_no_tag ~warnings_tag:env.warnings_tag container vd.val_attributes in
let type_ = read_core_type env container vd.val_desc in
let value =
#if OCAML_VERSION >= (5,6,0)
(* Since 5.6 externals have their own node, so a [val] is never one. *)
Value.Abstract
#else
match vd.val_prim with
| [] -> Value.Abstract
| primitives -> External primitives
#endif
in
let ext_attrs = Doc_attr.attrs_of_value_description vd.val_val in
let modalities = Cmi.read_value_descr_modalities vd.val_val in
Value { Value.id; source_loc; doc; type_; value; ext_attrs; modalities }

#if OCAML_VERSION >= (5,6,0)
(* Since 5.6 (RFC 44) [external] declarations have their own Typedtree node,
because they can now also be written as an alias of an existing primitive:
[external x : t = M.y], or [external x = M.y] with the type left implicit.
An alias carries no primitive strings of its own, so recover them from the
resolved [Types.value_description] the way the .cmi reader does. *)
let read_primitive_description env parent pd =
let open Signature in
let id = Env.find_value_identifier env.ident_env pd.prim_id in
let source_loc = None in
let container =
(parent : Identifier.Signature.t :> Identifier.LabelParent.t)
in
let doc =
Doc_attr.attached_no_tag ~warnings_tag:env.warnings_tag container
pd.prim_attributes
in
let type_ =
match pd.prim_kind with
| Tprim_decl (core_type, _) | Tprim_alias (Some core_type, _, _) ->
read_core_type env container core_type
| Tprim_alias (None, _, _) ->
(* No type written at the declaration site: use the inferred one. *)
Cmi.mark_type_expr pd.prim_val.val_type;
Cmi.read_type_expr env pd.prim_val.val_type
in
let value =
match pd.prim_kind with
| Tprim_decl (_, primitives) -> Value.External primitives
| Tprim_alias _ -> (
match pd.prim_val.val_kind with
| Val_prim desc ->
let open Primitive in
Value.External
(desc.prim_name
:: (match desc.prim_native_name with
| "" -> []
| name -> [ name ]))
| _ -> Value.Abstract)
in
let ext_attrs = Doc_attr.attrs_of_value_description pd.prim_val in
let modalities = Cmi.read_value_descr_modalities pd.prim_val in
Value { Value.id; source_loc; doc; type_; value; ext_attrs; modalities }
#endif

let read_type_parameter (ctyp, var_and_injectivity) =
let open TypeDecl in
let desc, kind =
Expand Down Expand Up @@ -804,6 +854,10 @@ and read_signature_item env parent item =
match item.sig_desc with
| Tsig_value vd ->
[read_value_description env parent vd]
#if OCAML_VERSION >= (5,6,0)
| Tsig_primitive pd ->
[read_primitive_description env parent pd]
#endif
| Tsig_type (rec_flag, decls) ->
let rec_flag =
match rec_flag with
Expand Down
8 changes: 8 additions & 0 deletions src/loader/cmti.mli
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ val read_value_description :
Typedtree.value_description ->
Odoc_model.Lang.Signature.item

#if OCAML_VERSION >= (5,6,0)
val read_primitive_description :
Cmi.env ->
Paths.Identifier.Signature.t ->
Typedtree.primitive_description ->
Odoc_model.Lang.Signature.item
#endif

val read_type_declarations :
Cmi.env ->
Paths.Identifier.Signature.t ->
Expand Down
11 changes: 10 additions & 1 deletion src/loader/ident_env.ml
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,11 @@ let rec extract_signature_tree_items : bool -> Typedtree.signature_item list ->
mds @ extract_signature_tree_items hide_item rest
#endif
| { sig_desc = Tsig_value {val_id; _}; sig_loc; _ } :: rest->
[`Value (val_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest
[`Value (val_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest
#if OCAML_VERSION >= (5,6,0)
| { sig_desc = Tsig_primitive {prim_id; _}; sig_loc; _ } :: rest->
[`Value (prim_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest
#endif
| { sig_desc = Tsig_modtype mtd; sig_loc; _} :: rest ->
[`ModuleType (mtd.mtd_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest
#if defined OXCAML
Expand Down Expand Up @@ -450,8 +454,13 @@ let rec extract_structure_tree_items : bool -> Typedtree.structure_item list ->
)) cltyps @ extract_structure_tree_items hide_item rest
| { str_desc = Tstr_open o; _ } :: rest ->
((extract_extended_open o) :> items list) @ extract_structure_tree_items hide_item rest
#if OCAML_VERSION >= (5,6,0)
| { str_desc = Tstr_primitive {prim_id; _}; str_loc; _ } :: rest ->
[`Value (prim_id, false, Some str_loc)] @ extract_structure_tree_items hide_item rest
#else
| { str_desc = Tstr_primitive {val_id; _}; str_loc; _ } :: rest ->
[`Value (val_id, false, Some str_loc)] @ extract_structure_tree_items hide_item rest
#endif
| { str_desc = Tstr_eval _; _} :: rest -> extract_structure_tree_items hide_item rest
#if defined OXCAML
| { str_desc = Tstr_jkind _; _ } :: rest -> extract_structure_tree_items hide_item rest
Expand Down
3 changes: 3 additions & 0 deletions src/loader/implementation.ml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ module Env = struct
| Tsig_exception _ | Tsig_modsubst _ | Tsig_open _ | Tsig_include _
| Tsig_class _ | Tsig_class_type _ | Tsig_attribute _ ->
()
#if OCAML_VERSION >= (5,6,0)
| Tsig_primitive _ -> ()
#endif
#if defined OXCAML
| Tsig_jkind _ -> ()
#endif
Expand Down
3 changes: 3 additions & 0 deletions src/model/compat.cppo.ml
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ let shape_info_of_cmt_infos : Cmt_format.cmt_infos -> (shape * uid_to_loc) optio
let open Typedtree in
function
| Value v -> v.val_loc
#if OCAML_VERSION >= (5,6,0)
| Primitive p -> p.prim_loc
#endif
| Value_binding vb -> vb.vb_pat.pat_loc
| Type t -> t.typ_loc
| Constructor c -> c.cd_loc
Expand Down
13 changes: 13 additions & 0 deletions test/generators/cases/ocaml_56.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(** Features introduced in OCaml 5.6. *)

type ext = external "gmp"
(** An external type declaration. *)

external classic : int -> int = "caml_classic" "caml_classic_native"
(** A classic external declaration. *)

external alias_with_type : int -> int = classic
(** A primitive alias declaring its type. *)

external alias_no_type = classic
(** A primitive alias leaving its type implicit. *)
1 change: 1 addition & 0 deletions test/generators/gen_rules/gen_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ let constraints =
("class_comments.mli", Min "4.08");
("functor_ml.ml", Min "4.14");
("ocaml_55.mli", Min "5.5");
("ocaml_56.mli", Min "5.6");
("oxcaml.mli", OxCaml);
("oxcaml_impl.ml", OxCaml);
]
Expand Down
60 changes: 60 additions & 0 deletions test/generators/html/Ocaml_56.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Ocaml_56 (Ocaml_56)</title><meta charset="utf-8"/>
<link rel="stylesheet" href="odoc.css"/>
<meta name="generator" content="odoc %%VERSION%%"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
<script src="highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body class="odoc">
<nav class="odoc-nav"><a href="index.html">Up</a> –
<a href="index.html">Index</a> &#x00BB; Ocaml_56
</nav>
<header class="odoc-preamble">
<h1>Module <code><span>Ocaml_56</span></code></h1>
<p>Features introduced in OCaml 5.6.</p>
</header>
<div class="odoc-content">
<div class="odoc-spec">
<div class="spec type anchored" id="type-ext">
<a href="#type-ext" class="anchor"></a>
<code><span><span class="keyword">type</span> ext</span></code>
</div><div class="spec-doc"><p>An external type declaration.</p></div>
</div>
<div class="odoc-spec">
<div class="spec value external anchored" id="val-classic">
<a href="#val-classic" class="anchor"></a>
<code>
<span><span class="keyword">val</span> classic :
<span>int <span class="arrow">&#45;&gt;</span></span> int
</span>
</code>
</div><div class="spec-doc"><p>A classic external declaration.</p></div>
</div>
<div class="odoc-spec">
<div class="spec value external anchored" id="val-alias_with_type">
<a href="#val-alias_with_type" class="anchor"></a>
<code>
<span><span class="keyword">val</span> alias_with_type :
<span>int <span class="arrow">&#45;&gt;</span></span> int
</span>
</code>
</div>
<div class="spec-doc"><p>A primitive alias declaring its type.</p></div>
</div>
<div class="odoc-spec">
<div class="spec value external anchored" id="val-alias_no_type">
<a href="#val-alias_no_type" class="anchor"></a>
<code>
<span><span class="keyword">val</span> alias_no_type :
<span>int <span class="arrow">&#45;&gt;</span></span> int
</span>
</code>
</div>
<div class="spec-doc"><p>A primitive alias leaving its type implicit.</p>
</div>
</div>
</div>
</body>
</html>
1 change: 1 addition & 0 deletions test/generators/html/ocaml_56.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ocaml_56.html
13 changes: 13 additions & 0 deletions test/generators/latex/Ocaml_56.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
\section{Module \ocamlinlinecode{Ocaml\_\allowbreak{}56}}\label{Ocaml_56}%
Features introduced in OCaml 5.6.

\label{Ocaml_56--type-ext}\ocamlcodefragment{\ocamltag{keyword}{type} ext}\begin{ocamlindent}An external type declaration.\end{ocamlindent}%
\medbreak
\label{Ocaml_56--val-classic}\ocamlcodefragment{\ocamltag{keyword}{val} classic : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}A classic external declaration.\end{ocamlindent}%
\medbreak
\label{Ocaml_56--val-alias_with_type}\ocamlcodefragment{\ocamltag{keyword}{val} alias\_\allowbreak{}with\_\allowbreak{}type : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}A primitive alias declaring its type.\end{ocamlindent}%
\medbreak
\label{Ocaml_56--val-alias_no_type}\ocamlcodefragment{\ocamltag{keyword}{val} alias\_\allowbreak{}no\_\allowbreak{}type : int \ocamltag{arrow}{$\rightarrow$} int}\begin{ocamlindent}A primitive alias leaving its type implicit.\end{ocamlindent}%
\medbreak


1 change: 1 addition & 0 deletions test/generators/latex/ocaml_56.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ocaml_56.tex
Loading
Loading