diff --git a/CHANGES.md b/CHANGES.md index 88775b03..0694e67d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,8 @@ unreleased - Remove reduntant module type copy from migrate_504_503, preventing exponential blowup with many "with" constraints. (#644, @smuenzel) +- Fix the 5.4/5.3 migration of attributes on package types (#650, @dra27) + 0.38.0 ------ diff --git a/astlib/encoding_504.ml b/astlib/encoding_504.ml index 771e524f..028632a5 100644 --- a/astlib/encoding_504.ml +++ b/astlib/encoding_504.ml @@ -10,6 +10,11 @@ module Ext_name = struct let bivariant_pmty_with = "ppxlib.migration.bivariant_pmty_with_5_4" end +module Attr_name = struct + (* An attribute name used for splitting package type attributes. *) + let split_package_attributes = "ppxlib.migration.split_package_attributes_5_4" +end + let invalid_encoding ~loc name = Error.invalid_encoding ~loc ~version:"5.4" name module type AST = sig diff --git a/astlib/encoding_504.mli b/astlib/encoding_504.mli index a6ec797b..220a4dcb 100644 --- a/astlib/encoding_504.mli +++ b/astlib/encoding_504.mli @@ -7,6 +7,10 @@ module Ext_name : sig val bivariant_pmty_with : string end +module Attr_name : sig + val split_package_attributes : string +end + module To_503 : sig open Ast_503.Asttypes open Ast_503.Parsetree diff --git a/astlib/migrate_503_504.ml b/astlib/migrate_503_504.ml index b492b148..cc057a0d 100644 --- a/astlib/migrate_503_504.ml +++ b/astlib/migrate_503_504.ml @@ -406,12 +406,43 @@ and copy_core_type : Ast_503.Parsetree.core_type -> Ast_504.Parsetree.core_type Ast_503.Parsetree.ptyp_loc_stack; Ast_503.Parsetree.ptyp_attributes; } -> - { - Ast_504.Parsetree.ptyp_desc = copy_core_type_desc ptyp_desc; - Ast_504.Parsetree.ptyp_loc = copy_location ptyp_loc; - Ast_504.Parsetree.ptyp_loc_stack = copy_location_stack ptyp_loc_stack; - Ast_504.Parsetree.ptyp_attributes = copy_attributes ptyp_attributes; - } + match ptyp_desc with + | Ptyp_package (name, constraints) -> + let rec split_attributes (typ, pkg) = function + | [] -> (List.rev typ, List.rev pkg) + | attr :: attrs + when String.equal attr.Ast_503.Parsetree.attr_name.txt + Encoding_504.Attr_name.split_package_attributes -> + (List.rev typ, attrs) + | attr :: attrs -> split_attributes (attr :: typ, pkg) attrs + in + let typ_attrs, pkg_attrs = split_attributes ([], []) ptyp_attributes in + let pkg : Ast_504.Parsetree.package_type = + { + ppt_path = copy_loc (copy_Longident_t ~loc:name.loc) name; + ppt_cstrs = + List.map + (fun (a, b) -> + ( copy_loc (copy_Longident_t ~loc:a.Ast_503.Asttypes.loc) a, + copy_core_type b )) + constraints; + ppt_loc = ptyp_loc; + ppt_attrs = copy_attributes pkg_attrs; + } + in + { + Ast_504.Parsetree.ptyp_desc = Ast_504.Parsetree.Ptyp_package pkg; + Ast_504.Parsetree.ptyp_loc = copy_location ptyp_loc; + Ast_504.Parsetree.ptyp_loc_stack = copy_location_stack ptyp_loc_stack; + Ast_504.Parsetree.ptyp_attributes = copy_attributes typ_attrs; + } + | _ -> + { + Ast_504.Parsetree.ptyp_desc = copy_core_type_desc ptyp_desc; + Ast_504.Parsetree.ptyp_loc = copy_location ptyp_loc; + Ast_504.Parsetree.ptyp_loc_stack = copy_location_stack ptyp_loc_stack; + Ast_504.Parsetree.ptyp_attributes = copy_attributes ptyp_attributes; + } and copy_location_stack : Ast_503.Parsetree.location_stack -> Ast_504.Parsetree.location_stack = diff --git a/astlib/migrate_504_503.ml b/astlib/migrate_504_503.ml index 0767d96e..63f17b58 100644 --- a/astlib/migrate_504_503.ml +++ b/astlib/migrate_504_503.ml @@ -12,6 +12,17 @@ end let bivariant_error ~loc = Error.migration_error ~loc ~from:"5.4" ~to_:"5.3" "bivariant type parameters" +let split_package_attr = + let attr_name = + Ast_503.Asttypes. + { + txt = Encoding_504.Attr_name.split_package_attributes; + loc = Location.none; + } + in + Ast_503.Parsetree. + { attr_name; attr_loc = Location.none; attr_payload = PStr [] } + let rec copy_toplevel_phrase : Ast_504.Parsetree.toplevel_phrase -> Ast_503.Parsetree.toplevel_phrase = function @@ -194,7 +205,8 @@ and copy_expression_desc ~loc : ptyp_desc = package; ptyp_loc = Location.none; ptyp_loc_stack = []; - ptyp_attributes = []; + ptyp_attributes = + split_package_attr :: copy_attributes c.Ast_504.Parsetree.ppt_attrs; } in Ast_503.Parsetree.Pexp_constraint (exp, ct) @@ -403,11 +415,18 @@ and copy_core_type : Ast_504.Parsetree.core_type -> Ast_503.Parsetree.core_type Ast_504.Parsetree.ptyp_attributes; } -> let loc = copy_location ptyp_loc in + let package_attrs = + match ptyp_desc with + | Ast_504.Parsetree.Ptyp_package { Ast_504.Parsetree.ppt_attrs; _ } -> + split_package_attr :: copy_attributes ppt_attrs + | _ -> [] + in { Ast_503.Parsetree.ptyp_desc = copy_core_type_desc ~loc ptyp_desc; Ast_503.Parsetree.ptyp_loc = loc; Ast_503.Parsetree.ptyp_loc_stack = copy_location_stack ptyp_loc_stack; - Ast_503.Parsetree.ptyp_attributes = copy_attributes ptyp_attributes; + Ast_503.Parsetree.ptyp_attributes = + copy_attributes ptyp_attributes @ package_attrs; } and copy_location_stack : diff --git a/test/504_migrations/package-types/dune b/test/504_migrations/package-types/dune new file mode 100644 index 00000000..7d5145e8 --- /dev/null +++ b/test/504_migrations/package-types/dune @@ -0,0 +1,13 @@ +(executable + (name id_driver) + (modules id_driver) + (libraries ppxlib)) + +(cram + ; Somewhat confusingly we enable this test on 5.5 and above, even + ; though it is a test for 5.4 migrations. We need this Pprintast bug + ; fix (https://github.com/ocaml/ocaml/pull/14797) which did not make + ; it back to 5.4, to really test this. + (enabled_if + (>= %{ocaml_version} "5.5")) + (deps id_driver.exe)) diff --git a/test/504_migrations/package-types/id_driver.ml b/test/504_migrations/package-types/id_driver.ml new file mode 100644 index 00000000..e3cba404 --- /dev/null +++ b/test/504_migrations/package-types/id_driver.ml @@ -0,0 +1 @@ +let () = Ppxlib.Driver.standalone () diff --git a/test/504_migrations/package-types/run.t b/test/504_migrations/package-types/run.t new file mode 100644 index 00000000..40181e47 --- /dev/null +++ b/test/504_migrations/package-types/run.t @@ -0,0 +1,30 @@ +The signature for package types, as well as packed expressions changed +in between. + +Originally we had a bug in the migrations that would silently drop some +attributes. Now we split them internally and when migrating back to compiler's +that can distinguish these attributes we make sure to split them back +correctly. + + $ cat > test.ml << EOF + > module type S = sig type t end + > let f (module K : S with type t = int [@foo]) = () + > let f (module K : S with type t = (int [@foo])) = () + > let f (module K : S with type t = (int [@foo])[@bar]) = () + > type t = (module S [@inner])[@outer] + > + > EOF + + $ ./id_driver.exe test.ml + module type S = sig type t end + let f ((module K) : (((module S with type t = int))[@foo ])) = () + let f ((module K) : (module S with type t = ((int)[@foo ]))) = () + let f ((module K) : (((module S with type t = ((int)[@foo ])))[@bar ])) = () + type t = (((module S))[@outer ][@inner ]) + $ ./id_driver.exe --use-compiler-pp test.ml + module type S = sig type t end + let f (module K : ((S with type t = int)[@foo ])) = () + let f (module K : S with type t = ((int)[@foo ])) = () + let f (module K : ((S with type t = ((int)[@foo ]))[@bar ])) = () + type t = (((module ((S)[@inner ])))[@outer ]) +