From c299fbf0080938d86de9c0cd81b991f62028d84f Mon Sep 17 00:00:00 2001 From: Jon Ludlam's Agent Date: Wed, 11 Mar 2026 10:34:53 +0000 Subject: [PATCH 01/10] Fix build with OCaml 5.5 compiler-libs API changes - pack_cstrs renamed to pack_constraints in Types.package - tpt_cstrs renamed to tpt_constraints in Typedtree.package_type - typ_cstrs renamed to typ_constraints in Typedtree.type_declaration - New Type_external/Ttype_external constructors for external types - New Tfunctor/Ttyp_functor constructors in type_desc/core_type_desc - New Local_opaque_item constructor in Shape.Uid - Typemod.path_of_module moved to Typedtree.path_of_module Co-Authored-By: Claude Opus 4.6 --- src/loader/cmi.ml | 24 ++++++++++++++++++++++-- src/loader/cmti.ml | 19 ++++++++++++++++++- src/loader/ident_env.ml | 12 +++++++++++- src/xref2/shape_tools.cppo.ml | 2 ++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index db7bfd1ba3..c68b74009b 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -300,7 +300,11 @@ let mark_type ty = | Tpoly (ty, tyl) -> List.iter (fun t -> add_alias t) tyl; loop visited ty -#if OCAML_VERSION>=(5,4,0) +#if OCAML_VERSION>=(5,5,0) + | Tpackage p -> + List.iter (fun (_,x) -> loop visited x) p.pack_constraints + | Tfunctor _ -> () +#elif OCAML_VERSION>=(5,4,0) | Tpackage p -> List.iter (fun (_,x) -> loop visited x) p.pack_cstrs #elif OCAML_VERSION>=(4,13,0) @@ -428,6 +432,9 @@ let mark_type_kind = function #endif List.iter (fun ld -> mark_type ld.ld_type) lds | Type_open -> () +#if OCAML_VERSION >= (5,5,0) + | Type_external _ -> () +#endif let mark_type_declaration decl = let params = prepare_type_parameters decl.type_params decl.type_manifest in @@ -554,7 +561,10 @@ let rec read_type_expr env typ = remove_names tyl; Poly(vars, typ) | Tunivar _ -> Var (name_of_type typ) -#if OCAML_VERSION>=(5,4,0) +#if OCAML_VERSION>=(5,5,0) + | Tpackage {pack_path=p; pack_constraints } -> + let eqs = List.filter_map (fun (l,ty) -> Option.map (fun x -> x, ty) (Longident.unflatten l)) pack_constraints in +#elif OCAML_VERSION>=(5,4,0) | Tpackage {pack_path=p; pack_cstrs } -> let eqs = List.filter_map (fun (l,ty) -> Option.map (fun x -> x, ty) (Longident.unflatten l)) pack_cstrs in #elif OCAML_VERSION>=(4,13,0) @@ -579,6 +589,9 @@ let rec read_type_expr env typ = | Tsubst typ -> read_type_expr env typ #else | Tsubst (typ,_) -> read_type_expr env typ +#endif +#if OCAML_VERSION >= (5,5,0) + | Tfunctor _ -> Any #endif | Tlink _ -> assert false #if defined OXCAML @@ -811,6 +824,9 @@ let read_type_kind env parent = in Some (Record lbls) | Type_open -> Some Extensible +#if OCAML_VERSION >= (5,5,0) + | Type_external _ -> None +#endif let read_injectivity var = #if OCAML_VERSION < (5, 1, 0) @@ -893,6 +909,10 @@ let read_type_declaration env parent id decl = List.exists (fun cd -> cd.cd_res <> None) tll | Type_open -> decl.type_manifest = None +#if OCAML_VERSION >= (5,5,0) + | Type_external _ -> + decl.type_manifest = None || decl.type_private = Private +#endif in let params = List.map2 (read_type_parameter abstr) decl.type_variance params diff --git a/src/loader/cmti.ml b/src/loader/cmti.ml index 5468d42af3..fd9a6a250f 100644 --- a/src/loader/cmti.ml +++ b/src/loader/cmti.ml @@ -173,7 +173,9 @@ let rec read_core_type env container ctyp = #else | Ttyp_poly(vars, typ) -> Poly(vars, read_core_type env container typ) #endif -#if OCAML_VERSION >= (5,4,0) +#if OCAML_VERSION >= (5,5,0) + | Ttyp_package {tpt_path = pack_path; tpt_constraints=pack_fields; _} -> +#elif OCAML_VERSION >= (5,4,0) | Ttyp_package {tpt_path = pack_path; tpt_cstrs=pack_fields; _} -> #else | Ttyp_package {pack_path; pack_fields; _} -> @@ -199,6 +201,10 @@ let rec read_core_type env container ctyp = | Ttyp_splice typ -> Splice (read_core_type env container typ) | Ttyp_call_pos -> Constr(Env.Path.read_type env.ident_env Predef.path_lexing_position, []) | Ttyp_of_kind _ -> assert false +#elif OCAML_VERSION >= (5,5,0) + | Ttyp_functor _ -> + (* TODO: adjust model *) + Any #endif let read_value_description env parent vd = @@ -333,6 +339,9 @@ let read_type_kind env parent = Some (Record_unboxed_product lbls) #endif | Ttype_open -> Some Extensible +#if OCAML_VERSION >= (5,5,0) + | Ttype_external _ -> None +#endif let read_type_equation env container decl = let open TypeDecl.Equation in @@ -344,7 +353,11 @@ let read_type_equation env container decl = (fun (typ1, typ2, _) -> (read_core_type env container typ1, read_core_type env container typ2)) +#if OCAML_VERSION >= (5,5,0) + decl.typ_constraints +#else decl.typ_cstrs +#endif in {params; private_; manifest; constraints} @@ -661,7 +674,11 @@ and read_module_type env parent label_parent mty = let p = Env.Path.read_module env.ident_env p in TypeOf {t_desc = ModPath p; t_original_path = p; t_expansion = None} | Tmod_structure {str_items = [{str_desc = Tstr_include {incl_mod; _}; _}]; _} -> begin +#if OCAML_VERSION >= (5,5,0) + match Typedtree.path_of_module incl_mod with +#else match Typemod.path_of_module incl_mod with +#endif | Some p -> let p = Env.Path.read_module env.ident_env p in TypeOf {t_desc=StructInclude p; t_original_path = p; t_expansion = None} diff --git a/src/loader/ident_env.ml b/src/loader/ident_env.ml index 54788364af..626c89e3ed 100644 --- a/src/loader/ident_env.ml +++ b/src/loader/ident_env.ml @@ -132,7 +132,11 @@ and extract_signature_type_items_extract vis ~hidden item rest = | Type_variant (cstrs, _) -> #endif List.map (fun c -> `Constructor (c.Types.cd_id, id, Some c.cd_loc)) cstrs - | Type_open -> [] in + | Type_open -> [] +#if OCAML_VERSION >= (5,5,0) + | Type_external _ -> [] +#endif + in `Type (id, hidden, None) :: constrs @ extract_signature_type_items vis rest | Sig_module(id, _, _, _, _), _ -> @@ -221,6 +225,9 @@ let rec extract_signature_tree_items : bool -> Typedtree.signature_item list -> | Ttype_record_unboxed_product _ -> [] #endif | Ttype_open -> [] +#if OCAML_VERSION >= (5,5,0) + | Ttype_external _ -> [] +#endif ) decls @ extract_signature_tree_items hide_item rest @@ -389,6 +396,9 @@ let rec extract_structure_tree_items : bool -> Typedtree.structure_item list -> | Ttype_record_unboxed_product _ -> [] #endif | Ttype_open -> [] +#if OCAML_VERSION >= (5,5,0) + | Ttype_external _ -> [] +#endif )) decls @ extract_structure_tree_items hide_item rest diff --git a/src/xref2/shape_tools.cppo.ml b/src/xref2/shape_tools.cppo.ml index 2b16cb2e4e..9302b56ce5 100644 --- a/src/xref2/shape_tools.cppo.ml +++ b/src/xref2/shape_tools.cppo.ml @@ -120,6 +120,8 @@ let unit_of_uid uid = | Internal -> None #if defined OXCAML | Unboxed_version _ -> None +#elif OCAML_VERSION >= (5,5,0) + | Local_opaque_item _ -> None #endif #if OCAML_VERSION >= (5,2,0) From 803eb0655233111a59f4a71b11703dcb190af738 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Wed, 25 Mar 2026 00:21:00 +0100 Subject: [PATCH 02/10] 5.5 support: Module arguments The way it works is not ideal: we create a synthetic parent id for each module argument (as they can be introduced multiple times with the same name in the same type expression). This id is hidden and we don't render links to hidden ids. This is slightly bad because: - The appearance of unresolved links suggest an error when there is no. - There is no way to distinguish module args from normal modules But let's say it is a good first step! Co-authored-by: xvw --- odoc-parser.opam | 2 +- odoc.opam | 2 +- src/document/generator.ml | 43 +++++-- src/loader/cmi.ml | 49 +++++--- src/loader/cmti.ml | 40 ++++--- src/loader/ident_env.ml | 7 ++ src/loader/ident_env.mli | 7 ++ src/model/lang.ml | 5 + src/model/paths.ml | 14 ++- src/model/paths.mli | 5 + src/model_desc/lang_desc.ml | 15 ++- src/xref2/compile.ml | 10 ++ src/xref2/component.ml | 18 +++ src/xref2/component.mli | 5 + src/xref2/env.ml | 15 +++ src/xref2/env.mli | 2 + src/xref2/expand_tools.ml | 7 ++ src/xref2/lang_of.ml | 8 ++ src/xref2/link.ml | 11 ++ src/xref2/subst.ml | 13 ++ test/generators/link.dune.inc | 218 ++++++++++++++++++++++++++++++++++ 21 files changed, 450 insertions(+), 46 deletions(-) diff --git a/odoc-parser.opam b/odoc-parser.opam index 92935df19a..139c584a11 100644 --- a/odoc-parser.opam +++ b/odoc-parser.opam @@ -14,7 +14,7 @@ dev-repo: "git+https://github.com/ocaml/odoc.git" doc: "https://ocaml.github.io/odoc/odoc_parser" depends: [ "dune" {>= "3.21"} - "ocaml" {>= "4.08.0" & < "5.5"} + "ocaml" {>= "4.08.0" & <= "5.5.1"} "astring" "camlp-streams" "ppx_expect" {with-test} diff --git a/odoc.opam b/odoc.opam index 62478fe47c..e4ab6f9b4d 100644 --- a/odoc.opam +++ b/odoc.opam @@ -45,7 +45,7 @@ depends: [ "cppo" {build & >= "1.1.0"} "dune" {>= "3.21.0"} "fpath" {>= "0.7.3"} - "ocaml" {>= "4.08.0" & < "5.5"} + "ocaml" {>= "4.08.0" & <= "5.5.1"} "tyxml" {>= "4.4.0"} "fmt" "crunch" {>= "1.4.1"} diff --git a/src/document/generator.ml b/src/document/generator.ml index de14ee9a5a..0e481f582c 100644 --- a/src/document/generator.ml +++ b/src/document/generator.ml @@ -485,19 +485,36 @@ module Make (Syntax : SYNTAX) = struct | Splice t -> O.span (O.txt "$" ++ type_expr ~needs_parentheses:true t) | Package pkg -> enclose ~l:"(" ~r:")" - (O.keyword "module" ++ O.txt " " - ++ Link.from_path (pkg.path :> Paths.Path.t) - ++ - match pkg.substitutions with - | [] -> O.noop - | fst :: lst -> - O.sp - ++ O.box_hv (O.keyword "with" ++ O.txt " " ++ package_subst fst) - ++ O.list lst ~f:(fun s -> - O.cut - ++ (O.box_hv - @@ O.txt " " ++ O.keyword "and" ++ O.txt " " - ++ package_subst s))) + (O.keyword "module" ++ O.txt " " ++ package_path pkg) + | Arrow_functor (lbl, m_arg, dst) -> + let lbl = + match lbl with None -> O.noop | Some lbl -> label lbl ++ O.txt ":" + in + let name = + match m_arg.id.iv with + | `Parameter (_, name) -> ModuleName.to_string name + in + let dst = type_expr dst in + let pkg = + enclose ~l:"(" ~r:")" + @@ O.keyword "module" ++ O.txt " " ++ O.txt name ++ O.txt " : " + ++ package_path m_arg.package + in + lbl ++ pkg ++ O.sp ++ Syntax.Type.arrow ++ O.sp ++ dst + + and package_path pkg = + Link.from_path (pkg.path :> Paths.Path.t) + ++ + match pkg.substitutions with + | [] -> O.noop + | fst :: lst -> + O.sp + ++ O.box_hv (O.keyword "with" ++ O.txt " " ++ package_subst fst) + ++ O.list lst ~f:(fun s -> + O.cut + ++ (O.box_hv + @@ O.txt " " ++ O.keyword "and" ++ O.txt " " + ++ package_subst s)) and package_subst ((frag_typ, te) : Paths.Fragment.Type.t * Odoc_model.Lang.TypeExpr.t) : diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index c68b74009b..06270d51a0 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -303,7 +303,9 @@ let mark_type ty = #if OCAML_VERSION>=(5,5,0) | Tpackage p -> List.iter (fun (_,x) -> loop visited x) p.pack_constraints - | Tfunctor _ -> () + | Tfunctor (_lbl, _id, pkg, ret_type) -> + List.iter (fun (_,x) -> loop visited x) pkg.pack_constraints; + loop visited ret_type #elif OCAML_VERSION>=(5,4,0) | Tpackage p -> List.iter (fun (_,x) -> loop visited x) p.pack_cstrs @@ -573,25 +575,30 @@ let rec read_type_expr env typ = | Tpackage(p, frags, tyl) -> let eqs = List.combine frags tyl in #endif - let open TypeExpr.Package in - let path = Env.Path.read_module_type env.ident_env p in - let substitutions = - List.map - (fun (frag,typ) -> - let frag = Env.Fragment.read_type frag in - let typ = read_type_expr env typ in - (frag, typ)) - eqs - in - - Package {path; substitutions} + let package = read_package env eqs p in + Package package #if OCAML_VERSION<(4,13,0) | Tsubst typ -> read_type_expr env typ #else | Tsubst (typ,_) -> read_type_expr env typ #endif #if OCAML_VERSION >= (5,5,0) - | Tfunctor _ -> Any + | Tfunctor (lbl, id, pkg, ret_type) -> + let lbl = read_label lbl in + let parent = Identifier.fresh_module_arg_parent () in + let id = Ocaml_ident.of_unscoped id in + let e', id = + Env.add_module_arg parent id (ModuleName.hidden_of_ident id) + env.ident_env + in + let env = {env with ident_env = e'} in + let ret = read_type_expr env ret_type in + let eqs = + List.filter_map (fun (l,ty) -> Option.map (fun x -> x, ty) (Longident.unflatten l)) pkg.pack_constraints + in + let package = read_package env eqs pkg.pack_path in + Arrow_functor(lbl, {id ; package}, ret) + #endif | Tlink _ -> assert false #if defined OXCAML @@ -605,6 +612,20 @@ let rec read_type_expr env typ = | Some name -> Alias(typ, name) end +and read_package env eqs p = + let open TypeExpr in + let open TypeExpr.Package in + let path = Env.Path.read_module_type env.ident_env p in + let substitutions = + List.map + (fun (frag,typ) -> + let frag = Env.Fragment.read_type frag in + let typ = read_type_expr env typ in + (frag, typ)) + eqs + in + {path; substitutions} + and read_row env _px row = let open TypeExpr in let open TypeExpr.Polymorphic_variant in diff --git a/src/loader/cmti.ml b/src/loader/cmti.ml index fd9a6a250f..e74246692e 100644 --- a/src/loader/cmti.ml +++ b/src/loader/cmti.ml @@ -180,17 +180,8 @@ let rec read_core_type env container ctyp = #else | Ttyp_package {pack_path; pack_fields; _} -> #endif - let open TypeExpr.Package in - let path = Env.Path.read_module_type env.ident_env pack_path in - let substitutions = - List.map - (fun (frag, typ) -> - let frag = Env.Fragment.read_type frag.Location.txt in - let typ = read_core_type env container typ in - (frag, typ)) - pack_fields - in - Package {path; substitutions} + let pkg = read_package env container pack_path pack_fields in + Package pkg #if OCAML_VERSION >= (5,2,0) | Ttyp_open (_p,_l,t) -> (* TODO: adjust model *) @@ -202,11 +193,32 @@ let rec read_core_type env container ctyp = | Ttyp_call_pos -> Constr(Env.Path.read_type env.ident_env Predef.path_lexing_position, []) | Ttyp_of_kind _ -> assert false #elif OCAML_VERSION >= (5,5,0) - | Ttyp_functor _ -> - (* TODO: adjust model *) - Any + | Ttyp_functor (lbl, id, pkg, ret_type) -> + let lbl = read_label lbl in + let parent = Identifier.fresh_module_arg_parent () in + let e', id = + Env.add_module_arg parent id.txt (ModuleName.hidden_of_ident id.txt) + env.ident_env + in + let env = {env with ident_env = e'} in + let ret = read_core_type env container ret_type in + let package = read_package env container pkg.tpt_path pkg.tpt_constraints in + Arrow_functor(lbl, {id ; package}, ret) #endif +and read_package env container pack_path pack_fields = + let open TypeExpr.Package in + let path = Env.Path.read_module_type env.ident_env pack_path in + let substitutions = + List.map + (fun (frag, typ) -> + let frag = Env.Fragment.read_type frag.Location.txt in + let typ = read_core_type env container typ in + (frag, typ)) + pack_fields + in + {path; substitutions} + let read_value_description env parent vd = let open Signature in let id = Env.find_value_identifier env.ident_env vd.val_id in diff --git a/src/loader/ident_env.ml b/src/loader/ident_env.ml index 626c89e3ed..f8671d735f 100644 --- a/src/loader/ident_env.ml +++ b/src/loader/ident_env.ml @@ -670,6 +670,13 @@ let add_parameter parent id name env = let parameters = Ident.add id oid env.parameters in { env with module_paths; modules; parameters } +let add_module_arg parent id name env = + let oid = Odoc_model.Paths.Identifier.Mk.(parameter (parent, name)) in + let path = `Identifier (oid, false) in + let module_paths = Ident.add id path env.module_paths in + let modules = Ident.add id oid env.modules in + { env with module_paths; modules }, oid + let find_module env id = Ident.find_same id env.module_paths diff --git a/src/loader/ident_env.mli b/src/loader/ident_env.mli index 531ceb6261..c7bd95e1d2 100644 --- a/src/loader/ident_env.mli +++ b/src/loader/ident_env.mli @@ -23,6 +23,13 @@ val empty : unit -> t val add_parameter : Paths.Identifier.Signature.t -> Ident.t -> Names.ModuleName.t -> t -> t +val add_module_arg : + Paths.Identifier.Signature.t -> + Ident.t -> + Names.ModuleName.t -> + t -> + t * Odoc_model.Paths.Identifier.FunctorParameter.t + val handle_signature_type_items : Paths.Identifier.Signature.t -> Compat.signature -> t -> t diff --git a/src/model/lang.ml b/src/model/lang.ml index e801ebbf2e..432eb88152 100644 --- a/src/model/lang.ml +++ b/src/model/lang.ml @@ -451,6 +451,10 @@ and TypeExpr : sig type t = { path : Path.ModuleType.t; substitutions : substitution list } end + module Module : sig + type t = { package : Package.t; id : Identifier.FunctorParameter.t } + end + type label = Label of string | RawOptional of string | Optional of string type t = @@ -468,6 +472,7 @@ and TypeExpr : sig | Quote of t | Splice of t | Package of TypeExpr.Package.t + | Arrow_functor of label option * Module.t * t end = TypeExpr diff --git a/src/model/paths.ml b/src/model/paths.ml index a1042b64cd..9d26fdad87 100644 --- a/src/model/paths.ml +++ b/src/model/paths.ml @@ -659,6 +659,16 @@ module Identifier = struct let name = Printf.sprintf "include%d_" !include_parent_counter in (Mk.module_ (parent, ModuleName.make_std name) :> Signature.t) + let module_arg_parent_counter = ref 0 + + (* Create a synthetic parent identifier for module arguments, which can't have + unique identifier, as they can be introduced multiple times with the same + name in a single type expression . *) + let fresh_module_arg_parent () : Signature.t = + incr module_arg_parent_counter; + let name = Printf.sprintf "module_arg_%d_" !module_arg_parent_counter in + (Mk.root (None, ModuleName.hidden_of_string name) :> Signature.t) + module Hashtbl = struct module Any = Hashtbl.Make (Any) module ContainerPage = Hashtbl.Make (ContainerPage) @@ -684,7 +694,7 @@ module Path = struct | `Identifier { iv = `Module (_, m); _ } when Names.ModuleName.is_hidden m -> true - | `Identifier _ -> false + | `Identifier id -> Identifier.is_hidden id | `Canonical (_, `Resolved _) -> false | `Canonical (x, _) -> (not weak_canonical_test) && inner (x : module_ :> any) @@ -727,7 +737,7 @@ module Path = struct let open Paths_types.Path in function | `Resolved r -> is_resolved_hidden ~weak_canonical_test:false r - | `Identifier (_, hidden) -> hidden + | `Identifier (id, hidden) -> hidden || Identifier.is_hidden id | `Substituted r -> is_path_hidden (r :> any) | `SubstitutedMT r -> is_path_hidden (r :> any) | `SubstitutedT r -> is_path_hidden (r :> any) diff --git a/src/model/paths.mli b/src/model/paths.mli index 1892f008ba..0f5c16aca3 100644 --- a/src/model/paths.mli +++ b/src/model/paths.mli @@ -364,6 +364,11 @@ module Identifier : sig type expression. Uses a lowercase module name (illegal in normal OCaml) to ensure no clashes with real identifiers. Each call returns a fresh identifier. *) + + val fresh_module_arg_parent : unit -> Signature.t + (** Create a synthetic parent identifier for module arguments, which can't + have unique identifier, as they can be introduced multiple times with the + same name in a single type expression . *) end (** Normal OCaml paths (i.e. the ones present in types) *) diff --git a/src/model_desc/lang_desc.ml b/src/model_desc/lang_desc.ml index 8df9471334..2e59a456d2 100644 --- a/src/model_desc/lang_desc.ml +++ b/src/model_desc/lang_desc.ml @@ -637,6 +637,14 @@ and typeexpr_package = List typeexpr_package_substitution ); ] +and typeexpr_module_arg = + let open Lang.TypeExpr.Module in + Record + [ + F ("id", (fun t -> t.id), identifier); + F ("package", (fun t -> t.package), typeexpr_package); + ] + and typeexpr_label = let open Lang.TypeExpr in Variant @@ -670,7 +678,12 @@ and typeexpr_t = | Poly (x1, x2) -> C ("Poly", (x1, x2), Pair (List string, typeexpr_t)) | Quote x -> C ("Quote", x, typeexpr_t) | Splice x -> C ("Splice", x, typeexpr_t) - | Package x -> C ("Package", x, typeexpr_package)) + | Package x -> C ("Package", x, typeexpr_package) + | Arrow_functor (lbl, m_arg, t) -> + C + ( "Arrow_functor", + (lbl, m_arg, t), + Triple (Option typeexpr_label, typeexpr_module_arg, typeexpr_t) )) (** {3 Compilation_unit} *) diff --git a/src/xref2/compile.ml b/src/xref2/compile.ml index 6d92d8e071..1066425741 100644 --- a/src/xref2/compile.ml +++ b/src/xref2/compile.ml @@ -838,6 +838,10 @@ and type_expression_object env parent o = in { o with fields = List.map field o.fields } +and type_expression_module_arg env parent m_arg = + let open TypeExpr.Module in + { m_arg with package = type_expression_package env parent m_arg.package } + and type_expression_package env parent p = let open TypeExpr.Package in let cp = Component.Of_Lang.(module_type_path (empty ()) p.path) in @@ -956,6 +960,12 @@ and type_expression : Env.t -> Id.LabelParent.t -> _ -> _ = | Quote t -> Quote (type_expression env parent t) | Splice t -> Splice (type_expression env parent t) | Package p -> Package (type_expression_package env parent p) + | Arrow_functor (lbl, m_arg, t) -> + let new_env = Env.add_module_arg m_arg env in + Arrow_functor + ( lbl, + type_expression_module_arg env parent m_arg, + type_expression new_env parent t ) let compile ~filename env compilation_unit = Lookup_failures.catch_failures ~filename (fun () -> unit env compilation_unit) diff --git a/src/xref2/component.ml b/src/xref2/component.ml index 9017fea357..64b9996a4a 100644 --- a/src/xref2/component.ml +++ b/src/xref2/component.ml @@ -115,6 +115,10 @@ and TypeExpr : sig type t = { path : Cpath.module_type; substitutions : substitution list } end + module Module : sig + type t = { package : Package.t; id : Ident.module_ } + end + type label = Odoc_model.Lang.TypeExpr.label type t = @@ -132,6 +136,7 @@ and TypeExpr : sig | Quote of t | Splice of t | Package of TypeExpr.Package.t + | Arrow_functor of label option * Module.t * t end = TypeExpr @@ -1211,6 +1216,11 @@ module Fmt = struct | Quote t -> Format.fprintf ppf "(quote %a)" (type_expr c) t | Splice t -> Format.fprintf ppf "(splice %a)" (type_expr c) t | Package x -> type_package c ppf x + | Arrow_functor (l, m_arg, t) -> + Format.fprintf ppf "%a(%a) -> %a" type_expr_label l (type_module_arg c) + m_arg (type_expr c) t + + and type_module_arg _c ppf _m = Format.fprintf ppf "(module_arg)" and resolved_module_path : config -> Format.formatter -> Cpath.Resolved.module_ -> unit = @@ -2356,6 +2366,14 @@ module Of_Lang = struct | Quote t -> Quote (type_expression ident_map t) | Splice t -> Splice (type_expression ident_map t) | Package p -> Package (type_package ident_map p) + | Arrow_functor (lbl, m_arg, t) -> + Arrow_functor + (lbl, type_module_arg ident_map m_arg, type_expression ident_map t) + + and type_module_arg ident_map { package; id } = + let id = Ident.Of_Identifier.functor_parameter id in + let package = type_package ident_map package in + { package; id } and module_decl ident_map m = match m with diff --git a/src/xref2/component.mli b/src/xref2/component.mli index 0cd6e900f5..c4fe50d51b 100644 --- a/src/xref2/component.mli +++ b/src/xref2/component.mli @@ -110,6 +110,10 @@ and TypeExpr : sig type t = { path : Cpath.module_type; substitutions : substitution list } end + module Module : sig + type t = { package : Package.t; id : Ident.module_ } + end + type label = Odoc_model.Lang.TypeExpr.label type t = @@ -127,6 +131,7 @@ and TypeExpr : sig | Quote of t | Splice of t | Package of TypeExpr.Package.t + | Arrow_functor of label option * Module.t * t end and Extension : sig diff --git a/src/xref2/env.ml b/src/xref2/env.ml index 751e8a2147..f254db4328 100644 --- a/src/xref2/env.ml +++ b/src/xref2/env.ml @@ -701,6 +701,21 @@ let add_functor_parameter : Lang.FunctorParameter.t -> t -> t = { elements = []; warnings_tag = None } t +let add_module_arg : Lang.TypeExpr.Module.t -> t -> t = + fun p t -> + let id = (p.id :> Paths.Identifier.Path.Module.t) in + let m = + let expr = + Lang.ModuleType.Path { p_path = p.package.path; p_expansion = None } + in + let open Component.Of_Lang in + mk_functor_parameter (module_type_expr (empty ()) expr) + in + add_module id + (Component.Delayed.put_val m) + { elements = []; warnings_tag = None } + t + let add_functor_args' : Paths.Identifier.Signature.t -> Component.ModuleType.expr -> t -> t = let open Component in diff --git a/src/xref2/env.mli b/src/xref2/env.mli index 413986088a..a2e2325a5a 100644 --- a/src/xref2/env.mli +++ b/src/xref2/env.mli @@ -166,6 +166,8 @@ val s_fragment_type_parent : Component.Element.fragment_type_parent scope val add_functor_parameter : Lang.FunctorParameter.t -> t -> t +val add_module_arg : Lang.TypeExpr.Module.t -> t -> t + val open_class_signature : Lang.ClassSignature.t -> t -> t val open_signature : Lang.Signature.t -> t -> t diff --git a/src/xref2/expand_tools.ml b/src/xref2/expand_tools.ml index c87ef6e420..6ec6930ad4 100644 --- a/src/xref2/expand_tools.ml +++ b/src/xref2/expand_tools.ml @@ -69,6 +69,9 @@ let rec type_expr map t = | Package p -> Package (package map p) | Quote t -> Quote (type_expr map t) | Splice t -> Splice (type_expr map t) + | Arrow_functor (l, m_arg, t) -> + let m_arg = module_arg map m_arg in + Arrow_functor (l, m_arg, type_expr map t) and polymorphic_variant map pv = let open Lang.TypeExpr.Polymorphic_variant in @@ -98,6 +101,10 @@ and package map p = let subst (frag, t) = (frag, type_expr map t) in { p with substitutions = List.map subst p.substitutions } +and module_arg map m = + let open Lang.TypeExpr.Module in + { m with package = package map m.package } + let collapse_eqns eqn1 eqn2 params = let open Lang.TypeDecl in let map = diff --git a/src/xref2/lang_of.ml b/src/xref2/lang_of.ml index ed5f45dfd0..a1b17fb6a5 100644 --- a/src/xref2/lang_of.ml +++ b/src/xref2/lang_of.ml @@ -1017,6 +1017,11 @@ and type_expr_package map (parent : Identifier.LabelParent.t) t = t.substitutions; } +and type_expr_module_arg map (parent : Identifier.LabelParent.t) + (t : Component.TypeExpr.Module.t) = + let id = List.assoc t.id map.functor_parameter in + { Lang.TypeExpr.Module.id; package = type_expr_package map parent t.package } + and type_expr map (parent : Identifier.LabelParent.t) (t : Component.TypeExpr.t) : Odoc_model.Lang.TypeExpr.t = try @@ -1043,6 +1048,9 @@ and type_expr map (parent : Identifier.LabelParent.t) (t : Component.TypeExpr.t) | Quote t -> Quote (type_expr map parent t) | Splice t -> Splice (type_expr map parent t) | Package p -> Package (type_expr_package map parent p) + | Arrow_functor (lbl, m_arg, t) -> + Arrow_functor + (lbl, type_expr_module_arg map parent m_arg, type_expr map parent t) with e -> let bt = Printexc.get_backtrace () in Format.fprintf Format.err_formatter diff --git a/src/xref2/link.ml b/src/xref2/link.ml index 0cdac826db..82c5809af5 100644 --- a/src/xref2/link.ml +++ b/src/xref2/link.ml @@ -1106,6 +1106,11 @@ and type_expression_object env parent visited o = in { o with fields = List.map field o.fields } +and type_expression_module_arg env parent visited m_arg = + let open TypeExpr.Module in + let package = type_expression_package env parent visited m_arg.package in + { m_arg with package } + and type_expression_package env parent visited p = let open TypeExpr.Package in let substitution (frag, t) = @@ -1207,6 +1212,12 @@ and type_expression : Env.t -> Id.Signature.t -> _ -> _ = | Quote t -> Quote (type_expression env parent visited t) | Splice t -> Splice (type_expression env parent visited t) | Package p -> Package (type_expression_package env parent visited p) + | Arrow_functor (lbl, m_arg, t) -> + let new_env = Env.add_module_arg m_arg env in + Arrow_functor + ( lbl, + type_expression_module_arg env parent visited m_arg, + type_expression new_env parent visited t ) let link ~filename x y = Lookup_failures.catch_failures ~filename (fun () -> diff --git a/src/xref2/subst.ml b/src/xref2/subst.ml index e6c02e469b..c7cc903ca8 100644 --- a/src/xref2/subst.ml +++ b/src/xref2/subst.ml @@ -179,6 +179,13 @@ let rec substitute_vars vars t = | Quote t -> Quote (substitute_vars vars t) | Splice t -> Splice (substitute_vars vars t) | Package p -> Package (substitute_vars_package vars p) + | Arrow_functor (lbl, m_arg, t) -> + Arrow_functor + (lbl, substitute_vars_module_arg vars m_arg, substitute_vars vars t) + +and substitute_vars_module_arg vars m_arg = + let package = substitute_vars_package vars m_arg.package in + { m_arg with package } and substitute_vars_package vars p = let open TypeExpr.Package in @@ -622,6 +629,12 @@ and type_expr s t = | Quote t -> Quote (type_expr s t) | Splice t -> Splice (type_expr s t) | Package p -> Package (type_package s p) + | Arrow_functor (lbl, m_arg, t) -> + Arrow_functor (lbl, type_module_arg s m_arg, type_expr s t) + +and type_module_arg s m_arg = + let package = type_package s m_arg.package in + { m_arg with package } and simple_expansion : t -> diff --git a/test/generators/link.dune.inc b/test/generators/link.dune.inc index e5d3455c96..e43f6a0e59 100644 --- a/test/generators/link.dune.inc +++ b/test/generators/link.dune.inc @@ -542,6 +542,30 @@ (enabled_if (>= %{ocaml_version} 4.04))) +(rule + (target ocaml_55.cmti) + (package odoc) + (action + (run ocamlc -c -bin-annot -o %{target} %{dep:cases/ocaml_55.mli})) + (enabled_if + (>= %{ocaml_version} 4.04))) + +(rule + (target ocaml_55.odoc) + (package odoc) + (action + (run odoc compile -o %{target} %{dep:ocaml_55.cmti})) + (enabled_if + (>= %{ocaml_version} 4.04))) + +(rule + (target ocaml_55.odocl) + (package odoc) + (action + (run odoc link -o %{target} %{dep:ocaml_55.odoc})) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule (target ocamlary.cmti) (package odoc) @@ -7380,6 +7404,200 @@ (enabled_if (>= %{ocaml_version} 4.04)))) +(subdir + html + (rule + (targets + Ocaml_55.html.gen + Ocaml_55-module-type-X.html.gen + Ocaml_55-module-type-Y.html.gen) + (package odoc) + (action + (run + odoc + html-generate + --indent + --flat + --extra-suffix + gen + -o + . + %{dep:../ocaml_55.odocl})) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55.html Ocaml_55.html.gen)) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55-module-type-X.html Ocaml_55-module-type-X.html.gen)) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55-module-type-Y.html Ocaml_55-module-type-Y.html.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + +(subdir + html + (rule + (target ocaml_55.targets.gen) + (package odoc) + (action + (with-outputs-to + ocaml_55.targets.gen + (run odoc html-targets -o . %{dep:../ocaml_55.odocl} --flat))) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff ocaml_55.targets ocaml_55.targets.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + +(subdir + latex + (rule + (targets Ocaml_55.tex.gen) + (package odoc) + (action + (run odoc latex-generate -o . --extra-suffix gen %{dep:../ocaml_55.odocl})) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55.tex Ocaml_55.tex.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + +(subdir + latex + (rule + (target ocaml_55.targets.gen) + (package odoc) + (action + (with-outputs-to + ocaml_55.targets.gen + (run odoc latex-targets -o . %{dep:../ocaml_55.odocl}))) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff ocaml_55.targets ocaml_55.targets.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + +(subdir + man + (rule + (targets Ocaml_55.3o.gen) + (package odoc) + (action + (run odoc man-generate -o . --extra-suffix gen %{dep:../ocaml_55.odocl})) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55.3o Ocaml_55.3o.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + +(subdir + man + (rule + (target ocaml_55.targets.gen) + (package odoc) + (action + (with-outputs-to + ocaml_55.targets.gen + (run odoc man-targets -o . %{dep:../ocaml_55.odocl}))) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff ocaml_55.targets ocaml_55.targets.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + +(subdir + markdown + (rule + (targets + Ocaml_55.md.gen + Ocaml_55-module-type-X.md.gen + Ocaml_55-module-type-Y.md.gen) + (package odoc) + (action + (run + odoc + markdown-generate + -o + . + --extra-suffix + gen + %{dep:../ocaml_55.odocl})) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55.md Ocaml_55.md.gen)) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55-module-type-X.md Ocaml_55-module-type-X.md.gen)) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff Ocaml_55-module-type-Y.md Ocaml_55-module-type-Y.md.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + +(subdir + markdown + (rule + (target ocaml_55.targets.gen) + (package odoc) + (action + (with-outputs-to + ocaml_55.targets.gen + (run odoc markdown-targets -o . %{dep:../ocaml_55.odocl}))) + (enabled_if + (>= %{ocaml_version} 4.04))) + (rule + (alias runtest) + (package odoc) + (action + (diff ocaml_55.targets ocaml_55.targets.gen)) + (enabled_if + (>= %{ocaml_version} 4.04)))) + (subdir html (rule From 1fd7d1c7f41014db70e02d11c53b128ce0bd4c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul-Elliot=20Angl=C3=A8s=20d=27Auriac?= Date: Tue, 7 Apr 2026 16:33:02 +0200 Subject: [PATCH 03/10] Update odoc.opam Co-authored-by: Kate --- odoc.opam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoc.opam b/odoc.opam index e4ab6f9b4d..4589994626 100644 --- a/odoc.opam +++ b/odoc.opam @@ -45,7 +45,7 @@ depends: [ "cppo" {build & >= "1.1.0"} "dune" {>= "3.21.0"} "fpath" {>= "0.7.3"} - "ocaml" {>= "4.08.0" & <= "5.5.1"} + "ocaml" {>= "4.08.0" & < "5.6"} "tyxml" {>= "4.4.0"} "fmt" "crunch" {>= "1.4.1"} From b1f0b25e3892e78d60b11bd7434fb070e0bb78c9 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Wed, 8 Apr 2026 15:56:14 +0200 Subject: [PATCH 04/10] Add missing test output --- test/generators/cases/ocaml_55.mli | 19 +++ .../html/Ocaml_55-module-type-X.html | 33 ++++ .../html/Ocaml_55-module-type-Y.html | 41 +++++ test/generators/html/Ocaml_55.html | 149 ++++++++++++++++++ test/generators/html/ocaml_55.targets | 3 + test/generators/latex/Ocaml_55.tex | 19 +++ test/generators/latex/ocaml_55.targets | 1 + test/generators/man/Ocaml_55.3o | 48 ++++++ test/generators/man/ocaml_55.targets | 1 + .../markdown/Ocaml_55-module-type-X.md | 9 ++ .../markdown/Ocaml_55-module-type-Y.md | 9 ++ test/generators/markdown/Ocaml_55.md | 33 ++++ test/generators/markdown/ocaml_55.targets | 3 + 13 files changed, 368 insertions(+) create mode 100644 test/generators/cases/ocaml_55.mli create mode 100644 test/generators/html/Ocaml_55-module-type-X.html create mode 100644 test/generators/html/Ocaml_55-module-type-Y.html create mode 100644 test/generators/html/Ocaml_55.html create mode 100644 test/generators/html/ocaml_55.targets create mode 100644 test/generators/latex/Ocaml_55.tex create mode 100644 test/generators/latex/ocaml_55.targets create mode 100644 test/generators/man/Ocaml_55.3o create mode 100644 test/generators/man/ocaml_55.targets create mode 100644 test/generators/markdown/Ocaml_55-module-type-X.md create mode 100644 test/generators/markdown/Ocaml_55-module-type-Y.md create mode 100644 test/generators/markdown/Ocaml_55.md create mode 100644 test/generators/markdown/ocaml_55.targets diff --git a/test/generators/cases/ocaml_55.mli b/test/generators/cases/ocaml_55.mli new file mode 100644 index 0000000000..f3fe822dec --- /dev/null +++ b/test/generators/cases/ocaml_55.mli @@ -0,0 +1,19 @@ +module type X = sig type t val x : int end + +type m = (module X) + +val f0 : m -> unit + +val f55 : (module M : X) -> M.t + +val f' : (module M : X with type t = int) -> int + +val f'' : (module X with type t = int) -> int + +module type Y = sig type 'a t val return : 'a -> 'a t end + +val g : (module M : Y) -> int M.t + +val g' : (module M : Y) -> int + +val g'' : (module Y) -> int diff --git a/test/generators/html/Ocaml_55-module-type-X.html b/test/generators/html/Ocaml_55-module-type-X.html new file mode 100644 index 0000000000..a49ceb9027 --- /dev/null +++ b/test/generators/html/Ocaml_55-module-type-X.html @@ -0,0 +1,33 @@ + + + X (Ocaml_55.X) + + + + + + + + +
+

Module type Ocaml_55.X

+
+
+
+
+ + type t +
+
+
+
+ + val x : int +
+
+
+ + diff --git a/test/generators/html/Ocaml_55-module-type-Y.html b/test/generators/html/Ocaml_55-module-type-Y.html new file mode 100644 index 0000000000..19e462f0e8 --- /dev/null +++ b/test/generators/html/Ocaml_55-module-type-Y.html @@ -0,0 +1,41 @@ + + + Y (Ocaml_55.Y) + + + + + + + + +
+

Module type Ocaml_55.Y

+
+
+
+
+ + type 'a t + +
+
+
+
+ + + val return : + 'a + -> + + 'a t + + +
+
+
+ + diff --git a/test/generators/html/Ocaml_55.html b/test/generators/html/Ocaml_55.html new file mode 100644 index 0000000000..b4c2f77d7f --- /dev/null +++ b/test/generators/html/Ocaml_55.html @@ -0,0 +1,149 @@ + + + Ocaml_55 (Ocaml_55) + + + + + + + + +
+

Module Ocaml_55

+
+
+
+
+ + + module + type + X + + = sig ... + end + + +
+
+
+
+ + type m + = + (module + X) + + + +
+
+
+
+ + + val f0 : + m -> + unit + + +
+
+
+
+ + + val f55 : (module M : + X) + -> + M.t + + +
+
+
+
+ + + val f' : (module M : + X + with type + t = int) + -> int + + +
+
+
+
+ + + val f'' : + + (module + X + with type + t = int) + -> + int + + +
+
+
+
+ + + module + type + Y + + = sig ... + end + + +
+
+
+
+ + + val g : (module M : + Y) + -> + int M.t + + +
+
+
+
+ + + val g' : (module M : + Y) + -> int + + +
+
+
+
+ + + val g'' : + + (module + Y) + -> + int + + +
+
+
+ + diff --git a/test/generators/html/ocaml_55.targets b/test/generators/html/ocaml_55.targets new file mode 100644 index 0000000000..fb491ea1be --- /dev/null +++ b/test/generators/html/ocaml_55.targets @@ -0,0 +1,3 @@ +Ocaml_55.html +Ocaml_55-module-type-X.html +Ocaml_55-module-type-Y.html diff --git a/test/generators/latex/Ocaml_55.tex b/test/generators/latex/Ocaml_55.tex new file mode 100644 index 0000000000..23d3874e96 --- /dev/null +++ b/test/generators/latex/Ocaml_55.tex @@ -0,0 +1,19 @@ +\section{Module \ocamlinlinecode{Ocaml\_\allowbreak{}55}}\label{Ocaml_55}% +\label{Ocaml_55--module-type-X}\ocamlcodefragment{\ocamltag{keyword}{module} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}}}\label{Ocaml_55-module-type-X}\ocamlcodefragment{ = \ocamltag{keyword}{sig}}\begin{ocamlindent}\label{Ocaml_55-module-type-X--type-t}\ocamlcodefragment{\ocamltag{keyword}{type} t}\\ +\label{Ocaml_55-module-type-X--val-x}\ocamlcodefragment{\ocamltag{keyword}{val} x : int}\\ +\end{ocamlindent}% +\ocamlcodefragment{\ocamltag{keyword}{end}}\\ +\label{Ocaml_55--type-m}\ocamlcodefragment{\ocamltag{keyword}{type} m = (\ocamltag{keyword}{module} \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}})}\\ +\label{Ocaml_55--val-f0}\ocamlcodefragment{\ocamltag{keyword}{val} f0 : \hyperref[Ocaml_55--type-m]{\ocamlinlinecode{m}} \ocamltag{arrow}{$\rightarrow$} unit}\\ +\label{Ocaml_55--val-f55}\ocamlcodefragment{\ocamltag{keyword}{val} f55 : (module M : \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}}) \ocamltag{arrow}{$\rightarrow$} \hyperref[xref-unresolved]{\ocamlinlinecode{M.\allowbreak{}t}}}\\ +\label{Ocaml_55--val-f'}\ocamlcodefragment{\ocamltag{keyword}{val} f' : (module M : \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}} \ocamltag{keyword}{with} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-X--type-t]{\ocamlinlinecode{t}} = int) \ocamltag{arrow}{$\rightarrow$} int}\\ +\label{Ocaml_55--val-f''}\ocamlcodefragment{\ocamltag{keyword}{val} f'' : (\ocamltag{keyword}{module} \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}} \ocamltag{keyword}{with} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-X--type-t]{\ocamlinlinecode{t}} = int) \ocamltag{arrow}{$\rightarrow$} int}\\ +\label{Ocaml_55--module-type-Y}\ocamlcodefragment{\ocamltag{keyword}{module} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}}\label{Ocaml_55-module-type-Y}\ocamlcodefragment{ = \ocamltag{keyword}{sig}}\begin{ocamlindent}\label{Ocaml_55-module-type-Y--type-t}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t}\\ +\label{Ocaml_55-module-type-Y--val-return}\ocamlcodefragment{\ocamltag{keyword}{val} return : \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a} \hyperref[Ocaml_55-module-type-Y--type-t]{\ocamlinlinecode{t}}}\\ +\end{ocamlindent}% +\ocamlcodefragment{\ocamltag{keyword}{end}}\\ +\label{Ocaml_55--val-g}\ocamlcodefragment{\ocamltag{keyword}{val} g : (module M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int \hyperref[xref-unresolved]{\ocamlinlinecode{M.\allowbreak{}t}}}\\ +\label{Ocaml_55--val-g'}\ocamlcodefragment{\ocamltag{keyword}{val} g' : (module M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int}\\ +\label{Ocaml_55--val-g''}\ocamlcodefragment{\ocamltag{keyword}{val} g'' : (\ocamltag{keyword}{module} \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int}\\ + + diff --git a/test/generators/latex/ocaml_55.targets b/test/generators/latex/ocaml_55.targets new file mode 100644 index 0000000000..6bb2d3d3da --- /dev/null +++ b/test/generators/latex/ocaml_55.targets @@ -0,0 +1 @@ +Ocaml_55.tex diff --git a/test/generators/man/Ocaml_55.3o b/test/generators/man/Ocaml_55.3o new file mode 100644 index 0000000000..672d3456e6 --- /dev/null +++ b/test/generators/man/Ocaml_55.3o @@ -0,0 +1,48 @@ + +.TH Ocaml_55 3 "" "Odoc" "OCaml Library" +.SH Name +Ocaml_55 +.SH Synopsis +.sp +.in 2 +\fBModule Ocaml_55\fR +.in +.sp +.SH Documentation +.sp +.nf +\f[CB]module\fR \f[CB]type\fR X = \f[CB]sig\fR +.br +.ti +2 +\f[CB]type\fR t +.sp +.ti +2 +\f[CB]val\fR x : int +.br +\f[CB]end\fR +.sp +\f[CB]type\fR m = (\f[CB]module\fR X) +.sp +\f[CB]val\fR f0 : m \f[CB]\->\fR unit +.sp +\f[CB]val\fR f55 : (module M : X) \f[CB]\->\fR M\.t +.sp +\f[CB]val\fR f' : (module M : X \f[CB]with\fR \f[CB]type\fR t = int) \f[CB]\->\fR int +.sp +\f[CB]val\fR f'' : (\f[CB]module\fR X \f[CB]with\fR \f[CB]type\fR t = int) \f[CB]\->\fR int +.sp +\f[CB]module\fR \f[CB]type\fR Y = \f[CB]sig\fR +.br +.ti +2 +\f[CB]type\fR 'a t +.sp +.ti +2 +\f[CB]val\fR return : \f[CB]'a\fR \f[CB]\->\fR \f[CB]'a\fR t +.br +\f[CB]end\fR +.sp +\f[CB]val\fR g : (module M : Y) \f[CB]\->\fR int M\.t +.sp +\f[CB]val\fR g' : (module M : Y) \f[CB]\->\fR int +.sp +\f[CB]val\fR g'' : (\f[CB]module\fR Y) \f[CB]\->\fR int diff --git a/test/generators/man/ocaml_55.targets b/test/generators/man/ocaml_55.targets new file mode 100644 index 0000000000..f540aa2e96 --- /dev/null +++ b/test/generators/man/ocaml_55.targets @@ -0,0 +1 @@ +Ocaml_55.3o diff --git a/test/generators/markdown/Ocaml_55-module-type-X.md b/test/generators/markdown/Ocaml_55-module-type-X.md new file mode 100644 index 0000000000..12faae1bf9 --- /dev/null +++ b/test/generators/markdown/Ocaml_55-module-type-X.md @@ -0,0 +1,9 @@ + +# Module type `Ocaml_55.X` + +```ocaml +type t +``` +```ocaml +val x : int +``` \ No newline at end of file diff --git a/test/generators/markdown/Ocaml_55-module-type-Y.md b/test/generators/markdown/Ocaml_55-module-type-Y.md new file mode 100644 index 0000000000..41457df468 --- /dev/null +++ b/test/generators/markdown/Ocaml_55-module-type-Y.md @@ -0,0 +1,9 @@ + +# Module type `Ocaml_55.Y` + +```ocaml +type 'a t +``` +```ocaml +val return : 'a -> 'a t +``` \ No newline at end of file diff --git a/test/generators/markdown/Ocaml_55.md b/test/generators/markdown/Ocaml_55.md new file mode 100644 index 0000000000..0c3cfc2328 --- /dev/null +++ b/test/generators/markdown/Ocaml_55.md @@ -0,0 +1,33 @@ + +# Module `Ocaml_55` + +```ocaml +module type X = sig ... end +``` +```ocaml +type m = (module X) +``` +```ocaml +val f0 : m -> unit +``` +```ocaml +val f55 : (module M : X) -> M.t +``` +```ocaml +val f' : (module M : X with type t = int) -> int +``` +```ocaml +val f'' : (module X with type t = int) -> int +``` +```ocaml +module type Y = sig ... end +``` +```ocaml +val g : (module M : Y) -> int M.t +``` +```ocaml +val g' : (module M : Y) -> int +``` +```ocaml +val g'' : (module Y) -> int +``` \ No newline at end of file diff --git a/test/generators/markdown/ocaml_55.targets b/test/generators/markdown/ocaml_55.targets new file mode 100644 index 0000000000..e59d9f384e --- /dev/null +++ b/test/generators/markdown/ocaml_55.targets @@ -0,0 +1,3 @@ +Ocaml_55.md +Ocaml_55-module-type-X.md +Ocaml_55-module-type-Y.md From 0db4523251e3865b47f20e32102a3fcb23074338 Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Wed, 8 Apr 2026 16:02:02 +0200 Subject: [PATCH 05/10] Add constraint on 5.5 test --- test/generators/gen_rules/gen_rules.ml | 1 + test/generators/html/Ocaml_55.html | 32 ++++++++++-------- test/generators/latex/Ocaml_55.tex | 8 ++--- test/generators/link.dune.inc | 46 +++++++++++++------------- test/generators/man/Ocaml_55.3o | 8 ++--- 5 files changed, 50 insertions(+), 45 deletions(-) diff --git a/test/generators/gen_rules/gen_rules.ml b/test/generators/gen_rules/gen_rules.ml index e20d5f64ab..1548f8a26d 100644 --- a/test/generators/gen_rules/gen_rules.ml +++ b/test/generators/gen_rules/gen_rules.ml @@ -67,6 +67,7 @@ let constraints = ("module_type_subst.mli", Min "4.13"); ("class_comments.mli", Min "4.08"); ("functor_ml.ml", Min "4.14"); + ("ocaml_55.mli", Min "5.5"); ("oxcaml.mli", OxCaml); ] diff --git a/test/generators/html/Ocaml_55.html b/test/generators/html/Ocaml_55.html index b4c2f77d7f..ebfb4bbe05 100644 --- a/test/generators/html/Ocaml_55.html +++ b/test/generators/html/Ocaml_55.html @@ -56,9 +56,10 @@

Module Ocaml_55

- val f55 : (module M : - X) - -> + val f55 : + (module M : + X) + -> M.t @@ -68,11 +69,12 @@

Module Ocaml_55

- val f' : (module M : - X - with type - t = int) - -> int + val f' : + (module M : + X + with type + t = int) + -> int
@@ -111,9 +113,10 @@

Module Ocaml_55

- val g : (module M : - Y) - -> + val g : + (module M : + Y) + -> int M.t @@ -123,9 +126,10 @@

Module Ocaml_55

- val g' : (module M : - Y) - -> int + val g' : + (module M : + Y) + -> int
diff --git a/test/generators/latex/Ocaml_55.tex b/test/generators/latex/Ocaml_55.tex index 23d3874e96..d04bf06def 100644 --- a/test/generators/latex/Ocaml_55.tex +++ b/test/generators/latex/Ocaml_55.tex @@ -5,15 +5,15 @@ \section{Module \ocamlinlinecode{Ocaml\_\allowbreak{}55}}\label{Ocaml_55}% \ocamlcodefragment{\ocamltag{keyword}{end}}\\ \label{Ocaml_55--type-m}\ocamlcodefragment{\ocamltag{keyword}{type} m = (\ocamltag{keyword}{module} \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}})}\\ \label{Ocaml_55--val-f0}\ocamlcodefragment{\ocamltag{keyword}{val} f0 : \hyperref[Ocaml_55--type-m]{\ocamlinlinecode{m}} \ocamltag{arrow}{$\rightarrow$} unit}\\ -\label{Ocaml_55--val-f55}\ocamlcodefragment{\ocamltag{keyword}{val} f55 : (module M : \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}}) \ocamltag{arrow}{$\rightarrow$} \hyperref[xref-unresolved]{\ocamlinlinecode{M.\allowbreak{}t}}}\\ -\label{Ocaml_55--val-f'}\ocamlcodefragment{\ocamltag{keyword}{val} f' : (module M : \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}} \ocamltag{keyword}{with} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-X--type-t]{\ocamlinlinecode{t}} = int) \ocamltag{arrow}{$\rightarrow$} int}\\ +\label{Ocaml_55--val-f55}\ocamlcodefragment{\ocamltag{keyword}{val} f55 : (\ocamltag{keyword}{module} M : \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}}) \ocamltag{arrow}{$\rightarrow$} \hyperref[xref-unresolved]{\ocamlinlinecode{M.\allowbreak{}t}}}\\ +\label{Ocaml_55--val-f'}\ocamlcodefragment{\ocamltag{keyword}{val} f' : (\ocamltag{keyword}{module} M : \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}} \ocamltag{keyword}{with} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-X--type-t]{\ocamlinlinecode{t}} = int) \ocamltag{arrow}{$\rightarrow$} int}\\ \label{Ocaml_55--val-f''}\ocamlcodefragment{\ocamltag{keyword}{val} f'' : (\ocamltag{keyword}{module} \hyperref[Ocaml_55-module-type-X]{\ocamlinlinecode{X}} \ocamltag{keyword}{with} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-X--type-t]{\ocamlinlinecode{t}} = int) \ocamltag{arrow}{$\rightarrow$} int}\\ \label{Ocaml_55--module-type-Y}\ocamlcodefragment{\ocamltag{keyword}{module} \ocamltag{keyword}{type} \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}}\label{Ocaml_55-module-type-Y}\ocamlcodefragment{ = \ocamltag{keyword}{sig}}\begin{ocamlindent}\label{Ocaml_55-module-type-Y--type-t}\ocamlcodefragment{\ocamltag{keyword}{type} 'a t}\\ \label{Ocaml_55-module-type-Y--val-return}\ocamlcodefragment{\ocamltag{keyword}{val} return : \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a} \hyperref[Ocaml_55-module-type-Y--type-t]{\ocamlinlinecode{t}}}\\ \end{ocamlindent}% \ocamlcodefragment{\ocamltag{keyword}{end}}\\ -\label{Ocaml_55--val-g}\ocamlcodefragment{\ocamltag{keyword}{val} g : (module M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int \hyperref[xref-unresolved]{\ocamlinlinecode{M.\allowbreak{}t}}}\\ -\label{Ocaml_55--val-g'}\ocamlcodefragment{\ocamltag{keyword}{val} g' : (module M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int}\\ +\label{Ocaml_55--val-g}\ocamlcodefragment{\ocamltag{keyword}{val} g : (\ocamltag{keyword}{module} M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int \hyperref[xref-unresolved]{\ocamlinlinecode{M.\allowbreak{}t}}}\\ +\label{Ocaml_55--val-g'}\ocamlcodefragment{\ocamltag{keyword}{val} g' : (\ocamltag{keyword}{module} M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int}\\ \label{Ocaml_55--val-g''}\ocamlcodefragment{\ocamltag{keyword}{val} g'' : (\ocamltag{keyword}{module} \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int}\\ diff --git a/test/generators/link.dune.inc b/test/generators/link.dune.inc index e43f6a0e59..88177118d6 100644 --- a/test/generators/link.dune.inc +++ b/test/generators/link.dune.inc @@ -548,7 +548,7 @@ (action (run ocamlc -c -bin-annot -o %{target} %{dep:cases/ocaml_55.mli})) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (target ocaml_55.odoc) @@ -556,7 +556,7 @@ (action (run odoc compile -o %{target} %{dep:ocaml_55.cmti})) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (target ocaml_55.odocl) @@ -564,7 +564,7 @@ (action (run odoc link -o %{target} %{dep:ocaml_55.odoc})) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (target ocamlary.cmti) @@ -7424,28 +7424,28 @@ . %{dep:../ocaml_55.odocl})) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55.html Ocaml_55.html.gen)) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55-module-type-X.html Ocaml_55-module-type-X.html.gen)) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55-module-type-Y.html Ocaml_55-module-type-Y.html.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir html @@ -7457,14 +7457,14 @@ ocaml_55.targets.gen (run odoc html-targets -o . %{dep:../ocaml_55.odocl} --flat))) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff ocaml_55.targets ocaml_55.targets.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir latex @@ -7474,14 +7474,14 @@ (action (run odoc latex-generate -o . --extra-suffix gen %{dep:../ocaml_55.odocl})) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55.tex Ocaml_55.tex.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir latex @@ -7493,14 +7493,14 @@ ocaml_55.targets.gen (run odoc latex-targets -o . %{dep:../ocaml_55.odocl}))) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff ocaml_55.targets ocaml_55.targets.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir man @@ -7510,14 +7510,14 @@ (action (run odoc man-generate -o . --extra-suffix gen %{dep:../ocaml_55.odocl})) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55.3o Ocaml_55.3o.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir man @@ -7529,14 +7529,14 @@ ocaml_55.targets.gen (run odoc man-targets -o . %{dep:../ocaml_55.odocl}))) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff ocaml_55.targets ocaml_55.targets.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir markdown @@ -7556,28 +7556,28 @@ gen %{dep:../ocaml_55.odocl})) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55.md Ocaml_55.md.gen)) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55-module-type-X.md Ocaml_55-module-type-X.md.gen)) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff Ocaml_55-module-type-Y.md Ocaml_55-module-type-Y.md.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir markdown @@ -7589,14 +7589,14 @@ ocaml_55.targets.gen (run odoc markdown-targets -o . %{dep:../ocaml_55.odocl}))) (enabled_if - (>= %{ocaml_version} 4.04))) + (>= %{ocaml_version} 5.5))) (rule (alias runtest) (package odoc) (action (diff ocaml_55.targets ocaml_55.targets.gen)) (enabled_if - (>= %{ocaml_version} 4.04)))) + (>= %{ocaml_version} 5.5)))) (subdir html diff --git a/test/generators/man/Ocaml_55.3o b/test/generators/man/Ocaml_55.3o index 672d3456e6..51f1e4ec17 100644 --- a/test/generators/man/Ocaml_55.3o +++ b/test/generators/man/Ocaml_55.3o @@ -25,9 +25,9 @@ Ocaml_55 .sp \f[CB]val\fR f0 : m \f[CB]\->\fR unit .sp -\f[CB]val\fR f55 : (module M : X) \f[CB]\->\fR M\.t +\f[CB]val\fR f55 : (\f[CB]module\fR M : X) \f[CB]\->\fR M\.t .sp -\f[CB]val\fR f' : (module M : X \f[CB]with\fR \f[CB]type\fR t = int) \f[CB]\->\fR int +\f[CB]val\fR f' : (\f[CB]module\fR M : X \f[CB]with\fR \f[CB]type\fR t = int) \f[CB]\->\fR int .sp \f[CB]val\fR f'' : (\f[CB]module\fR X \f[CB]with\fR \f[CB]type\fR t = int) \f[CB]\->\fR int .sp @@ -41,8 +41,8 @@ Ocaml_55 .br \f[CB]end\fR .sp -\f[CB]val\fR g : (module M : Y) \f[CB]\->\fR int M\.t +\f[CB]val\fR g : (\f[CB]module\fR M : Y) \f[CB]\->\fR int M\.t .sp -\f[CB]val\fR g' : (module M : Y) \f[CB]\->\fR int +\f[CB]val\fR g' : (\f[CB]module\fR M : Y) \f[CB]\->\fR int .sp \f[CB]val\fR g'' : (\f[CB]module\fR Y) \f[CB]\->\fR int From 4c2023d24c790dff8d24c858922badf76d23203c Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Wed, 8 Apr 2026 17:48:39 +0200 Subject: [PATCH 06/10] Remove odoc-parser upper bound on ocaml version --- odoc-parser.opam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoc-parser.opam b/odoc-parser.opam index 139c584a11..8db379515a 100644 --- a/odoc-parser.opam +++ b/odoc-parser.opam @@ -14,7 +14,7 @@ dev-repo: "git+https://github.com/ocaml/odoc.git" doc: "https://ocaml.github.io/odoc/odoc_parser" depends: [ "dune" {>= "3.21"} - "ocaml" {>= "4.08.0" & <= "5.5.1"} + "ocaml" {>= "4.08.0"} "astring" "camlp-streams" "ppx_expect" {with-test} From a90cc6e1ce090c3584a13e5388423453d2f9153e Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Wed, 8 Apr 2026 18:06:40 +0200 Subject: [PATCH 07/10] Add changelog entry for #1406 --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index f7d64d2f91..fb32f45690 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ - `markdown-generate` command now accepts multiple `.odocl` files in a single invocation, eliminating the need for shell scripting (@davesnx, #1387) - Support for OxCaml (@lukemaurer, @art-w, #1399) +- OCaml 5.5.0 support (@panglesd, @xvw, #1406) ### Fixed - Fix compile-time crashing bugs #930 and #1385 (@jonludlam, #1400) From fdf71a2a30c7184903072cc8064b671cd808488e Mon Sep 17 00:00:00 2001 From: Paul-Elliot Date: Wed, 15 Apr 2026 11:21:50 +0200 Subject: [PATCH 08/10] Add test for polymorphic argument in 5.5 --- test/generators/cases/ocaml_55.mli | 2 ++ test/generators/html/Ocaml_55.html | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/test/generators/cases/ocaml_55.mli b/test/generators/cases/ocaml_55.mli index f3fe822dec..e41d207f12 100644 --- a/test/generators/cases/ocaml_55.mli +++ b/test/generators/cases/ocaml_55.mli @@ -17,3 +17,5 @@ val g : (module M : Y) -> int M.t val g' : (module M : Y) -> int val g'' : (module Y) -> int + +val map2: ('a. 'a -> 'a) -> 'a * 'b -> 'a * 'b diff --git a/test/generators/html/Ocaml_55.html b/test/generators/html/Ocaml_55.html index ebfb4bbe05..4f31ef681f 100644 --- a/test/generators/html/Ocaml_55.html +++ b/test/generators/html/Ocaml_55.html @@ -148,6 +148,28 @@

Module Ocaml_55

+
+
+ + + val map2 : + + ('a. + 'a + -> + 'a) + -> + + + ('a * + 'b) + -> + 'a * + 'b + + +
+
From baa1bbf46a6dd9b6934f902ad5f8c32b9fb7dc7d Mon Sep 17 00:00:00 2001 From: Jon Ludlam Date: Thu, 16 Apr 2026 16:32:51 +0100 Subject: [PATCH 09/10] Promote tests --- test/generators/latex/Ocaml_55.tex | 1 + test/generators/man/Ocaml_55.3o | 2 ++ test/generators/markdown/Ocaml_55.md | 3 ++ test/generators/markdown/Recent-X.md | 8 ++--- test/generators/markdown/Recent-Z-Y-X.md | 2 +- test/generators/markdown/Recent-Z-Y.md | 2 +- test/generators/markdown/Recent-Z.md | 2 +- .../markdown/Recent-module-type-PolyS.md | 12 ++----- .../markdown/Recent-module-type-S1.md | 2 +- test/generators/markdown/Recent.md | 34 +++++++++---------- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/test/generators/latex/Ocaml_55.tex b/test/generators/latex/Ocaml_55.tex index d04bf06def..de2466d441 100644 --- a/test/generators/latex/Ocaml_55.tex +++ b/test/generators/latex/Ocaml_55.tex @@ -15,5 +15,6 @@ \section{Module \ocamlinlinecode{Ocaml\_\allowbreak{}55}}\label{Ocaml_55}% \label{Ocaml_55--val-g}\ocamlcodefragment{\ocamltag{keyword}{val} g : (\ocamltag{keyword}{module} M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int \hyperref[xref-unresolved]{\ocamlinlinecode{M.\allowbreak{}t}}}\\ \label{Ocaml_55--val-g'}\ocamlcodefragment{\ocamltag{keyword}{val} g' : (\ocamltag{keyword}{module} M : \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int}\\ \label{Ocaml_55--val-g''}\ocamlcodefragment{\ocamltag{keyword}{val} g'' : (\ocamltag{keyword}{module} \hyperref[Ocaml_55-module-type-Y]{\ocamlinlinecode{Y}}) \ocamltag{arrow}{$\rightarrow$} int}\\ +\label{Ocaml_55--val-map2}\ocamlcodefragment{\ocamltag{keyword}{val} map2 : ('a.\allowbreak{} \ocamltag{type-var}{'a} \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a}) \ocamltag{arrow}{$\rightarrow$} (\ocamltag{type-var}{'a} * \ocamltag{type-var}{'b}) \ocamltag{arrow}{$\rightarrow$} \ocamltag{type-var}{'a} * \ocamltag{type-var}{'b}}\\ diff --git a/test/generators/man/Ocaml_55.3o b/test/generators/man/Ocaml_55.3o index 51f1e4ec17..e4ed83e9a2 100644 --- a/test/generators/man/Ocaml_55.3o +++ b/test/generators/man/Ocaml_55.3o @@ -46,3 +46,5 @@ Ocaml_55 \f[CB]val\fR g' : (\f[CB]module\fR M : Y) \f[CB]\->\fR int .sp \f[CB]val\fR g'' : (\f[CB]module\fR Y) \f[CB]\->\fR int +.sp +\f[CB]val\fR map2 : ('a\. \f[CB]'a\fR \f[CB]\->\fR \f[CB]'a\fR) \f[CB]\->\fR (\f[CB]'a\fR * \f[CB]'b\fR) \f[CB]\->\fR \f[CB]'a\fR * \f[CB]'b\fR diff --git a/test/generators/markdown/Ocaml_55.md b/test/generators/markdown/Ocaml_55.md index 0c3cfc2328..5d4a34978a 100644 --- a/test/generators/markdown/Ocaml_55.md +++ b/test/generators/markdown/Ocaml_55.md @@ -30,4 +30,7 @@ val g' : (module M : Y) -> int ``` ```ocaml val g'' : (module Y) -> int +``` +```ocaml +val map2 : ('a. 'a -> 'a) -> ('a * 'b) -> 'a * 'b ``` \ No newline at end of file diff --git a/test/generators/markdown/Recent-X.md b/test/generators/markdown/Recent-X.md index d1d4858704..480cf2e22b 100644 --- a/test/generators/markdown/Recent-X.md +++ b/test/generators/markdown/Recent-X.md @@ -1,15 +1,15 @@ # Module `Recent.X` -``` +```ocaml module L := Z.Y ``` -``` +```ocaml type t = int L.X.t ``` -``` +```ocaml type u := int ``` -``` +```ocaml type v = u L.X.t ``` \ No newline at end of file diff --git a/test/generators/markdown/Recent-Z-Y-X.md b/test/generators/markdown/Recent-Z-Y-X.md index 74a5fc997c..8c3d0d18c3 100644 --- a/test/generators/markdown/Recent-Z-Y-X.md +++ b/test/generators/markdown/Recent-Z-Y-X.md @@ -1,6 +1,6 @@ # Module `Y.X` -``` +```ocaml type 'a t ``` \ No newline at end of file diff --git a/test/generators/markdown/Recent-Z-Y.md b/test/generators/markdown/Recent-Z-Y.md index 93d7cc96e6..15ba3da283 100644 --- a/test/generators/markdown/Recent-Z-Y.md +++ b/test/generators/markdown/Recent-Z-Y.md @@ -1,6 +1,6 @@ # Module `Z.Y` -``` +```ocaml module X : sig ... end ``` \ No newline at end of file diff --git a/test/generators/markdown/Recent-Z.md b/test/generators/markdown/Recent-Z.md index fa06f69c30..86bd9aaa3f 100644 --- a/test/generators/markdown/Recent-Z.md +++ b/test/generators/markdown/Recent-Z.md @@ -1,6 +1,6 @@ # Module `Recent.Z` -``` +```ocaml module Y : sig ... end ``` \ No newline at end of file diff --git a/test/generators/markdown/Recent-module-type-PolyS.md b/test/generators/markdown/Recent-module-type-PolyS.md index f43d7afa3f..0edf1a9682 100644 --- a/test/generators/markdown/Recent-module-type-PolyS.md +++ b/test/generators/markdown/Recent-module-type-PolyS.md @@ -1,15 +1,9 @@ # Module type `Recent.PolyS` -``` +```ocaml type t = [ -``` -``` -| `A -``` -``` -| `B -``` -``` + | `A + | `B ] ``` \ No newline at end of file diff --git a/test/generators/markdown/Recent-module-type-S1.md b/test/generators/markdown/Recent-module-type-S1.md index fc503f25e1..63a7cbe0a7 100644 --- a/test/generators/markdown/Recent-module-type-S1.md +++ b/test/generators/markdown/Recent-module-type-S1.md @@ -4,7 +4,7 @@ ## Parameters -``` +```ocaml module _ : S ``` diff --git a/test/generators/markdown/Recent.md b/test/generators/markdown/Recent.md index 837f7894da..95e87797bb 100644 --- a/test/generators/markdown/Recent.md +++ b/test/generators/markdown/Recent.md @@ -1,13 +1,13 @@ # Module `Recent` -``` +```ocaml module type S = sig ... end ``` -``` +```ocaml module type S1 = functor (_ : S) -> S ``` -``` +```ocaml type variant = | A | B of int @@ -17,7 +17,7 @@ type variant = a : int; } ``` -``` +```ocaml type _ gadt = | A : int gadt | B : int -> string gadt (* foo *) @@ -25,7 +25,7 @@ type _ gadt = a : int; } -> unit gadt ``` -``` +```ocaml type polymorphic_variant = [ | `A | `B of int @@ -33,38 +33,38 @@ type polymorphic_variant = [ | `D (* bar *) ] ``` -``` +```ocaml type empty_variant = | ``` -``` +```ocaml type nonrec nonrec_ = int ``` -``` +```ocaml type empty_conj = | X : [< `X of & 'a & int * float ] -> empty_conj ``` -``` +```ocaml type conj = | X : [< `X of int & [< `B of int & float ] ] -> conj ``` -``` +```ocaml val empty_conj : [< `X of & 'a & int * float ] ``` -``` +```ocaml val conj : [< `X of int & [< `B of int & float ] ] ``` -``` +```ocaml module Z : sig ... end ``` -``` +```ocaml module X : sig ... end ``` -``` +```ocaml module type PolyS = sig ... end ``` -``` +```ocaml type +-'a phantom ``` -``` +```ocaml val f : (x:int * y:int) phantom -> unit -``` +``` \ No newline at end of file From 3c1811be2a14687ad284b6fa05bf821dac28243c Mon Sep 17 00:00:00 2001 From: Jon Ludlam Date: Thu, 16 Apr 2026 16:33:07 +0100 Subject: [PATCH 10/10] Don't rely on the output of cmdliner errors in tests --- test/search/html_search.t/run.t | 6 +----- test/sources/lookup_def.t/run.t | 6 +----- test/sources/source.t/run.t | 28 +++++----------------------- 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/test/search/html_search.t/run.t b/test/search/html_search.t/run.t index 3f39c790d8..ff4a2f7fde 100644 --- a/test/search/html_search.t/run.t +++ b/test/search/html_search.t/run.t @@ -215,11 +215,7 @@ Testing the warnings/errors for the `compile-index` command: Passing an inexistent file: $ odoc compile-index --root babar - $ odoc compile-index --file-list babar - odoc: option '--file-list': no 'babar' file or directory - Usage: odoc compile-index [OPTION]… [FILE]… - Try 'odoc compile-index --help' or 'odoc --help' for more information. - [2] + $ ! odoc compile-index --file-list babar > /dev/null 2>&1 Passing an empty folder is allowed: diff --git a/test/sources/lookup_def.t/run.t b/test/sources/lookup_def.t/run.t index 7877163102..e40ea74ca8 100644 --- a/test/sources/lookup_def.t/run.t +++ b/test/sources/lookup_def.t/run.t @@ -5,11 +5,7 @@ Compile the modules: $ odoc compile-impl --source-id src/a.ml -I . a.cmt $ odoc compile -I . a.cmti - $ odoc link -I . src-a.odoc - odoc: FILE.odoc argument: no 'src-a.odoc' file or directory - Usage: odoc link [--custom-layout] [--open=MODULE] [OPTION]… FILE.odoc - Try 'odoc link --help' or 'odoc --help' for more information. - [2] + $ ! odoc link -I . src-a.odoc > /dev/null 2>&1 $ odoc link -I . a.odoc Show the locations: diff --git a/test/sources/source.t/run.t b/test/sources/source.t/run.t index 5ec6c77e46..020ee1b1db 100644 --- a/test/sources/source.t/run.t +++ b/test/sources/source.t/run.t @@ -386,29 +386,11 @@ Ids generated in the source code: Html generation for implementation and mld/interface uses different commands - $ odoc html-generate-source --indent -o html a.odocl - odoc: required option --impl is missing - Usage: odoc html-generate-source [OPTION]… FILE.ml - Try 'odoc html-generate-source --help' or 'odoc --help' for more information. - [2] - $ odoc html-generate-source --indent -o html --impl a.odocl a.ml - ERROR: Expected an implementation unit - [1] - $ odoc html-generate-source --indent -o html --impl impl-a.odocl - odoc: required argument FILE.ml is missing - Usage: odoc html-generate-source [OPTION]… FILE.ml - Try 'odoc html-generate-source --help' or 'odoc --help' for more information. - [2] - $ odoc html-generate-source --indent -o html a.ml - odoc: required option --impl is missing - Usage: odoc html-generate-source [OPTION]… FILE.ml - Try 'odoc html-generate-source --help' or 'odoc --help' for more information. - [2] - $ odoc html-generate --source a.ml --indent -o html impl-a.odocl - odoc: unknown option '--source'. - Usage: odoc html-generate [OPTION]… FILE.odocl… - Try 'odoc html-generate --help' or 'odoc --help' for more information. - [2] + $ ! odoc html-generate-source --indent -o html a.odocl > /dev/null 2>&1 + $ ! odoc html-generate-source --indent -o html --impl a.odocl a.ml > /dev/null 2>&1 + $ ! odoc html-generate-source --indent -o html --impl impl-a.odocl > /dev/null 2>&1 + $ ! odoc html-generate-source --indent -o html a.ml > /dev/null 2>&1 + $ ! odoc html-generate --source a.ml --indent -o html impl-a.odocl > /dev/null 2>&1 Compiling without --source-id makes it impossible to generate the source: