Skip to content

Commit a7a9475

Browse files
committed
Preserve attributes on marked polymorphic variant type tuples
Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent 531a5fd commit a7a9475

3 files changed

Lines changed: 56 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
#### :bug: Bug fix
3838

39+
- Preserve PPX-added attributes on polymorphic-variant type payload tuples when converting from the frozen v0 AST. https://github.com/rescript-lang/rescript/pull/8610
3940
- Fix the side-effect analysis treating bigint exponentiation and bounds-checked array and string reads as pure, which let dead-code elimination drop an unused one that throws: `let _ = 2n ** -1n` no longer raised. https://github.com/rescript-lang/rescript/pull/8617
4041
- Preserve record field `@as` annotations when formatting object types containing spreads. https://github.com/rescript-lang/rescript/pull/8619
4142
- Fix record-field completion inside constructor tuple payloads and for their destructured bindings, including both supported tuple spellings and polymorphic variants. https://github.com/rescript-lang/rescript/pull/8610

compiler/ml/ast_mapper_from0.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,9 @@ module T = struct
248248
in
249249
let txt =
250250
match typ.ptyp_desc with
251-
| Ptyp_tuple args when has_constructor_args -> args
251+
| Ptyp_tuple args when has_constructor_args && attrs = [] -> args
252+
(* A PPX may annotate the synthesized tuple. Keep its wrapper when
253+
consuming the marker so those attributes retain their owner. *)
252254
| _ -> [{typ with ptyp_attributes = attrs}]
253255
in
254256
{loc = typ.ptyp_loc; txt}

tests/ounit_tests/ounit_ast_mapper0_tests.ml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,56 @@ let test_polyvariant_args_roundtrip_through_ast0 _ =
751751
()
752752
| _ -> assert_failure "Expected two polymorphic variant type arguments"
753753

754+
let test_polyvariant_type_payload_attributes_through_ast0 _ =
755+
let payload_loc = source_loc 10 30 in
756+
let marker = attr "_res.constructor_args" (Parsetree0.PStr []) in
757+
let before = attr "ppx.before" (Parsetree0.PStr []) in
758+
let after = attr "ppx.after" (Parsetree0.PStr []) in
759+
let item =
760+
Ast_helper0.Typ.constr ~loc:(source_loc 12 15)
761+
~attrs:[attr "ppx.child" (Parsetree0.PStr [])]
762+
(Location.mknoloc (Longident.Lident "int"))
763+
[]
764+
in
765+
let make_variant payload =
766+
Ast_helper0.Typ.variant ~loc:(source_loc 0 32)
767+
[Parsetree0.Rtag (located_string "Pair", [before], false, [payload])]
768+
Closed None
769+
in
770+
List.iter
771+
(fun payload_attrs ->
772+
let payload =
773+
Ast_helper0.Typ.tuple ~loc:payload_loc ~attrs:payload_attrs [item; item]
774+
in
775+
let from0 = Ast_mapper_from0.default_mapper in
776+
let to0 = Ast_mapper_to0.default_mapper in
777+
let decoded = from0.typ from0 (make_variant payload) in
778+
let remaining_attrs =
779+
List.filter (fun attribute -> attribute <> marker) payload_attrs
780+
in
781+
(match decoded.ptyp_desc with
782+
| Ptyp_variant ([Rtag (_, _, false, [{loc; txt}])], _, _) -> (
783+
OUnit.assert_equal payload_loc loc;
784+
match (remaining_attrs, txt) with
785+
| [], [_; _] -> ()
786+
| _ :: _, [{ptyp_desc = Ptyp_tuple [_; _]; ptyp_attributes}] ->
787+
OUnit.assert_bool "bridge marker is consumed"
788+
(not (has_attr "_res.constructor_args" ptyp_attributes))
789+
| _ -> assert_failure "Expected attributed tuple wrapper to survive")
790+
| _ -> assert_failure "Expected a polymorphic variant type");
791+
let expected_payload =
792+
if remaining_attrs = [] then payload
793+
else {payload with ptyp_attributes = remaining_attrs}
794+
in
795+
let encoded = to0.typ to0 decoded in
796+
OUnit.assert_equal
797+
~msg:"preserve payload attributes, children and locations"
798+
(make_variant expected_payload)
799+
encoded;
800+
OUnit.assert_equal ~msg:"a second bridge roundtrip is stable" encoded
801+
(to0.typ to0 (from0.typ from0 encoded)))
802+
[[marker]; [before; marker]; [marker; after]; [before; marker; after]]
803+
754804
let assert_string_expr ~expected_source ~expected_semantic expr =
755805
match expr.Parsetree.pexp_desc with
756806
| Pexp_constant (Pconst_string payload) ->
@@ -1280,6 +1330,8 @@ let suites =
12801330
>:: test_fresh_ast0_constructor_tuple_defers_arity_to_typechecker;
12811331
"polyvariant_args_roundtrip_through_ast0"
12821332
>:: test_polyvariant_args_roundtrip_through_ast0;
1333+
"polyvariant_type_payload_attributes_through_ast0"
1334+
>:: test_polyvariant_type_payload_attributes_through_ast0;
12831335
"polyvariant_args_keep_parentheses_location_in_ast0"
12841336
>:: test_polyvariant_args_keep_parentheses_location_in_ast0;
12851337
"value_constraint_roundtrips_through_ast0"

0 commit comments

Comments
 (0)