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) diff --git a/odoc-parser.opam b/odoc-parser.opam index 92935df19a..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"} + "ocaml" {>= "4.08.0"} "astring" "camlp-streams" "ppx_expect" {with-test} diff --git a/odoc.opam b/odoc.opam index 62478fe47c..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"} + "ocaml" {>= "4.08.0" & < "5.6"} "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 db7bfd1ba3..06270d51a0 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -300,7 +300,13 @@ 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 (_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 #elif OCAML_VERSION>=(4,13,0) @@ -428,6 +434,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 +563,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) @@ -563,22 +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 (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 @@ -592,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 @@ -811,6 +845,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 +930,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..e74246692e 100644 --- a/src/loader/cmti.ml +++ b/src/loader/cmti.ml @@ -173,22 +173,15 @@ 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; _} -> #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 *) @@ -199,8 +192,33 @@ 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 (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 @@ -333,6 +351,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 +365,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 +686,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..f8671d735f 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 @@ -660,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/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) 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/cases/ocaml_55.mli b/test/generators/cases/ocaml_55.mli new file mode 100644 index 0000000000..e41d207f12 --- /dev/null +++ b/test/generators/cases/ocaml_55.mli @@ -0,0 +1,21 @@ +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 + +val map2: ('a. 'a -> 'a) -> 'a * 'b -> 'a * 'b 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-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 @@ + + +
Ocaml_55.XOcaml_55.Y
+ val return :
+ 'a
+ ->
+
+ 'a t
+
+
+ Ocaml_55
+ module
+ type
+ X
+
+ = sig ...
+ end
+
+
+ type m
+ =
+ (module
+ X)
+
+
+
+
+ val f0 :
+ m ->
+ unit
+
+
+
+ val f55 :
+ (module M :
+ X)
+ ->
+ M.t
+
+
+
+ module
+ type
+ Y
+
+ = sig ...
+ end
+
+
+
+ val g :
+ (module M :
+ Y)
+ ->
+ int M.t
+
+
+
+ val g' :
+ (module M :
+ Y)
+ -> int
+
+
+
+ val g'' :
+
+ (module
+ Y)
+ ->
+ int
+
+
+