diff --git a/CHANGES.md b/CHANGES.md index 551d12f499..71b09b3710 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,6 @@ # Unreleased +- Support for OCaml 5.6 (@jonludlam, #1472) - Support for OxCaml unboxed named types (@art-w, #1407) - Support for OxCaml zero alloc definitions (@Leonidas-from-XIV, #1422, #1444) - Remove requirement for ppx_expect in tests (@jonludlam, #1445) diff --git a/odoc.opam b/odoc.opam index 21565bd8b4..6339ffe05c 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.6"} + "ocaml" {>= "4.08.0" & < "5.7"} "tyxml" {>= "4.4.0"} "fmt" "crunch" {>= "1.4.1"} diff --git a/src/loader/cmi.ml b/src/loader/cmi.ml index bc30e26666..3efe11f192 100644 --- a/src/loader/cmi.ml +++ b/src/loader/cmi.ml @@ -46,7 +46,18 @@ module Compat = struct versions *) let repr x = Transient_expr.repr x +#if OCAML_VERSION >= (5,6,0) + (** Since 5.6, abbreviation expansion happens in place in the type graph and + the original abbreviation is remembered in the [Texpand] edge that + replaced it. [Types.get_desc] walks past those edges and would hand us + the expanded type, so use the same accessor the compiler's own printer + uses ([Out_type.printer_get_desc]) to recover the abbreviation. *) + let get_desc ty = Btype.get_folded_desc ~keep_Tvar:true ty + let deep_occur = Btype.deep_occur +#else let get_desc = Types.get_desc + let deep_occur = Ctype.deep_occur +#endif let get_row_name = Types.row_name let row_field_repr = Types.row_field_repr let field_kind_repr = Types.field_kind_repr @@ -69,6 +80,7 @@ module Compat = struct type repr_type_node = Types.type_expr let repr = Btype.repr let get_desc x = (repr x).Types.desc + let deep_occur = Ctype.deep_occur let get_row_name x = x.Types.row_name let row_field_repr = Btype.row_field_repr let field_kind_repr = Btype.field_kind_repr @@ -313,6 +325,10 @@ let mark_type ty = | Tsubst (ty,_) -> loop visited ty #endif | Tlink _ -> assert false +#if OCAML_VERSION >= (5,6,0) + (* [Compat.get_desc] walks past [Texpand] just as it does [Tlink]. *) + | Texpand _ -> assert false +#endif #if defined OXCAML | Tquote typ -> loop visited typ | Tsplice typ -> loop visited typ @@ -459,7 +475,7 @@ let rec mark_class_type params = function let sty = Compat.self_type cty in if is_row_visited (proxy sty) || List.exists aliasable params - || List.exists (Ctype.deep_occur sty) tyl + || List.exists (Compat.deep_occur sty) tyl then mark_class_type params cty else List.iter mark_type tyl | Cty_signature sign -> @@ -663,6 +679,10 @@ let rec read_type_expr env typ = #endif | Tlink _ -> assert false +#if OCAML_VERSION >= (5,6,0) + (* [Compat.get_desc] walks past [Texpand] just as it does [Tlink]. *) + | Texpand _ -> assert false +#endif #if defined OXCAML | Tquote typ -> Quote (read_type_expr env typ) | Tsplice typ -> Splice (read_type_expr env typ) diff --git a/src/loader/cmt.ml b/src/loader/cmt.ml index d00b5d3e97..5ae29ac6bd 100644 --- a/src/loader/cmt.ml +++ b/src/loader/cmt.ml @@ -524,8 +524,13 @@ and read_structure_item env parent item = | Tstr_eval _ -> [] | Tstr_value(_, vbs) -> read_value_bindings env parent vbs +#if OCAML_VERSION >= (5,6,0) + | Tstr_primitive pd -> + [Cmti.read_primitive_description env parent pd] +#else | Tstr_primitive vd -> [Cmti.read_value_description env parent vd] +#endif | Tstr_type (rec_flag, decls) -> let rec_flag = match rec_flag with diff --git a/src/loader/cmti.ml b/src/loader/cmti.ml index 10fda71abc..5025a282a9 100644 --- a/src/loader/cmti.ml +++ b/src/loader/cmti.ml @@ -200,14 +200,64 @@ let read_value_description env parent vd = let doc = Doc_attr.attached_no_tag ~warnings_tag:env.warnings_tag container vd.val_attributes in let type_ = read_core_type env container vd.val_desc in let value = +#if OCAML_VERSION >= (5,6,0) + (* Since 5.6 externals have their own node, so a [val] is never one. *) + Value.Abstract +#else match vd.val_prim with | [] -> Value.Abstract | primitives -> External primitives +#endif in let ext_attrs = Doc_attr.attrs_of_value_description vd.val_val in let modalities = Cmi.read_value_descr_modalities vd.val_val in Value { Value.id; source_loc; doc; type_; value; ext_attrs; modalities } +#if OCAML_VERSION >= (5,6,0) +(* Since 5.6 (RFC 44) [external] declarations have their own Typedtree node, + because they can now also be written as an alias of an existing primitive: + [external x : t = M.y], or [external x = M.y] with the type left implicit. + An alias carries no primitive strings of its own, so recover them from the + resolved [Types.value_description] the way the .cmi reader does. *) +let read_primitive_description env parent pd = + let open Signature in + let id = Env.find_value_identifier env.ident_env pd.prim_id in + let source_loc = None in + let container = + (parent : Identifier.Signature.t :> Identifier.LabelParent.t) + in + let doc = + Doc_attr.attached_no_tag ~warnings_tag:env.warnings_tag container + pd.prim_attributes + in + let type_ = + match pd.prim_kind with + | Tprim_decl (core_type, _) | Tprim_alias (Some core_type, _, _) -> + read_core_type env container core_type + | Tprim_alias (None, _, _) -> + (* No type written at the declaration site: use the inferred one. *) + Cmi.mark_type_expr pd.prim_val.val_type; + Cmi.read_type_expr env pd.prim_val.val_type + in + let value = + match pd.prim_kind with + | Tprim_decl (_, primitives) -> Value.External primitives + | Tprim_alias _ -> ( + match pd.prim_val.val_kind with + | Val_prim desc -> + let open Primitive in + Value.External + (desc.prim_name + :: (match desc.prim_native_name with + | "" -> [] + | name -> [ name ])) + | _ -> Value.Abstract) + in + let ext_attrs = Doc_attr.attrs_of_value_description pd.prim_val in + let modalities = Cmi.read_value_descr_modalities pd.prim_val in + Value { Value.id; source_loc; doc; type_; value; ext_attrs; modalities } +#endif + let read_type_parameter (ctyp, var_and_injectivity) = let open TypeDecl in let desc, kind = @@ -804,6 +854,10 @@ and read_signature_item env parent item = match item.sig_desc with | Tsig_value vd -> [read_value_description env parent vd] +#if OCAML_VERSION >= (5,6,0) + | Tsig_primitive pd -> + [read_primitive_description env parent pd] +#endif | Tsig_type (rec_flag, decls) -> let rec_flag = match rec_flag with diff --git a/src/loader/cmti.mli b/src/loader/cmti.mli index d2e5905a2d..bb46122320 100644 --- a/src/loader/cmti.mli +++ b/src/loader/cmti.mli @@ -49,6 +49,14 @@ val read_value_description : Typedtree.value_description -> Odoc_model.Lang.Signature.item +#if OCAML_VERSION >= (5,6,0) +val read_primitive_description : + Cmi.env -> + Paths.Identifier.Signature.t -> + Typedtree.primitive_description -> + Odoc_model.Lang.Signature.item +#endif + val read_type_declarations : Cmi.env -> Paths.Identifier.Signature.t -> diff --git a/src/loader/ident_env.ml b/src/loader/ident_env.ml index 3dd81576c8..2e85e7b3a2 100644 --- a/src/loader/ident_env.ml +++ b/src/loader/ident_env.ml @@ -253,7 +253,11 @@ let rec extract_signature_tree_items : bool -> Typedtree.signature_item list -> mds @ extract_signature_tree_items hide_item rest #endif | { sig_desc = Tsig_value {val_id; _}; sig_loc; _ } :: rest-> - [`Value (val_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest + [`Value (val_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest +#if OCAML_VERSION >= (5,6,0) + | { sig_desc = Tsig_primitive {prim_id; _}; sig_loc; _ } :: rest-> + [`Value (prim_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest +#endif | { sig_desc = Tsig_modtype mtd; sig_loc; _} :: rest -> [`ModuleType (mtd.mtd_id, hide_item, Some sig_loc)] @ extract_signature_tree_items hide_item rest #if defined OXCAML @@ -450,8 +454,13 @@ let rec extract_structure_tree_items : bool -> Typedtree.structure_item list -> )) cltyps @ extract_structure_tree_items hide_item rest | { str_desc = Tstr_open o; _ } :: rest -> ((extract_extended_open o) :> items list) @ extract_structure_tree_items hide_item rest +#if OCAML_VERSION >= (5,6,0) + | { str_desc = Tstr_primitive {prim_id; _}; str_loc; _ } :: rest -> + [`Value (prim_id, false, Some str_loc)] @ extract_structure_tree_items hide_item rest +#else | { str_desc = Tstr_primitive {val_id; _}; str_loc; _ } :: rest -> [`Value (val_id, false, Some str_loc)] @ extract_structure_tree_items hide_item rest +#endif | { str_desc = Tstr_eval _; _} :: rest -> extract_structure_tree_items hide_item rest #if defined OXCAML | { str_desc = Tstr_jkind _; _ } :: rest -> extract_structure_tree_items hide_item rest diff --git a/src/loader/implementation.ml b/src/loader/implementation.ml index 792f1fb35c..d9c6b3d459 100644 --- a/src/loader/implementation.ml +++ b/src/loader/implementation.ml @@ -38,6 +38,9 @@ module Env = struct | Tsig_exception _ | Tsig_modsubst _ | Tsig_open _ | Tsig_include _ | Tsig_class _ | Tsig_class_type _ | Tsig_attribute _ -> () +#if OCAML_VERSION >= (5,6,0) + | Tsig_primitive _ -> () +#endif #if defined OXCAML | Tsig_jkind _ -> () #endif diff --git a/src/model/compat.cppo.ml b/src/model/compat.cppo.ml index f9aef91fbf..3c60bc4e70 100644 --- a/src/model/compat.cppo.ml +++ b/src/model/compat.cppo.ml @@ -210,6 +210,9 @@ let shape_info_of_cmt_infos : Cmt_format.cmt_infos -> (shape * uid_to_loc) optio let open Typedtree in function | Value v -> v.val_loc +#if OCAML_VERSION >= (5,6,0) + | Primitive p -> p.prim_loc +#endif | Value_binding vb -> vb.vb_pat.pat_loc | Type t -> t.typ_loc | Constructor c -> c.cd_loc diff --git a/test/generators/cases/ocaml_56.mli b/test/generators/cases/ocaml_56.mli new file mode 100644 index 0000000000..b121f5d07a --- /dev/null +++ b/test/generators/cases/ocaml_56.mli @@ -0,0 +1,13 @@ +(** Features introduced in OCaml 5.6. *) + +type ext = external "gmp" +(** An external type declaration. *) + +external classic : int -> int = "caml_classic" "caml_classic_native" +(** A classic external declaration. *) + +external alias_with_type : int -> int = classic +(** A primitive alias declaring its type. *) + +external alias_no_type = classic +(** A primitive alias leaving its type implicit. *) diff --git a/test/generators/gen_rules/gen_rules.ml b/test/generators/gen_rules/gen_rules.ml index a1be5a3e9f..456b527e58 100644 --- a/test/generators/gen_rules/gen_rules.ml +++ b/test/generators/gen_rules/gen_rules.ml @@ -68,6 +68,7 @@ let constraints = ("class_comments.mli", Min "4.08"); ("functor_ml.ml", Min "4.14"); ("ocaml_55.mli", Min "5.5"); + ("ocaml_56.mli", Min "5.6"); ("oxcaml.mli", OxCaml); ("oxcaml_impl.ml", OxCaml); ] diff --git a/test/generators/html/Ocaml_56.html b/test/generators/html/Ocaml_56.html new file mode 100644 index 0000000000..3e7c98d3c7 --- /dev/null +++ b/test/generators/html/Ocaml_56.html @@ -0,0 +1,60 @@ + + +
Ocaml_56Features introduced in OCaml 5.6.
+