diff --git a/CHANGES.md b/CHANGES.md
index cafd075db0..6cb5bf928b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -6,6 +6,7 @@
- Support for OxCaml modalities (@art-w, #1420)
- Support OxCaml 5.2.0minus39 (@jonludlam, #1469)
- Support for OxCaml modes (@art-w, #1454)
+- Fix OxCaml with-bounds for arbitrary types (@art-w, #1466)
### Fixed
- Remove requirement for ppx_expect in tests (@jonludlam, #1445)
diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml
index b0cf333675..5a91f648c4 100644
--- a/src/loader/cmi.ml
+++ b/src/loader/cmi.ml
@@ -489,22 +489,141 @@ let mark_class_declaration cld =
mark_class_type cld.cty_params cld.cty_type
#if defined OXCAML
-let read_parsetree_core_type (ct : Parsetree.core_type) =
+let rec read_longident_module (l : Longident.t) : Paths.Path.Module.t =
+ match l with
+ | Longident.Lident s -> `Root (ModuleName.make_std s)
+ | Longident.Ldot (p, s) -> `Dot (read_longident_module p, ModuleName.make_std s)
+ | Longident.Lapply (p, arg) ->
+ `Apply (read_longident_module p, read_longident_module arg)
+
+let read_longident_type (l : Longident.t) : Paths.Path.Type.t =
+ match l with
+ | Longident.Lident s -> `Resolved (`CoreType (TypeName.make_std s))
+ | Longident.Ldot (p, s) -> `DotT (read_longident_module p, TypeName.make_std s)
+ | Longident.Lapply _ -> `Resolved (`CoreType (TypeName.make_std "_"))
+
+let read_longident_class_type (l : Longident.t) : Paths.Path.ClassType.t =
+ match l with
+ | Longident.Ldot (p, s) -> `DotT (read_longident_module p, TypeName.make_std s)
+ | Longident.Lident s ->
+ `DotT (`Root (ModuleName.make_std "*"), TypeName.make_std s)
+ | Longident.Lapply _ ->
+ `DotT (`Root (ModuleName.make_std "*"), TypeName.make_std "_")
+
+let read_longident_module_type (l : Longident.t) : Paths.Path.ModuleType.t =
+ match l with
+ | Longident.Ldot (p, s) ->
+ `DotMT (read_longident_module p, ModuleTypeName.make_std s)
+ | Longident.Lident s ->
+ `DotMT (`Root (ModuleName.make_std "_"), ModuleTypeName.make_std s)
+ | Longident.Lapply _ ->
+ `DotMT (`Root (ModuleName.make_std "_"), ModuleTypeName.make_std "_")
+
+let read_parsetree_modes (modes : Parsetree.modes) =
+ List.map (fun (m : Parsetree.mode Location.loc) ->
+ let (Parsetree.Mode s) = m.txt in s)
+ modes
+
+let rec read_parsetree_core_type (ct : Parsetree.core_type) =
let open TypeExpr in
match ct.ptyp_desc with
| Ptyp_var (s, _) -> Var s
| Ptyp_any _ -> Any
- | _ -> failwith "invalid core type"
-
-let rec read_jkind_annotation (jk : Parsetree.jkind_annotation) =
+ | Ptyp_constr (lid, args) ->
+ Constr (read_longident_type lid.txt, List.map read_parsetree_core_type args)
+ | Ptyp_class (lid, args) ->
+ Class
+ (read_longident_class_type lid.txt, List.map read_parsetree_core_type args)
+ | Ptyp_tuple ts ->
+ Tuple (List.map (fun (lbl, t) -> (lbl, read_parsetree_core_type t)) ts)
+ | Ptyp_unboxed_tuple ts ->
+ Unboxed_tuple (List.map (fun (lbl, t) -> (lbl, read_parsetree_core_type t)) ts)
+ | Ptyp_arrow (lbl, arg, res, arg_modes, res_modes) ->
+ let lbl =
+ match lbl with
+ | Asttypes.Nolabel -> None
+ | Asttypes.Labelled s -> Some (Label s)
+ | Asttypes.Optional s -> Some (Optional s)
+ in
+ Arrow
+ ( lbl,
+ (read_parsetree_core_type arg, read_parsetree_modes arg_modes),
+ (read_parsetree_core_type res, read_parsetree_modes res_modes) )
+ | Ptyp_variant (fields, closed, labels) ->
+ let open TypeExpr.Polymorphic_variant in
+ let elements =
+ List.map
+ (fun (field : Parsetree.row_field) ->
+ match field.prf_desc with
+ | Rtag (name, constant, args) ->
+ Constructor
+ {
+ name = name.txt;
+ constant;
+ arguments = List.map read_parsetree_core_type args;
+ doc =
+ { Odoc_model.Comment.elements = []; warnings_tag = None };
+ }
+ | Rinherit ct -> Type (read_parsetree_core_type ct))
+ fields
+ in
+ let kind =
+ match (closed, labels) with
+ | Asttypes.Open, _ -> Open
+ | Asttypes.Closed, None -> Fixed
+ | Asttypes.Closed, Some ls -> Closed ls
+ in
+ Polymorphic_variant { kind; elements }
+ | Ptyp_object (fields, closed) ->
+ let open TypeExpr.Object in
+ let fields =
+ List.map
+ (fun (field : Parsetree.object_field) ->
+ match field.pof_desc with
+ | Otag (name, ct) ->
+ Method { name = name.txt; type_ = read_parsetree_core_type ct }
+ | Oinherit ct -> Inherit (read_parsetree_core_type ct))
+ fields
+ in
+ Object { fields; open_ = (closed = Asttypes.Open) }
+ | Ptyp_alias (ct, None, _) -> read_parsetree_core_type ct
+ | Ptyp_alias (ct, Some name, _) -> Alias (read_parsetree_core_type ct, name.txt)
+ | Ptyp_poly (vars, ct) ->
+ let vars =
+ List.map
+ (fun (name, jk) ->
+ let kind =
+ match jk with None -> Kind.Default | Some jk -> read_jkind_annotation jk
+ in
+ (name.txt, kind))
+ vars
+ in
+ Poly (vars, read_parsetree_core_type ct)
+ | Ptyp_package (lid, substs) ->
+ let path = read_longident_module_type lid.txt in
+ let substitutions =
+ List.map
+ (fun (frag, ct) ->
+ (Env.Fragment.read_type frag.txt, read_parsetree_core_type ct))
+ substs
+ in
+ Package { path; substitutions }
+ | Ptyp_quote ct -> Quote (read_parsetree_core_type ct)
+ | Ptyp_splice ct -> Splice (read_parsetree_core_type ct)
+ (* TODO: no good representation available atm *)
+ | Ptyp_of_kind _ | Ptyp_repr _ | Ptyp_extension _ -> Any
+ | Ptyp_open (_, ct) -> read_parsetree_core_type ct
+ | Ptyp_newlayout (_, ct) ->
+ (* layout-variable binder; odoc currently ignores the layout vars *)
+ read_parsetree_core_type ct
+
+and read_jkind_annotation (jk : Parsetree.jkind_annotation) =
let open Kind in
match jk.pjka_desc with
| Pjk_default -> Default
| Pjk_abbreviation (s, _) -> Abbreviation (Env.Fragment.read_type s.txt)
| Pjk_mod (jk', modes) ->
- let modes = List.map (fun (m : Parsetree.mode Location.loc) ->
- let (Parsetree.Mode s) = m.txt in s) modes in
- Mod (read_jkind_annotation jk', modes)
+ Mod (read_jkind_annotation jk', read_parsetree_modes modes)
| Pjk_with (jk', cty, modalities) ->
let ty = read_parsetree_core_type cty in
let modalities = List.map (fun (m : Parsetree.modality Location.loc) ->
diff --git a/test/generators/cases/oxcaml.mli b/test/generators/cases/oxcaml.mli
index 8b5ccd0938..3947f4e83a 100644
--- a/test/generators/cases/oxcaml.mli
+++ b/test/generators/cases/oxcaml.mli
@@ -88,6 +88,57 @@ type 'a t_with : immediate with 'a
type 'a t_with_modalities : immutable_data with 'a @@ portable contended
(** Kind annotation with a [with] constraint and modalities. *)
+type ('k, 'cmp) comparator
+(** Helper used in the [with] constraints below. *)
+
+type ('k, 'v, 'cmp) t_with_constr
+ : immutable_data with 'k with 'v with ('k, 'cmp) comparator
+(** A [with] constraint whose right-hand side is a parameterized type
+ constructor (as found in [base]'s [Map] module). *)
+
+type 'a t_with_app : immutable_data with 'a list
+(** A [with] constraint whose right-hand side applies a type constructor. *)
+
+type 'a t_with_arrow : immutable_data with ('a -> 'a)
+(** A [with] constraint whose right-hand side is an arrow type. *)
+
+type 'a t_with_arrow_modes : immutable_data with ('a -> 'a @ local)
+(** A [with] constraint whose right-hand side is an arrow type carrying a
+ mode. *)
+
+type 'a t_with_tuple : immutable_data with ('a * int)
+(** A [with] constraint whose right-hand side is a tuple type. *)
+
+module M_with : sig
+ type 'a t : immutable_data
+end
+(** Helper module used in the [with] constraint below. *)
+
+type 'a t_with_dot : immutable_data with 'a M_with.t
+(** A [with] constraint referring to a type through a module path
+ ([M.t]). *)
+
+module type Arg_with = sig
+ type s
+end
+
+module F_with (X : Arg_with) : sig
+ type 'a t : immutable_data
+end
+(** Helper functor used in the [with] constraint below. *)
+
+module X_with : Arg_with
+
+type 'a t_with_functor : immutable_data with 'a F_with(X_with).t
+(** A [with] constraint referring to a type through a functor application
+ ([F(X).t]). *)
+
+type 'a t_with_variant : immutable_data with [ `Foo of 'a | `Bar ]
+(** A [with] constraint whose right-hand side is a polymorphic variant. *)
+
+type 'a t_with_object : immutable_data with < foo : 'a >
+(** A [with] constraint whose right-hand side is an object type. *)
+
(** {1 Kind annotations on type aliases} *)
type t_alias : immediate = int
diff --git a/test/generators/html/Oxcaml-F_with-argument-1-X.html b/test/generators/html/Oxcaml-F_with-argument-1-X.html
new file mode 100644
index 0000000000..3a24cab11a
--- /dev/null
+++ b/test/generators/html/Oxcaml-F_with-argument-1-X.html
@@ -0,0 +1,27 @@
+
+
+
X (Oxcaml.F_with.X)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/generators/html/Oxcaml-F_with.html b/test/generators/html/Oxcaml-F_with.html
new file mode 100644
index 0000000000..0ab541e33b
--- /dev/null
+++ b/test/generators/html/Oxcaml-F_with.html
@@ -0,0 +1,51 @@
+
+
+ F_with (Oxcaml.F_with)
+
+
+
+
+
+
+
+
+
+
+
+
Parameters
+
+
+
Signature
+
+
+
+
+ type 'a t :
+ immutable_data
+
+
+
+
+
+
+
diff --git a/test/generators/html/Oxcaml-M_with.html b/test/generators/html/Oxcaml-M_with.html
new file mode 100644
index 0000000000..0e394cfe34
--- /dev/null
+++ b/test/generators/html/Oxcaml-M_with.html
@@ -0,0 +1,32 @@
+
+
+ M_with (Oxcaml.M_with)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ type 'a t :
+ immutable_data
+
+
+
+
+
+
+
diff --git a/test/generators/html/Oxcaml-X_with.html b/test/generators/html/Oxcaml-X_with.html
new file mode 100644
index 0000000000..5747085624
--- /dev/null
+++ b/test/generators/html/Oxcaml-X_with.html
@@ -0,0 +1,27 @@
+
+
+ X_with (Oxcaml.X_with)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/generators/html/Oxcaml-module-type-Arg_with.html b/test/generators/html/Oxcaml-module-type-Arg_with.html
new file mode 100644
index 0000000000..050de3f1a5
--- /dev/null
+++ b/test/generators/html/Oxcaml-module-type-Arg_with.html
@@ -0,0 +1,27 @@
+
+
+ Arg_with (Oxcaml.Arg_with)
+
+
+
+
+
+
+
+
+
+ Module type Oxcaml.Arg_with
+
+
+
+
diff --git a/test/generators/html/Oxcaml.html b/test/generators/html/Oxcaml.html
index b4a4a676ee..91cd5aaf5e 100644
--- a/test/generators/html/Oxcaml.html
+++ b/test/generators/html/Oxcaml.html
@@ -403,6 +403,245 @@
+
+
+
+
+ type
+ ('k, 'cmp) comparator
+
+
+
+
+
Helper used in the with constraints below.
+
+
+
+
+
+
+ type
+ ('k, 'v, 'cmp)
+ t_with_constr
+ :
+ (
+ (immutable_data with
+ 'k)
+ with
+ 'v)
+ with
+
+ ('k,
+ 'cmp)
+ comparator
+
+
+
+
+
+
A with constraint whose right-hand side is a
+ parameterized type constructor (as found in base's
+ Map module).
+
+
+
+
+
+
+
+ type 'a t_with_app
+ : immutable_data with
+ 'a list
+
+
+
+
+
A with constraint whose right-hand side applies
+ a type constructor.
+
+
+
+
+
+
+
+ type 'a t_with_arrow
+ : immutable_data with
+ 'a
+ ->
+ 'a
+
+
+
+
+
A with constraint whose right-hand side is an arrow
+ type.
+
+
+
+
+
+
+
+ type
+ 'a t_with_arrow_modes : immutable_data
+ with
+ 'a
+ ->
+ 'a @ local
+
+
+
+
+
A with constraint whose right-hand side is an arrow
+ type carrying a mode.
+
+
+
+
+
+
+
+ type 'a t_with_tuple
+ : immutable_data with
+ 'a * int
+
+
+
+
+
A with constraint whose right-hand side is a tuple type.
+
+
+
+
+
+
+
+ module
+ M_with
+
+ : sig ...
+ end
+
+
+
+
+
Helper module used in the with constraint below.
+
+
+
+
+
+
+ type 'a t_with_dot
+ : immutable_data with
+ 'a
+ M_with.t
+
+
+
+
+
+
A with constraint referring to a type through a
+ module path (M.t).
+
+
+
+
+
+
+
+ module
+ type
+ Arg_with
+
+ = sig ...
+ end
+
+
+
+
+
+
+
+
Helper functor used in the with constraint below.
+
+
+
+
+
+
+
+ type 'a t_with_functor
+ : immutable_data with
+ 'a
+ F_with(
+ X_with).t
+
+
+
+
+
+
A with constraint referring to a type through a
+ functor application (F(X).t).
+
+
+
+
+
+
+
+ type 'a t_with_variant
+ : immutable_data with
+ [ `Foo of 'a
+ | `Bar ]
+
+
+
+
+
+
A with constraint whose right-hand side is a polymorphic
+ variant.
+
+
+
+
+
+
+
+ type 'a t_with_object
+ : immutable_data with
+ < foo : 'a >
+
+
+
+
+
A with constraint whose right-hand side is an object
+ type.
+
+
+
Kind
annotations on type aliases
diff --git a/test/generators/html/oxcaml.targets b/test/generators/html/oxcaml.targets
index 77bc5f1da0..5d69622d32 100644
--- a/test/generators/html/oxcaml.targets
+++ b/test/generators/html/oxcaml.targets
@@ -1,4 +1,9 @@
Oxcaml.html
+Oxcaml-M_with.html
+Oxcaml-module-type-Arg_with.html
+Oxcaml-F_with.html
+Oxcaml-F_with-argument-1-X.html
+Oxcaml-X_with.html
Oxcaml-module-type-S.html
Oxcaml-M1.html
Oxcaml-M2.html
diff --git a/test/generators/latex/Oxcaml.F_with.tex b/test/generators/latex/Oxcaml.F_with.tex
new file mode 100644
index 0000000000..dae8c85542
--- /dev/null
+++ b/test/generators/latex/Oxcaml.F_with.tex
@@ -0,0 +1,11 @@
+\section{Module \ocamlinlinecode{Oxcaml.\allowbreak{}F\_\allowbreak{}with}}\label{Oxcaml-F_with}%
+Helper functor used in the \ocamlinlinecode{with} constraint below.
+
+\subsection{Parameters\label{Oxcaml-F_with--parameters}}%
+\label{Oxcaml-F_with--argument-1-X}\ocamlcodefragment{\ocamltag{keyword}{module} \hyperref[Oxcaml-F_with-argument-1-X]{\ocamlinlinecode{X}}}\label{Oxcaml-F_with-argument-1-X}\ocamlcodefragment{ : \ocamltag{keyword}{sig}}\begin{ocamlindent}\label{Oxcaml-F_with-argument-1-X--type-s}\ocamlcodefragment{\ocamltag{keyword}{type} s}\\
+\end{ocamlindent}%
+\ocamlcodefragment{\ocamltag{keyword}{end}}\\
+\subsection{Signature\label{Oxcaml-F_with--signature}}%
+\label{Oxcaml-F_with--type-t}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t : immutable\_\allowbreak{}data}\\
+
+
diff --git a/test/generators/latex/Oxcaml.X_with.tex b/test/generators/latex/Oxcaml.X_with.tex
new file mode 100644
index 0000000000..1421d27a13
--- /dev/null
+++ b/test/generators/latex/Oxcaml.X_with.tex
@@ -0,0 +1,4 @@
+\section{Module \ocamlinlinecode{Oxcaml.\allowbreak{}X\_\allowbreak{}with}}\label{Oxcaml-X_with}%
+\label{Oxcaml-X_with--type-s}\ocamlcodefragment{\ocamltag{keyword}{type} s}\\
+
+
diff --git a/test/generators/latex/Oxcaml.tex b/test/generators/latex/Oxcaml.tex
index e3b29d5158..2fd47c8b7f 100644
--- a/test/generators/latex/Oxcaml.tex
+++ b/test/generators/latex/Oxcaml.tex
@@ -68,6 +68,37 @@ \subsection{Kind annotations with \ocamlinlinecode{with} constraints\label{Oxcam
\medbreak
\label{Oxcaml--type-t_with_modalities}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}modalities : immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'a} @@ portable contended}\begin{ocamlindent}Kind annotation with a \ocamlinlinecode{with} constraint and modalities.\end{ocamlindent}%
\medbreak
+\label{Oxcaml--type-comparator}\ocamlcodefragment{\ocamltag{keyword}{type} ('k,\allowbreak{} 'cmp) comparator}\begin{ocamlindent}Helper used in the \ocamlinlinecode{with} constraints below.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_constr}\ocamlcodefragment{\ocamltag{keyword}{type} ('k,\allowbreak{} 'v,\allowbreak{} 'cmp)
+ t\_\allowbreak{}with\_\allowbreak{}constr : ((immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'k}) \ocamltag{keyword}{with} \ocamltag{type-var}{'v}) \ocamltag{keyword}{with} (\ocamltag{type-var}{'k},\allowbreak{} \ocamltag{type-var}{'cmp}) comparator}\begin{ocamlindent}A \ocamlinlinecode{with} constraint whose right-hand side is a parameterized type constructor (as found in \ocamlinlinecode{base}'s \ocamlinlinecode{Map} module).\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_app}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}app : immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'a} list}\begin{ocamlindent}A \ocamlinlinecode{with} constraint whose right-hand side applies a type constructor.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_arrow}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}arrow : immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a}}\begin{ocamlindent}A \ocamlinlinecode{with} constraint whose right-hand side is an arrow type.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_arrow_modes}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}arrow\_\allowbreak{}modes : immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a} @ local}\begin{ocamlindent}A \ocamlinlinecode{with} constraint whose right-hand side is an arrow type carrying a mode.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_tuple}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}tuple : immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'a} * int}\begin{ocamlindent}A \ocamlinlinecode{with} constraint whose right-hand side is a tuple type.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--module-M_with}\ocamlcodefragment{\ocamltag{keyword}{module} \hyperref[Oxcaml-M_with]{\ocamlinlinecode{M\_\allowbreak{}with}}}\label{Oxcaml-M_with}\ocamlcodefragment{ : \ocamltag{keyword}{sig}}\begin{ocamlindent}\label{Oxcaml-M_with--type-t}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t : immutable\_\allowbreak{}data}\\
+\end{ocamlindent}%
+\ocamlcodefragment{\ocamltag{keyword}{end}}\begin{ocamlindent}Helper module used in the \ocamlinlinecode{with} constraint below.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_dot}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}dot : immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'a} \hyperref[xref-unresolved]{\ocamlinlinecode{M\_\allowbreak{}with}}.\allowbreak{}t}\begin{ocamlindent}A \ocamlinlinecode{with} constraint referring to a type through a module path (\ocamlinlinecode{M.\allowbreak{}t}).\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--module-type-Arg_with}\ocamlcodefragment{\ocamltag{keyword}{module} \ocamltag{keyword}{type} \hyperref[Oxcaml-module-type-Arg_with]{\ocamlinlinecode{Arg\_\allowbreak{}with}}}\label{Oxcaml-module-type-Arg_with}\ocamlcodefragment{ = \ocamltag{keyword}{sig}}\begin{ocamlindent}\label{Oxcaml-module-type-Arg_with--type-s}\ocamlcodefragment{\ocamltag{keyword}{type} s}\\
+\end{ocamlindent}%
+\ocamlcodefragment{\ocamltag{keyword}{end}}\\
+\label{Oxcaml--module-F_with}\ocamlcodefragment{\ocamltag{keyword}{module} \hyperref[Oxcaml-F_with]{\ocamlinlinecode{F\_\allowbreak{}with}}}\ocamlcodefragment{ (\hyperref[Oxcaml-F_with-argument-1-X]{\ocamlinlinecode{X}} : \hyperref[Oxcaml-module-type-Arg_with]{\ocamlinlinecode{Arg\_\allowbreak{}with}}) : \ocamltag{keyword}{sig} .\allowbreak{}.\allowbreak{}.\allowbreak{} \ocamltag{keyword}{end}}\begin{ocamlindent}Helper functor used in the \ocamlinlinecode{with} constraint below.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--module-X_with}\ocamlcodefragment{\ocamltag{keyword}{module} \hyperref[Oxcaml-X_with]{\ocamlinlinecode{X\_\allowbreak{}with}}}\ocamlcodefragment{ : \hyperref[Oxcaml-module-type-Arg_with]{\ocamlinlinecode{Arg\_\allowbreak{}with}}}\\
+\label{Oxcaml--type-t_with_functor}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}functor : immutable\_\allowbreak{}data \ocamltag{keyword}{with} \ocamltag{type-var}{'a} \hyperref[xref-unresolved]{\ocamlinlinecode{F\_\allowbreak{}with}}(\hyperref[xref-unresolved]{\ocamlinlinecode{X\_\allowbreak{}with}}).\allowbreak{}t}\begin{ocamlindent}A \ocamlinlinecode{with} constraint referring to a type through a functor application (\ocamlinlinecode{F(X).\allowbreak{}t}).\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_variant}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}variant : immutable\_\allowbreak{}data \ocamltag{keyword}{with} [ `Foo of \ocamltag{type-var}{'a} | `Bar ]}\begin{ocamlindent}A \ocamlinlinecode{with} constraint whose right-hand side is a polymorphic variant.\end{ocamlindent}%
+\medbreak
+\label{Oxcaml--type-t_with_object}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t\_\allowbreak{}with\_\allowbreak{}object : immutable\_\allowbreak{}data \ocamltag{keyword}{with} < foo : \ocamltag{type-var}{'a} >}\begin{ocamlindent}A \ocamlinlinecode{with} constraint whose right-hand side is an object type.\end{ocamlindent}%
+\medbreak
\subsection{Kind annotations on type aliases\label{Oxcaml--kind-annotations-on-type-aliases}}%
\label{Oxcaml--type-t_alias}\ocamlcodefragment{\ocamltag{keyword}{type} t\_\allowbreak{}alias : immediate = int}\begin{ocamlindent}Has both a kind annotation and a manifest.\end{ocamlindent}%
\medbreak
@@ -364,4 +395,6 @@ \subsubsection{Modes in type definitions\label{Oxcaml--modes-in-type-definitions
\end{ocamltabular}%
\\
+\input{Oxcaml.F_with.tex}
+\input{Oxcaml.X_with.tex}
\input{Oxcaml.M1.tex}
diff --git a/test/generators/latex/oxcaml.targets b/test/generators/latex/oxcaml.targets
index 7f76144fb3..d2d076e435 100644
--- a/test/generators/latex/oxcaml.targets
+++ b/test/generators/latex/oxcaml.targets
@@ -1,2 +1,4 @@
Oxcaml.tex
+Oxcaml.F_with.tex
+Oxcaml.X_with.tex
Oxcaml.M1.tex
diff --git a/test/generators/link.dune.inc b/test/generators/link.dune.inc
index 5efe5a1677..52ec09429d 100644
--- a/test/generators/link.dune.inc
+++ b/test/generators/link.dune.inc
@@ -11948,6 +11948,11 @@
(rule
(targets
Oxcaml.html.gen
+ Oxcaml-M_with.html.gen
+ Oxcaml-module-type-Arg_with.html.gen
+ Oxcaml-F_with.html.gen
+ Oxcaml-F_with-argument-1-X.html.gen
+ Oxcaml-X_with.html.gen
Oxcaml-module-type-S.html.gen
Oxcaml-M1.html.gen
Oxcaml-M2.html.gen
@@ -11971,6 +11976,38 @@
(action
(diff Oxcaml.html Oxcaml.html.gen))
(enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-M_with.html Oxcaml-M_with.html.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff
+ Oxcaml-module-type-Arg_with.html
+ Oxcaml-module-type-Arg_with.html.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-F_with.html Oxcaml-F_with.html.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-F_with-argument-1-X.html Oxcaml-F_with-argument-1-X.html.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-X_with.html Oxcaml-X_with.html.gen))
+ (enabled_if %{ocaml-config:ox}))
(rule
(alias runtest)
(package odoc)
@@ -12016,7 +12053,11 @@
(subdir
latex
(rule
- (targets Oxcaml.tex.gen Oxcaml.M1.tex.gen)
+ (targets
+ Oxcaml.tex.gen
+ Oxcaml.F_with.tex.gen
+ Oxcaml.X_with.tex.gen
+ Oxcaml.M1.tex.gen)
(package odoc)
(action
(run odoc latex-generate -o . --extra-suffix gen %{dep:../oxcaml.odocl}))
@@ -12027,6 +12068,18 @@
(action
(diff Oxcaml.tex Oxcaml.tex.gen))
(enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml.F_with.tex Oxcaml.F_with.tex.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml.X_with.tex Oxcaml.X_with.tex.gen))
+ (enabled_if %{ocaml-config:ox}))
(rule
(alias runtest)
(package odoc)
@@ -12054,7 +12107,14 @@
(subdir
man
(rule
- (targets Oxcaml.3o.gen Oxcaml.M1.3o.gen Oxcaml.M2.3o.gen Oxcaml.M3.3o.gen)
+ (targets
+ Oxcaml.3o.gen
+ Oxcaml.M_with.3o.gen
+ Oxcaml.F_with.3o.gen
+ Oxcaml.X_with.3o.gen
+ Oxcaml.M1.3o.gen
+ Oxcaml.M2.3o.gen
+ Oxcaml.M3.3o.gen)
(package odoc)
(action
(run odoc man-generate -o . --extra-suffix gen %{dep:../oxcaml.odocl}))
@@ -12065,6 +12125,24 @@
(action
(diff Oxcaml.3o Oxcaml.3o.gen))
(enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml.M_with.3o Oxcaml.M_with.3o.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml.F_with.3o Oxcaml.F_with.3o.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml.X_with.3o Oxcaml.X_with.3o.gen))
+ (enabled_if %{ocaml-config:ox}))
(rule
(alias runtest)
(package odoc)
@@ -12106,6 +12184,11 @@
(rule
(targets
Oxcaml.md.gen
+ Oxcaml-M_with.md.gen
+ Oxcaml-module-type-Arg_with.md.gen
+ Oxcaml-F_with.md.gen
+ Oxcaml-F_with-argument-1-X.md.gen
+ Oxcaml-X_with.md.gen
Oxcaml-module-type-S.md.gen
Oxcaml-M1.md.gen
Oxcaml-M2.md.gen
@@ -12127,6 +12210,36 @@
(action
(diff Oxcaml.md Oxcaml.md.gen))
(enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-M_with.md Oxcaml-M_with.md.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-module-type-Arg_with.md Oxcaml-module-type-Arg_with.md.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-F_with.md Oxcaml-F_with.md.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-F_with-argument-1-X.md Oxcaml-F_with-argument-1-X.md.gen))
+ (enabled_if %{ocaml-config:ox}))
+ (rule
+ (alias runtest)
+ (package odoc)
+ (action
+ (diff Oxcaml-X_with.md Oxcaml-X_with.md.gen))
+ (enabled_if %{ocaml-config:ox}))
(rule
(alias runtest)
(package odoc)
diff --git a/test/generators/man/Oxcaml.3o b/test/generators/man/Oxcaml.3o
index 9290c04198..29463c801c 100644
--- a/test/generators/man/Oxcaml.3o
+++ b/test/generators/man/Oxcaml.3o
@@ -230,6 +230,100 @@ Kind annotation with a with constraint\.
Kind annotation with a with constraint and modalities\.
.nf
.sp
+\f[CB]type\fR ('k, 'cmp) comparator
+.fi
+.br
+.ti +2
+Helper used in the with constraints below\.
+.nf
+.sp
+\f[CB]type\fR ('k, 'v, 'cmp)
+ t_with_constr : ((immutable_data \f[CB]with\fR \f[CB]'k\fR) \f[CB]with\fR \f[CB]'v\fR) \f[CB]with\fR (\f[CB]'k\fR, \f[CB]'cmp\fR) comparator
+.fi
+.br
+.ti +2
+A with constraint whose right-hand side is a parameterized type constructor (as found in base's Map module)\.
+.nf
+.sp
+\f[CB]type\fR 'a t_with_app : immutable_data \f[CB]with\fR \f[CB]'a\fR list
+.fi
+.br
+.ti +2
+A with constraint whose right-hand side applies a type constructor\.
+.nf
+.sp
+\f[CB]type\fR 'a t_with_arrow : immutable_data \f[CB]with\fR \f[CB]'a\fR \f[CB]\->\fR \f[CB]'a\fR
+.fi
+.br
+.ti +2
+A with constraint whose right-hand side is an arrow type\.
+.nf
+.sp
+\f[CB]type\fR 'a t_with_arrow_modes : immutable_data \f[CB]with\fR \f[CB]'a\fR \f[CB]\->\fR \f[CB]'a\fR @ local
+.fi
+.br
+.ti +2
+A with constraint whose right-hand side is an arrow type carrying a mode\.
+.nf
+.sp
+\f[CB]type\fR 'a t_with_tuple : immutable_data \f[CB]with\fR \f[CB]'a\fR * int
+.fi
+.br
+.ti +2
+A with constraint whose right-hand side is a tuple type\.
+.nf
+.sp
+\f[CB]module\fR M_with : \f[CB]sig\fR \.\.\. \f[CB]end\fR
+.fi
+.br
+.ti +2
+Helper module used in the with constraint below\.
+.nf
+.sp
+\f[CB]type\fR 'a t_with_dot : immutable_data \f[CB]with\fR \f[CB]'a\fR M_with\.t
+.fi
+.br
+.ti +2
+A with constraint referring to a type through a module path (M\.t)\.
+.nf
+.sp
+\f[CB]module\fR \f[CB]type\fR Arg_with = \f[CB]sig\fR
+.br
+.ti +2
+\f[CB]type\fR s
+.br
+\f[CB]end\fR
+.sp
+\f[CB]module\fR F_with (X : Arg_with) : \f[CB]sig\fR \.\.\. \f[CB]end\fR
+.fi
+.br
+.ti +2
+Helper functor used in the with constraint below\.
+.nf
+.sp
+\f[CB]module\fR X_with : Arg_with
+.sp
+\f[CB]type\fR 'a t_with_functor : immutable_data \f[CB]with\fR \f[CB]'a\fR F_with(X_with)\.t
+.fi
+.br
+.ti +2
+A with constraint referring to a type through a functor application (F(X)\.t)\.
+.nf
+.sp
+\f[CB]type\fR 'a t_with_variant : immutable_data \f[CB]with\fR [ `Foo of \f[CB]'a\fR | `Bar ]
+.fi
+.br
+.ti +2
+A with constraint whose right-hand side is a polymorphic variant\.
+.nf
+.sp
+\f[CB]type\fR 'a t_with_object : immutable_data \f[CB]with\fR < foo : \f[CB]'a\fR >
+.fi
+.br
+.ti +2
+A with constraint whose right-hand side is an object type\.
+.nf
+.sp
.in 3
\fB6 Kind annotations on type aliases\fR
.in
diff --git a/test/generators/man/Oxcaml.F_with.3o b/test/generators/man/Oxcaml.F_with.3o
new file mode 100644
index 0000000000..8cd2eb7699
--- /dev/null
+++ b/test/generators/man/Oxcaml.F_with.3o
@@ -0,0 +1,33 @@
+
+.TH F_with 3 "" "Odoc" "OCaml Library"
+.SH Name
+Oxcaml\.F_with
+.SH Synopsis
+.sp
+.in 2
+\fBModule Oxcaml\.F_with\fR
+.in
+.sp
+.fi
+Helper functor used in the with constraint below\.
+.nf
+.SH Documentation
+.sp
+.nf
+.sp
+.in 3
+\fB1 Parameters\fR
+.in
+.sp
+\f[CB]module\fR X : \f[CB]sig\fR
+.br
+.ti +2
+\f[CB]type\fR s
+.br
+\f[CB]end\fR
+.sp
+.in 3
+\fB2 Signature\fR
+.in
+.sp
+\f[CB]type\fR 'a t : immutable_data
diff --git a/test/generators/man/Oxcaml.M_with.3o b/test/generators/man/Oxcaml.M_with.3o
new file mode 100644
index 0000000000..5d8fe49142
--- /dev/null
+++ b/test/generators/man/Oxcaml.M_with.3o
@@ -0,0 +1,17 @@
+
+.TH M_with 3 "" "Odoc" "OCaml Library"
+.SH Name
+Oxcaml\.M_with
+.SH Synopsis
+.sp
+.in 2
+\fBModule Oxcaml\.M_with\fR
+.in
+.sp
+.fi
+Helper module used in the with constraint below\.
+.nf
+.SH Documentation
+.sp
+.nf
+\f[CB]type\fR 'a t : immutable_data
diff --git a/test/generators/man/Oxcaml.X_with.3o b/test/generators/man/Oxcaml.X_with.3o
new file mode 100644
index 0000000000..40921be59a
--- /dev/null
+++ b/test/generators/man/Oxcaml.X_with.3o
@@ -0,0 +1,14 @@
+
+.TH X_with 3 "" "Odoc" "OCaml Library"
+.SH Name
+Oxcaml\.X_with
+.SH Synopsis
+.sp
+.in 2
+\fBModule Oxcaml\.X_with\fR
+.in
+.sp
+.SH Documentation
+.sp
+.nf
+\f[CB]type\fR s
diff --git a/test/generators/man/oxcaml.targets b/test/generators/man/oxcaml.targets
index 3d3984495e..4ed49cfa3b 100644
--- a/test/generators/man/oxcaml.targets
+++ b/test/generators/man/oxcaml.targets
@@ -1,4 +1,7 @@
Oxcaml.3o
+Oxcaml.M_with.3o
+Oxcaml.F_with.3o
+Oxcaml.X_with.3o
Oxcaml.M1.3o
Oxcaml.M2.3o
Oxcaml.M3.3o
diff --git a/test/generators/markdown/Oxcaml-F_with-argument-1-X.md b/test/generators/markdown/Oxcaml-F_with-argument-1-X.md
new file mode 100644
index 0000000000..92a764b143
--- /dev/null
+++ b/test/generators/markdown/Oxcaml-F_with-argument-1-X.md
@@ -0,0 +1,6 @@
+
+# Parameter `F_with.X`
+
+```ocaml
+type s
+```
\ No newline at end of file
diff --git a/test/generators/markdown/Oxcaml-F_with.md b/test/generators/markdown/Oxcaml-F_with.md
new file mode 100644
index 0000000000..09431e9e41
--- /dev/null
+++ b/test/generators/markdown/Oxcaml-F_with.md
@@ -0,0 +1,17 @@
+
+# Module `Oxcaml.F_with`
+
+Helper functor used in the `with` constraint below.
+
+
+## Parameters
+
+```ocaml
+module X : Arg_with
+```
+
+## Signature
+
+```ocaml
+type 'a t : immutable_data
+```
\ No newline at end of file
diff --git a/test/generators/markdown/Oxcaml-M_with.md b/test/generators/markdown/Oxcaml-M_with.md
new file mode 100644
index 0000000000..5ef9c6966d
--- /dev/null
+++ b/test/generators/markdown/Oxcaml-M_with.md
@@ -0,0 +1,8 @@
+
+# Module `Oxcaml.M_with`
+
+Helper module used in the `with` constraint below.
+
+```ocaml
+type 'a t : immutable_data
+```
\ No newline at end of file
diff --git a/test/generators/markdown/Oxcaml-X_with.md b/test/generators/markdown/Oxcaml-X_with.md
new file mode 100644
index 0000000000..b5dba01c15
--- /dev/null
+++ b/test/generators/markdown/Oxcaml-X_with.md
@@ -0,0 +1,6 @@
+
+# Module `Oxcaml.X_with`
+
+```ocaml
+type s
+```
\ No newline at end of file
diff --git a/test/generators/markdown/Oxcaml-module-type-Arg_with.md b/test/generators/markdown/Oxcaml-module-type-Arg_with.md
new file mode 100644
index 0000000000..85d97df386
--- /dev/null
+++ b/test/generators/markdown/Oxcaml-module-type-Arg_with.md
@@ -0,0 +1,6 @@
+
+# Module type `Oxcaml.Arg_with`
+
+```ocaml
+type s
+```
\ No newline at end of file
diff --git a/test/generators/markdown/Oxcaml.md b/test/generators/markdown/Oxcaml.md
index 132cd6b4c6..0dfa5474f6 100644
--- a/test/generators/markdown/Oxcaml.md
+++ b/test/generators/markdown/Oxcaml.md
@@ -155,6 +155,73 @@ type 'a t_with_modalities : immutable_data with 'a @@ portable contended
```
Kind annotation with a `with` constraint and modalities.
+```ocaml
+type ('k, 'cmp) comparator
+```
+Helper used in the `with` constraints below.
+
+```ocaml
+type ('k, 'v, 'cmp)
+ t_with_constr : ((immutable_data with 'k) with 'v) with ('k, 'cmp) comparator
+```
+A `with` constraint whose right-hand side is a parameterized type constructor (as found in `base`'s `Map` module).
+
+```ocaml
+type 'a t_with_app : immutable_data with 'a list
+```
+A `with` constraint whose right-hand side applies a type constructor.
+
+```ocaml
+type 'a t_with_arrow : immutable_data with 'a -> 'a
+```
+A `with` constraint whose right-hand side is an arrow type.
+
+```ocaml
+type 'a t_with_arrow_modes : immutable_data with 'a -> 'a @ local
+```
+A `with` constraint whose right-hand side is an arrow type carrying a mode.
+
+```ocaml
+type 'a t_with_tuple : immutable_data with 'a * int
+```
+A `with` constraint whose right-hand side is a tuple type.
+
+```ocaml
+module M_with : sig ... end
+```
+Helper module used in the `with` constraint below.
+
+```ocaml
+type 'a t_with_dot : immutable_data with 'a M_with.t
+```
+A `with` constraint referring to a type through a module path (`M.t`).
+
+```ocaml
+module type Arg_with = sig ... end
+```
+```ocaml
+module F_with (X : Arg_with) : sig ... end
+```
+Helper functor used in the `with` constraint below.
+
+```ocaml
+module X_with : Arg_with
+```
+```ocaml
+type 'a t_with_functor : immutable_data with 'a F_with(X_with).t
+```
+A `with` constraint referring to a type through a functor application (`F(X).t`).
+
+```ocaml
+type 'a t_with_variant : immutable_data with [ `Foo of 'a | `Bar ]
+```
+A `with` constraint whose right-hand side is a polymorphic variant.
+
+```ocaml
+type 'a t_with_object : immutable_data with < foo : 'a >
+```
+A `with` constraint whose right-hand side is an object type.
+
## Kind annotations on type aliases
diff --git a/test/generators/markdown/oxcaml.targets b/test/generators/markdown/oxcaml.targets
index 03016b8b2f..c557e07cc6 100644
--- a/test/generators/markdown/oxcaml.targets
+++ b/test/generators/markdown/oxcaml.targets
@@ -1,4 +1,9 @@
Oxcaml.md
+Oxcaml-M_with.md
+Oxcaml-module-type-Arg_with.md
+Oxcaml-F_with.md
+Oxcaml-F_with-argument-1-X.md
+Oxcaml-X_with.md
Oxcaml-module-type-S.md
Oxcaml-M1.md
Oxcaml-M2.md