Skip to content

Commit 6d16043

Browse files
committed
Preserve attributed list payload tuples across AST0 conversions
Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent 3ed6059 commit 6d16043

5 files changed

Lines changed: 61 additions & 20 deletions

File tree

compiler/ml/ast_mapper_from0.ml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,11 @@ let remove_constructor_args_attr (attrs : Pt.attributes) =
195195
196196
Decoding consumes the internal marker and restores the source list.
197197
Ordinary constructors also accept PPX-produced [explicit_arity] and
198-
[ocaml.explicit_arity] attributes, and always split the list constructor
199-
[::]. Other unmarked v0 tuples remain a single syntactic payload; Typecore
200-
resolves semantic grouping once it knows the constructor declaration.
198+
[ocaml.explicit_arity] attributes, and split the list constructor [::] when
199+
its tuple has no attributes. Attributed cons tuples remain one payload so
200+
their attributes survive another v0 conversion. Other unmarked v0 tuples
201+
also remain a single syntactic payload; Typecore resolves semantic grouping
202+
once it knows the constructor declaration.
201203
202204
The tuple used to encode multiple arguments carries the argument-list
203205
location, preserving its parentheses span. For a single argument, v0
@@ -905,6 +907,10 @@ module E = struct
905907
decode_args ~map:(sub.expr sub)
906908
~tuple_args:(fun arg ->
907909
match arg.pexp_desc with
910+
| Pexp_tuple _
911+
when lid.txt = Longident.Lident "::" && arg.pexp_attributes <> []
912+
->
913+
None
908914
| Pexp_tuple args -> Some args
909915
| _ -> None)
910916
~split_tuple:
@@ -1163,6 +1169,9 @@ module P = struct
11631169
decode_args ~map:(sub.pat sub)
11641170
~tuple_args:(fun arg ->
11651171
match arg.ppat_desc with
1172+
| Ppat_tuple _
1173+
when l.txt = Longident.Lident "::" && arg.ppat_attributes <> [] ->
1174+
None
11661175
| Ppat_tuple args -> Some args
11671176
| _ -> None)
11681177
~split_tuple:

compiler/ml/pprintast.ml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,8 @@ and pattern1 ctxt (f : Format.formatter) (x : pattern) : unit =
465465
| Ppat_construct ({txt = Lident ("()" | "[]"); _}, _) ->
466466
simple_pattern ctxt f x
467467
| Ppat_construct (({txt; _} as li), {txt = po}) -> (
468-
if
469-
(* FIXME The third field always false *)
470-
txt = Lident "::"
471-
then pp f "%a" pattern_list_helper x
468+
if txt = Lident "::" && List.length po = 2 then
469+
pp f "%a" pattern_list_helper x
472470
else
473471
match po with
474472
| [] -> pp f "%a" longident_loc li

compiler/syntax/src/res_comments_table.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,21 @@ let partition_between_lines start_line end_line comments =
296296
let rec collect_list_patterns acc pattern =
297297
let open Parsetree in
298298
match pattern.ppat_desc with
299-
| Ppat_construct ({txt = Longident.Lident "::"}, {txt = [pat; rest]}) ->
299+
| Ppat_construct ({txt = Longident.Lident "::"}, {txt = [pat; rest]})
300+
| Ppat_construct
301+
( {txt = Longident.Lident "::"},
302+
{txt = [{ppat_desc = Ppat_tuple [pat; rest]}]} ) ->
300303
collect_list_patterns (pat :: acc) rest
301304
| Ppat_construct ({txt = Longident.Lident "[]"}, {txt = []}) -> List.rev acc
302305
| _ -> List.rev (pattern :: acc)
303306

304307
let rec collect_list_exprs acc expr =
305308
let open Parsetree in
306309
match expr.pexp_desc with
307-
| Pexp_construct ({txt = Longident.Lident "::"}, {txt = [expr; rest]}) ->
310+
| Pexp_construct ({txt = Longident.Lident "::"}, {txt = [expr; rest]})
311+
| Pexp_construct
312+
( {txt = Longident.Lident "::"},
313+
{txt = [{pexp_desc = Pexp_tuple [expr; rest]}]} ) ->
308314
collect_list_exprs (expr :: acc) rest
309315
| Pexp_construct ({txt = Longident.Lident "[]"}, _) -> List.rev acc
310316
| _ -> List.rev (expr :: acc)

compiler/syntax/src/res_parsetree_viewer.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ let collect_list_expressions expr =
7070
let rec collect acc expr =
7171
match expr.pexp_desc with
7272
| Pexp_construct ({txt = Longident.Lident "[]"}, _) -> (List.rev acc, None)
73-
| Pexp_construct ({txt = Longident.Lident "::"}, {txt = hd :: [tail]}) ->
73+
| Pexp_construct ({txt = Longident.Lident "::"}, {txt = hd :: [tail]})
74+
| Pexp_construct
75+
( {txt = Longident.Lident "::"},
76+
{txt = [{pexp_desc = Pexp_tuple [hd; tail]}]} ) ->
7477
collect (hd :: acc) tail
7578
| _ -> (List.rev acc, Some expr)
7679
in
@@ -642,7 +645,10 @@ let mod_expr_functor mod_expr =
642645
let rec collect_patterns_from_list_construct acc pattern =
643646
let open Parsetree in
644647
match pattern.ppat_desc with
645-
| Ppat_construct ({txt = Longident.Lident "::"}, {txt = [pat; rest]}) ->
648+
| Ppat_construct ({txt = Longident.Lident "::"}, {txt = [pat; rest]})
649+
| Ppat_construct
650+
( {txt = Longident.Lident "::"},
651+
{txt = [{ppat_desc = Ppat_tuple [pat; rest]}]} ) ->
646652
collect_patterns_from_list_construct (pat :: acc) rest
647653
| _ -> (List.rev acc, pattern)
648654

tests/ounit_tests/ounit_ast_mapper0_tests.ml

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,13 @@ let attr_names attrs = List.map (fun ({Location.txt}, _) -> txt) attrs
195195
let test_list_constructor_wire_shape _ =
196196
let lid name = Location.mknoloc (Longident.Lident name) in
197197
List.iter
198-
(fun attrs ->
198+
(fun (attrs, payload_attrs) ->
199199
let expr0 =
200200
List.fold_right
201201
(fun value tail ->
202202
Ast_helper0.Exp.construct ~loc ~attrs (lid "::")
203203
(Some
204-
(Ast_helper0.Exp.tuple ~loc
204+
(Ast_helper0.Exp.tuple ~loc ~attrs:payload_attrs
205205
[
206206
Ast_helper0.Exp.constant ~loc
207207
(Parsetree0.Pconst_integer (value, None));
@@ -215,24 +215,46 @@ let test_list_constructor_wire_shape _ =
215215
(fun name tail ->
216216
Ast_helper0.Pat.construct ~loc ~attrs (lid "::")
217217
(Some
218-
(Ast_helper0.Pat.tuple ~loc
218+
(Ast_helper0.Pat.tuple ~loc ~attrs:payload_attrs
219219
[Ast_helper0.Pat.var ~loc (Location.mknoloc name); tail])))
220220
["head"; "next"]
221221
(Ast_helper0.Pat.construct ~loc (lid "[]") None)
222222
in
223223
let expr = map_expr0 expr0 in
224224
let pat = map_pat0 pat0 in
225-
(match (expr.pexp_desc, pat.ppat_desc) with
226-
| Pexp_construct (_, {txt = [_; _]}), Ppat_construct (_, {txt = [_; _]})
227-
->
225+
(match (payload_attrs, expr.pexp_desc, pat.ppat_desc) with
226+
| ( [],
227+
Pexp_construct (_, {txt = [_; _]}),
228+
Ppat_construct (_, {txt = [_; _]}) ) ->
229+
()
230+
| ( _ :: _,
231+
Pexp_construct (_, {txt = [{pexp_desc = Pexp_tuple [_; _]}]}),
232+
Ppat_construct (_, {txt = [{ppat_desc = Ppat_tuple [_; _]}]}) ) ->
228233
()
229234
| _ ->
230-
assert_failure "Unmarked cons payloads must decode to two arguments");
235+
assert_failure "Attributed cons payloads must retain their tuple node");
231236
OUnit.assert_equal ~msg:"list expression wire shape and attributes" expr0
232237
(map_expr_to0 expr);
233238
OUnit.assert_equal ~msg:"list pattern wire shape and attributes" pat0
234-
(map_pat_to0 pat))
235-
[[]; [attr "public_attr" (Parsetree0.PStr [])]]
239+
(map_pat_to0 pat);
240+
let structure =
241+
[
242+
Ast_helper.Str.value ~loc Nonrecursive [Ast_helper.Vb.mk ~loc pat expr];
243+
]
244+
in
245+
ignore (Typemod.type_structure Env.initial_safe_string structure loc);
246+
let printed =
247+
Res_printer.print_implementation structure ~comments:[] ~width:80
248+
in
249+
let parsed =
250+
Res_driver.parse_implementation_from_source
251+
~display_filename:"ListPayloadAttributes.res" ~source:printed
252+
in
253+
OUnit.assert_bool "attributed list payloads remain printable"
254+
(not parsed.invalid);
255+
ignore (Format.asprintf "%a" Pprintast.structure structure))
256+
(let attrs = [attr "public_attr" (Parsetree0.PStr [])] in
257+
[([], []); (attrs, []); ([], attrs); (attrs, attrs)])
236258

237259
let test_constructor_args_roundtrip_through_ast0 _ =
238260
let int_expr value =

0 commit comments

Comments
 (0)