diff --git a/lib/Normalize_std_ast.ml b/lib/Normalize_std_ast.ml index 3c7beb4792..0855837f5c 100644 --- a/lib/Normalize_std_ast.ml +++ b/lib/Normalize_std_ast.ml @@ -271,6 +271,14 @@ let make_mapper conf ~ignore_doc_comments ~erase_jane_syntax = | Pexp_extension ({txt= "src_pos"; loc}, _) when erase_jane_syntax -> m.expr m (dummy_position ~loc) | Pexp_stack expr when erase_jane_syntax -> m.expr m expr + | Pexp_unboxed_tuple es when erase_jane_syntax -> + Ast_mapper.default_mapper.expr m {exp with pexp_desc= Pexp_tuple es} + | Pexp_record_unboxed_product (es, e) when erase_jane_syntax -> + Ast_mapper.default_mapper.expr m + {exp with pexp_desc= Pexp_record (es, e)} + | Pexp_unboxed_field (e, l) when erase_jane_syntax -> + Ast_mapper.default_mapper.expr m + {exp with pexp_desc= Pexp_field (e, l)} | _ -> Ast_mapper.default_mapper.expr m exp in let pat (m : Ast_mapper.mapper) pat = @@ -295,6 +303,12 @@ let make_mapper conf ~ignore_doc_comments ~erase_jane_syntax = [let _ : typ = exp] is represented as [let _ : typ = (exp : typ)]. *) m.pat m pat1 + | Ppat_unboxed_tuple (ps, oc) when erase_jane_syntax -> + Ast_mapper.default_mapper.pat m + {pat with ppat_desc= Ppat_tuple (ps, oc)} + | Ppat_record_unboxed_product (ps, oc) when erase_jane_syntax -> + Ast_mapper.default_mapper.pat m + {pat with ppat_desc= Ppat_record (ps, oc)} | _ -> Ast_mapper.default_mapper.pat m pat in let typ (m : Ast_mapper.mapper) typ = @@ -350,6 +364,8 @@ let make_mapper conf ~ignore_doc_comments ~erase_jane_syntax = | {ptyp_desc= Ptyp_poly (l, t); _} when erase_jane_syntax -> let l = List.map l ~f:(fun (n, _) -> (n, None)) in {typ with ptyp_desc= Ptyp_poly (l, t)} + | {ptyp_desc= Ptyp_unboxed_tuple ts; _} when erase_jane_syntax -> + {typ with ptyp_desc= Ptyp_tuple ts} | _ -> typ in Ast_mapper.default_mapper.typ m typ @@ -420,8 +436,14 @@ let make_mapper conf ~ignore_doc_comments ~erase_jane_syntax = removed *) |> if erase_jane_syntax then map_attributes_no_sort m else Fn.id in + let ptype_kind = + match decl.ptype_kind with + | Ptype_record_unboxed_product lds when erase_jane_syntax -> + Ptype_record lds + | _ -> decl.ptype_kind + in Ast_mapper.default_mapper.type_declaration m - {decl with ptype_attributes; ptype_jkind_annotation} + {decl with ptype_attributes; ptype_jkind_annotation; ptype_kind} in let modes (m : Ast_mapper.mapper) ms = Ast_mapper.default_mapper.modes m diff --git a/test/passing/dune.inc b/test/passing/dune.inc index 8195853623..1a0081c5d2 100644 --- a/test/passing/dune.inc +++ b/test/passing/dune.inc @@ -12232,6 +12232,24 @@ (package ocamlformat) (action (diff tests/unary_hash.ml.js-err unary_hash.ml.js-stderr))) +(rule + (deps tests/.ocamlformat ) + (package ocamlformat) + (action + (with-stdout-to unboxed_record-erased.ml.stdout + (with-stderr-to unboxed_record-erased.ml.stderr + (run %{bin:ocamlformat} --margin-check --erase-jane-syntax --max-iter=3 %{dep:tests/unboxed_record.ml}))))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_record-erased.ml.ref unboxed_record-erased.ml.stdout))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_record-erased.ml.err unboxed_record-erased.ml.stderr))) + (rule (deps tests/.ocamlformat ) (package ocamlformat) @@ -12268,6 +12286,24 @@ (package ocamlformat) (action (diff tests/unboxed_record.ml.js-err unboxed_record.ml.js-stderr))) +(rule + (deps tests/.ocamlformat ) + (package ocamlformat) + (action + (with-stdout-to unboxed_records_cmts_attrs-erased.ml.stdout + (with-stderr-to unboxed_records_cmts_attrs-erased.ml.stderr + (run %{bin:ocamlformat} --margin-check --erase-jane-syntax --max-iter=3 %{dep:tests/unboxed_records_cmts_attrs.ml}))))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_records_cmts_attrs-erased.ml.ref unboxed_records_cmts_attrs-erased.ml.stdout))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_records_cmts_attrs-erased.ml.err unboxed_records_cmts_attrs-erased.ml.stderr))) + (rule (deps tests/.ocamlformat ) (package ocamlformat) @@ -12304,6 +12340,24 @@ (package ocamlformat) (action (diff tests/unboxed_records_cmts_attrs.ml.js-err unboxed_records_cmts_attrs.ml.js-stderr))) +(rule + (deps tests/.ocamlformat ) + (package ocamlformat) + (action + (with-stdout-to unboxed_tuples-erased.ml.stdout + (with-stderr-to unboxed_tuples-erased.ml.stderr + (run %{bin:ocamlformat} --margin-check --erase-jane-syntax --max-iter=3 %{dep:tests/unboxed_tuples.ml}))))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_tuples-erased.ml.ref unboxed_tuples-erased.ml.stdout))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_tuples-erased.ml.err unboxed_tuples-erased.ml.stderr))) + (rule (deps tests/.ocamlformat ) (package ocamlformat) @@ -12340,6 +12394,24 @@ (package ocamlformat) (action (diff tests/unboxed_tuples.ml.js-err unboxed_tuples.ml.js-stderr))) +(rule + (deps tests/.ocamlformat ) + (package ocamlformat) + (action + (with-stdout-to unboxed_tuples_cmts_attrs-erased.ml.stdout + (with-stderr-to unboxed_tuples_cmts_attrs-erased.ml.stderr + (run %{bin:ocamlformat} --margin-check --erase-jane-syntax --max-iter=3 %{dep:tests/unboxed_tuples_cmts_attrs.ml}))))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_tuples_cmts_attrs-erased.ml.ref unboxed_tuples_cmts_attrs-erased.ml.stdout))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff tests/unboxed_tuples_cmts_attrs-erased.ml.err unboxed_tuples_cmts_attrs-erased.ml.stderr))) + (rule (deps tests/.ocamlformat ) (package ocamlformat) diff --git a/test/passing/tests/stack-erased.ml.ref b/test/passing/tests/stack-erased.ml.ref index 57a79364b4..ddeae48cc7 100644 --- a/test/passing/tests/stack-erased.ml.ref +++ b/test/passing/tests/stack-erased.ml.ref @@ -124,7 +124,7 @@ let x = () :: [] let x = (1, 2) -let x = #(1, 2) +let x = (1, 2) let x = (~x:1, ~y:2) diff --git a/test/passing/tests/unboxed_record-erased.ml.err b/test/passing/tests/unboxed_record-erased.ml.err new file mode 100644 index 0000000000..0a63963542 --- /dev/null +++ b/test/passing/tests/unboxed_record-erased.ml.err @@ -0,0 +1,9 @@ +Warning: tests/unboxed_record.ml:12 exceeds the margin +Warning: tests/unboxed_record.ml:18 exceeds the margin +Warning: tests/unboxed_record.ml:177 exceeds the margin +Warning: tests/unboxed_record.ml:186 exceeds the margin +Warning: tests/unboxed_record.ml:188 exceeds the margin +Warning: tests/unboxed_record.ml:198 exceeds the margin +Warning: tests/unboxed_record.ml:205 exceeds the margin +Warning: tests/unboxed_record.ml:206 exceeds the margin +Warning: tests/unboxed_record.ml:215 exceeds the margin diff --git a/test/passing/tests/unboxed_record-erased.ml.opts b/test/passing/tests/unboxed_record-erased.ml.opts new file mode 100644 index 0000000000..41a1f7197c --- /dev/null +++ b/test/passing/tests/unboxed_record-erased.ml.opts @@ -0,0 +1 @@ +--erase-jane-syntax --max-iter=3 diff --git a/test/passing/tests/unboxed_record-erased.ml.ref b/test/passing/tests/unboxed_record-erased.ml.ref new file mode 100644 index 0000000000..00c75dd12e --- /dev/null +++ b/test/passing/tests/unboxed_record-erased.ml.ref @@ -0,0 +1,226 @@ +(* This test file is a copy of record.ml, updated to use unboxed records, and + with some additional tests at the end. *) + +type t = {x: int; y: int} + +let _ = {x= 1; y= 2} + +let _ = {!e with a; b= c} + +let _ = {!(f e) with a; b= c} + +let _ = + { !looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo + with + a + ; b= c } + +let _ = + { !looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo + with + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ; b= c } + +let _ = {(a : t) with a; b; c} + +let _ = {(f a) with a; b; c} + +let _ = {(a ; a) with a; b; c} + +let _ = {(if x then e else e) with e1; e2} + +let _ = {(match x with x -> e) with e1; e2} + +let _ = {(x : x) with e1; e2} + +let _ = {(x :> x) with e1; e2} + +let _ = {(x#x) with e1; e2} + +let f ~l:{f; g} = e + +let f ?l:({f; g}) = e + +let _ = {a; b= (match b with `A -> A | `B -> B | `C -> C : c); c} + +let a () = A {A.a: t} + +let x = {aaaaaaaaaa (* b *); b} + +let x = {aaaaaaaaaa (* b *); b} + +type t = {a: (module S); b: (module S)} + +let _ = {a= (module M : S); b= (module M : S)} + +let to_string {x; _ (* we should print y *)} = string_of_int x + +let {x: t} = x + +(* Copy of record.ml ends here *) + +(* Basic field access. *) + +let _ = r.x + +(* Tests adapted from unboxed_tuples.ml *) +let _ = + { u= abcdefghijklmnopqrstuvwxyz + ; w= bcdefghijklmnopqrstuvwxyz + ; x= abcdefghijklmnopqrstuvwxyz + ; y= abcdefghijklmnopqrstuvwxyz + ; z= abcdefghijklmnopqrstuvwxyz } + +let _ = + match () with + | { a= abcdefghijklmnopqrstuvwxyz + ; b= abcdefghijklmnopqrstuvwxyz + ; c= abcdefghijklmnopqrstuvwxyz + ; d= abcdefghijklmnopqrstuvwxyz + ; e= abcdefghijklmnopqrstuvwxyz } -> + () + +type t = + { a: abcdefghijklmnopqrstuvwxyz + ; b: abcdefghijklmnopqrstuvwxyz + ; c: abcdefghijklmnopqrstuvwxyz + ; d: abcdefghijklmnopqrstuvwxyz + ; e: abcdefghijklmnopqrstuvwxyz } + +type t = t' = + { a: abcdefghijklmnopqrstuvwxyz + ; b: abcdefghijklmnopqrstuvwxyz + ; c: abcdefghijklmnopqrstuvwxyz + ; d: abcdefghijklmnopqrstuvwxyz + ; e: abcdefghijklmnopqrstuvwxyz } + +let x = match foo with {x= Some x; y= Some y} -> () + +let foo a = + match a with + | { l1= None + ; l2= Some _ + ; l3= [1; 2] + ; l4= 3 :: [] + ; l5= {x: _; y: _} + ; l6= 42 + ; l7= _ + ; l8= `Baz + ; l9= `Bar _ + ; l10= 1 | 2 + ; l11= [|1; 2|] + ; l12= (3 : int) + ; l13= (lazy _) + ; l14= (module M) + ; l15= (exception _) + ; l16= [%bar baz] + ; l17= M.(A) + ; l18= M.(A 42) } -> + false + +let bar = + { l1= foo + ; l2= 42 + ; l3= + (let x = 18 in + x ) + ; l4= (function x -> x) + ; l5= (fun x -> x) + ; l6= foo 42 + ; l7= (match () with () -> ()) + ; l8= (try () with _ -> ()) + ; l9= (1, 2) + ; l10= (~x:1, ~y:2) + ; l11= None + ; l12= Some 42 + ; l13= `A + ; l14= `B 42 + ; l15= {x= 42; z= false} + ; l16= foo.lbl + ; l17= (foo 42).lbl + ; l18= foo.lbl <- 42 + ; l19= [|1; 2|] + ; l20= [:1; 2:] + ; l21= [1; 2] + ; l22= [a for a = 1 to 10] + ; l23= (if true then true else false) + ; l24= (() ; ()) + ; l25= + while true do + () + done + ; l26= + for i = 1 to 2 do + () + done + ; l27= (42 : int) + ; l28= (42 :> int) + ; l29= (42 : int :> bool) + ; l30= foo#bar + ; l31= foo #~# bar + ; l32= new M.c + ; l33= x <- 2 + ; l34= {} + ; l35= + (let module M = N in + () ) + ; l36= + (let exception Ex in + () ) + ; l37= assert true } + +let _ = + match w with + | A -> {a= []; b= A.(B (C (f x))); c= None; d= f x y; e= g y x} + | B -> {a; b; c; d; e} + | C -> + { a= [] + ; b= A.(B (C (this is very looooooooooooooooooooooooooooooooooooong x))) + ; c= None + ; d= f x y + ; e= g y x } + +let _ = [%ext {a= 1; b= 2; c= 3}] + +let _ = + [%ext + { loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + ; y= + loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + ; z= 3 }] + +type t = int [@@deriving {a= 1; b= 2; c= 3}] + +type t = int +[@@deriving + { sexp + ; compare + ; x= + loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + }] + +let _ = + { a= 1 + ; b= 2 + ; c= + looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + ; looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + } + +let _ = {a= 1; b= 2; c= 3; short} ;; + +{ a= 1 +; b= 2 +; looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong +; d= + looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong +} +;; + +{a= 1; b= 2; c= 3; short} + +(* make sure to not drop parens for local open. *) +let _ = A.{a= 1; b= 2} + +(* make sure not to drop parens around thing being projected from. *) +let _ = (f x).foo diff --git a/test/passing/tests/unboxed_record-erased.ml.why-no-js b/test/passing/tests/unboxed_record-erased.ml.why-no-js new file mode 100644 index 0000000000..0f1aefcf07 --- /dev/null +++ b/test/passing/tests/unboxed_record-erased.ml.why-no-js @@ -0,0 +1 @@ +Erasure test diff --git a/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.opts b/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.opts new file mode 100644 index 0000000000..41a1f7197c --- /dev/null +++ b/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.opts @@ -0,0 +1 @@ +--erase-jane-syntax --max-iter=3 diff --git a/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.ref b/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.ref new file mode 100644 index 0000000000..da14cd455f --- /dev/null +++ b/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.ref @@ -0,0 +1,122 @@ +(* Tests making sure comments and attributes are handled reasonably by + unboxed record printing. *) + +(* Attrs around expressions *) +let y = {a= z; b= z [@attr]} + +let y = {a= z; b= z} [@@attr] + +let y = {a= ((42 [@attr]) : int); b= 42} + +let y = {a= a [@attr]; b= 42} + +(* Comments around expressions *) +let _ = (* baz *) {x= 42; y} + +let _ = {(* baz *) x= 42; y} + +let _ = {x (* baz *)= 42; y} + +let _ = {x= 42 (* baz *); y} + +let _ = {x= 42; (* baz *) y} + +let _ = {x= 42; y (* baz *)} + +let _ = {x= 42; y} (* baz *) + +let _ = (* baz *) {z; y: int} + +let _ = {(* baz *) z; y: int} + +let _ = {z (* baz *); y: int} + +let _ = {z; (* baz *) y: int} + +let _ = {z; y: (* baz *) int} + +let _ = {z; y: (* baz *) int} + +let _ = {z; y: int (* baz *)} + +let _ = {z; y: int (* baz *)} + +let _ = {z; y: int} (* baz *) + +(* Attrs around types *) +type t = {x: (int[@attr]); y: bool} + +type t = {x: int; y: (bool[@attr])} + +type t = {x: int; y: bool [@attr]} + +type t = {x: int; y: bool} [@@attr] + +(* Comments around types *) +type t = {(* baz *) x: int; y: bool} + +type t = {(* baz *) x: int; y: bool} + +type t = {x (* baz *): int; y: bool} + +type t = {x: (* baz *) int; y: bool} + +type t = {x: int (* baz *); y: bool} + +type t = {x: int; (* baz *) y: bool} + +type t = {x: int; y (* baz *): bool} + +type t = {x: int; y: (* baz *) bool} + +type t = {x: int; y: bool (* baz *)} + +type t = {x: int; y: bool} (* baz *) + +(* Attrs around patterns *) +let {z= (z [@attr]); y} = () + +let {z; y= (42 [@attr])} = () + +let ({z; y= 42} [@attr]) = () + +(* Comments around patterns *) +let (* baz *) {z; y= 42} = () + +let {(* baz *) z; y= 42} = () + +let {z (* baz *); y= 42} = () + +let {z; (* baz *) y= 42} = () + +let {z; y (* baz *)= 42} = () + +let {z; y= (* baz *) 42} = () + +let {z; y= 42 (* baz *)} = () + +let {z; y= 42} (* baz *) = () + +let (* baz *) {z= 42; y: int} = () + +let {(* baz *) z= 42; y: int} = () + +let {z (* baz *)= 42; y: int} = () + +let {z= (* baz *) 42; y: int} = () + +let {z= 42 (* baz *); y: int} = () + +let {z= 42; (* baz *) y: int} = () + +let {z= 42; y: (* baz *) int} = () + +let {z= 42; y: (* baz *) int} = () + +let {z= 42; y: (* baz *) int} = () + +let {z= 42; y: int (* baz *)} = () + +let {z= 42; y: int (* baz *)} = () + +let {z= 42; y: int} (* baz *) = () diff --git a/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.why-no-js b/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.why-no-js new file mode 100644 index 0000000000..0f1aefcf07 --- /dev/null +++ b/test/passing/tests/unboxed_records_cmts_attrs-erased.ml.why-no-js @@ -0,0 +1 @@ +Erasure test diff --git a/test/passing/tests/unboxed_tuples-erased.ml.err b/test/passing/tests/unboxed_tuples-erased.ml.err new file mode 100644 index 0000000000..a009d9bd96 --- /dev/null +++ b/test/passing/tests/unboxed_tuples-erased.ml.err @@ -0,0 +1,5 @@ +Warning: tests/unboxed_tuples.ml:414 exceeds the margin +Warning: tests/unboxed_tuples.ml:415 exceeds the margin +Warning: tests/unboxed_tuples.ml:424 exceeds the margin +Warning: tests/unboxed_tuples.ml:429 exceeds the margin +Warning: tests/unboxed_tuples.ml:430 exceeds the margin diff --git a/test/passing/tests/unboxed_tuples-erased.ml.opts b/test/passing/tests/unboxed_tuples-erased.ml.opts new file mode 100644 index 0000000000..41a1f7197c --- /dev/null +++ b/test/passing/tests/unboxed_tuples-erased.ml.opts @@ -0,0 +1 @@ +--erase-jane-syntax --max-iter=3 diff --git a/test/passing/tests/unboxed_tuples-erased.ml.ref b/test/passing/tests/unboxed_tuples-erased.ml.ref new file mode 100644 index 0000000000..ee089882c8 --- /dev/null +++ b/test/passing/tests/unboxed_tuples-erased.ml.ref @@ -0,0 +1,445 @@ +(* This test file is just a copy of labeled_tuples.ml and + labeled_tuples_regressions.ml, with less labels, and some additional + regression tests at the bottom. *) + +(* Basic expressions *) +let x = (1, 2) + +let z = 5 + +let punned = 2 + +let _ = (~x:5, 2, ~z, ~(punned : int)) + +(* Basic annotations *) +let (x : int * int) = (1, 2) + +let (x : x:int * int) = (~x:1, 2) + +(* Incorrect annotations *) +let (x : int * int) = (~x:1, 2) + +let (x : x:string * int) = (~x:1, 2) + +let (x : int * y:int) = (~x:1, 2) + +(* Happy case *) +let foo b = if b then (~a:"s", 10, ~c:"hi") else (~a:"5", 10, ~c:"hi") + +(* Missing label (the type vars in the error aren't ideal, but the same thing + happens when unifying normal tuples of different lengths) *) +let foo b = if b then (~a:"s", 10, "hi") else (~a:"5", 10, ~c:"hi") + +(* Missing labeled component *) +let foo b = if b then (~a:"s", 10) else (~a:"5", 10, ~c:"hi") + +(* Wrong label *) +let foo b = if b then (~a:"s", 10, ~a:"hi") else (~a:"5", 10, ~c:"hi") + +(* Types in function argument/return *) +let default = (~x:1, ~y:2) + +let choose_pt replace_with_default pt = + if replace_with_default then default else pt + +(* Application happy case *) +let a = choose_pt true (~x:5, ~y:6) + +(* Wrong order *) +let a = choose_pt true (~y:6, ~x:5) + +(* Mutually-recursive definitions *) +let rec a = (1, ~lbl:b) + +and b = (2, ~lbl:a) + +let rec l = (~lbl:5, ~lbl2:10) :: l + +(* Tuple containing labeled tuples *) +let tup = ((1, 2), (~b:3, ~a:4), 5) + +(* Polymorphic variant containing labeled tuple *) +let a = `Some (~a:1, ~b:2, 3) + +(* List of labeled tuples *) +let lst = (~a:1, ~b:2) :: [] + +(* Ref of labeled tuple *) +let x = ref (~x:"hello", 5) + +(* Polymorphic record containing a labeled tuple *) +type 'a box = {thing: 'a} + +let boxed = {thing= ("hello", ~x:5)} + +(* Punned tuple components with type annotations. *) +let x = 42 + +let y = "hi" + +let z = (~x, ~(y : string)) + +let z = (~(x : int), ~y:"baz") + +let z = ((x : string), ~y:"baz") + +(* Take a [a:'a * b:'a] and an int, and returns a [swapped:[a:'a * b:'a] * + same:bool]. The swapped component is the input with the [a] and [b] + components swapped as many times as the input int. The second component is + whether the first equals the input. *) +let rec swap (~a, ~b) = function + | 0 -> (~swapped:(~a, ~b), ~same:true) + | n -> swap' (~a:b, ~b:a) (n - 1) + +and swap' (~a, ~b) = function + | 0 -> (~swapped:(~a, ~b), ~same:false) + | n -> swap (~a:b, ~b:a) (n - 1) + +let foobar = swap (~a:"foo", ~b:"bar") 86 + +let barfoo = swap (~a:"foo", ~b:"bar") 87 + +(* Labeled tuple type annotations *) +(* Bad type *) +let x : string * a:int * int = (~lbl:5, "hi") + +(* Well-typed *) +let x : string * a:int * int = ("hi", ~a:1, 2) + +(* Function type *) +let mk_x : (foo:unit * bar:unit) -> string * a:int * int = fun _ -> x + +let x = mk_x (~foo:(), ~bar:()) + +(* Labeled tuples in records *) + +type bad_t = {x: lbl:bad_type * int} + +type tx = {x: foo:int * bar:int} + +type tx_unlabeled = {x: int * int} + +let _ = {x= (~foo:1, ~bar:2)} + +let _ : tx = {x= (~foo:1, ~bar:2)} + +let _ : tx = {x= (1, ~bar:2)} + +let _ : tx = {x= (~foo:1, 2)} + +let _ : tx = {x= (1, 2)} + +let _ = {x= (1, 2)} + +(* Module inclusion *) + +module IntString : sig + type t + + val mk : (x:int * string) -> t + + val unwrap : t -> x:int * string +end = struct + type t = string * x:int + + let mk (~x, s) = (s, ~x) + + let unwrap (s, ~x) = (~x, s) +end + +module Stringable = struct + module type Has_unwrap = sig + type t + + val unwrap : t -> x:int * string + end + + module type Has_to_string = sig + include Has_unwrap + + val to_string : t -> string + end + + module Make (M : Has_unwrap) : Has_to_string with type t := M.t = struct + include M + + let to_string int_string = + let ~x, s = unwrap int_string in + Int.to_string x ^ " " ^ s + end +end + +module StringableIntString = struct + include IntString + include functor Stringable.Make +end + +let _ = StringableIntString.to_string (StringableIntString.mk (~x:1, "hi")) + +module M : sig + val f : (x:int * string) -> x:int * string + + val mk : unit -> x:bool * y:string +end = struct + let f x = x + + let mk () = (~x:false, ~y:"hi") +end + +(* Module inclusion failure *) +module X_int_int = struct + type t = x:int * int +end + +module Y_int_int : sig + type t = y:int * int +end = struct + include X_int_int +end + +module Int_int : sig + type t = int * int +end = + X_int_int + +(* Recursive modules *) +module rec Tree : sig + type t = Leaf of string | Branch of string * TwoTrees.t + + val in_order : t -> string list +end = struct + type t = Leaf of string | Branch of string * TwoTrees.t + + let rec in_order = function + | Leaf s -> [s] + | Branch (s, (~left, ~right)) -> in_order left @ [s] @ in_order right +end + +and TwoTrees : sig + type t = left:Tree.t * right:Tree.t +end = struct + type t = left:Tree.t * right:Tree.t +end + +let leaf s = Tree.Leaf s + +let tree_abc = Tree.Branch ("b", (~left:(leaf "a"), ~right:(leaf "c"))) + +let tree_abcde = Tree.Branch ("d", (~left:tree_abc, ~right:(leaf "e"))) + +let _ = Tree.in_order tree_abcde + +(* Motivating example *) +let two_kinds_of_sums ints = + let init = (~normal_sum:0, ~absolute_value_sum:0) in + List.fold_left + (fun (~normal_sum, ~absolute_value_sum) elem -> + let normal_sum = elem + normal_sum in + let absolute_value_sum = abs elem + absolute_value_sum in + (~normal_sum, ~absolute_value_sum) ) + init ints + +let _ = two_kinds_of_sums [1; 2; 3; 4] + +let _ = two_kinds_of_sums [1; 2; -3; 42; -17] + +let x = (~x:1, ~y:2) + +(* Attribute should prevent punning *) +let z = 5 + +let y = (~z, ~z, ~z:(z [@attr])) + +let (~x:x0, ~s, ~(y : int), ..) : x:int * s:string * y:int * string = + (~x:1, ~s:"a", ~y:2, "ignore me") + +(* Constructor with labeled arguments (disallowed) *) + +type ('a, 'b) pair = Pair of 'a * 'b + +(* Labeled tuple pattern in constructor pattern, with the same arity as the + constructor. This is intentionally disallowed. *) +let f = function Pair (~x:5, 2) -> true | _ -> false + +(* Labeled tuple patterns in constructor patterns with that can union with + the constructor pattern type. *) +let f = function Some (~x:5, 2) -> true | _ -> false + +type t = Foo of (x:int * int) + +let f = function Foo (~x:5, 2) -> true | _ -> false + +let f = function (A | B), C -> () + +let x = ((fun () -> ()), fun () -> ()) + +let x = ((if y then 1 else 2), if y then 1 else 2) + +let x = ((match y with () -> ()), match y with () -> ()) + +let _ = + ( abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz ) + +let _ = + match () with + | ( abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz + , abcdefghijklmnopqrstuvwxyz ) -> + () + +type t = + t + * ( abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz ) + +type t = + t + * ( abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz + * abcdefghijklmnopqrstuvwxyz ) + +let x = match foo with Some x, ~l:(Some y) -> () + +let foo a = + match a with + | ( None + , Some _ + , [1; 2] + , 3 :: [] + , {x: _; y: _} + , 42 + , _ + , `Baz + , `Bar _ + , (1 | 2) + , [|1; 2|] + , (3 : int) + , (lazy _) + , (module M) + , (exception _) + , [%bar baz] + , M.(A) + , M.(A 42) ) -> + false + +let bar = + ( foo + , 42 + , (let x = 18 in + x ) + , (function x -> x) + , (fun x -> x) + , foo 42 + , (match () with () -> ()) + , (try () with _ -> ()) + , (1, 2) + , (~x:1, ~y:2) + , None + , Some 42 + , `A + , `B 42 + , {x= 42; z= false} + , foo.lbl + , (foo 42).lbl + , (foo.lbl <- 42) + , [|1; 2|] + , [:1; 2:] + , [1; 2] + , [a for a = 1 to 10] + , (if true then true else false) + , (() ; ()) + , while true do + () + done + , for i = 1 to 2 do + () + done + , (42 : int) + , (42 :> int) + , (42 : int :> bool) + , foo#bar + , foo #~# bar + , new M.c + , (x <- 2) + , {} + , (let module M = N in + () ) + , (let exception Ex in + () ) + , assert true ) + +(* Labeled tuples in function return positions: Parens are needed iff the + first element is labeled AND the return is `local_` *) +module type S = sig + val t1 : unit -> int * y:bool + + val t2 : unit -> int * y:bool + + val t3 : unit -> x:int * y:bool + + val t4 : unit -> x:int * y:bool + + val f : + (foo:int * very_long_type_name_so_we_get_multiple_lines) + -> (* cmt *) + bar:('long_type_var_1, 'long_type_var_2) Long_module_name.t + -> additional_somewhat_long_type_name +end + +let _ = + match w with + | A -> ([], A.(B (C (f x))), None, f x y, g y x) + | B -> (a, b, c, d, e, f) + | C -> + ( [] + , A.(B (C (this is very looooooooooooooooooooooooooooooooooooong x))) + , None + , f x y + , g y x ) + +let _ = [%ext 1, 2, 3] + +let _ = + [%ext + loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + , loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + , 3] + +type t = int [@@deriving 1, 2, 3] + +type t = int +[@@deriving + sexp + , compare + , loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong] + +let _ = + ( 1 + , 2 + , looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + , looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong + ) + +let _ = (1, 2, 3, short) ;; + +1 +, 2 +, looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong +, looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong +;; + +1, 2, 3, short + +(* make sure to not drop parens for local open. *) +let _ = A.(1, 2) diff --git a/test/passing/tests/unboxed_tuples-erased.ml.why-no-js b/test/passing/tests/unboxed_tuples-erased.ml.why-no-js new file mode 100644 index 0000000000..0f1aefcf07 --- /dev/null +++ b/test/passing/tests/unboxed_tuples-erased.ml.why-no-js @@ -0,0 +1 @@ +Erasure test diff --git a/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.opts b/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.opts new file mode 100644 index 0000000000..41a1f7197c --- /dev/null +++ b/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.opts @@ -0,0 +1 @@ +--erase-jane-syntax --max-iter=3 diff --git a/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.ref b/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.ref new file mode 100644 index 0000000000..3c43820179 --- /dev/null +++ b/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.ref @@ -0,0 +1,102 @@ +(* Tests making sure comments and attributes are handled reasonably by + unboxed tuple printing. *) + +(* Attrs around expressions *) +let y = (z, (z [@attr])) + +let y = (z, z) [@@attr] + +let y = (((42 [@attr]) : int), 42) + +(* Comments around expressions *) +let _ = (* baz *) (42, y) + +let _ = ((* baz *) 42, y) + +let _ = (42 (* baz *), y) + +let _ = (42, (* baz *) y) + +let _ = (42, y (* baz *)) + +let _ = (42, y) (* baz *) + +let _ = (* baz *) (z, (y : int)) + +let _ = ((* baz *) z, (y : int)) + +let _ = (z (* baz *), (y : int)) + +let _ = (z, (* baz *) (y : int)) + +let _ = (z, ((* baz *) y : int)) + +let _ = (z, (y : (* baz *) int)) + +let _ = (z, (y : int (* baz *))) + +let _ = (z, (y : int) (* baz *)) + +let _ = (z, (y : int)) (* baz *) + +(* Attrs around types *) +type t = (int[@attr]) * bool + +type t = int * (bool[@attr]) + +type t = (int * bool[@attr]) + +type t = int * bool [@@attr] + +(* Comments around types *) +type t = (* baz *) int * bool + +type t = (* baz *) int * bool + +type t = z (* baz *) int * bool + +type t = int (* baz *) * bool + +type t = int * (* baz *) bool + +type t = int * y (* baz *) bool + +type t = int * bool (* baz *) + +type t = int * bool (* baz *) + +(* Attrs around patterns *) +let (z [@attr]), y = () + +let z, (42 [@attr]) = () + +let ((z, 42) [@attr]) = () + +(* Comments around patterns *) +let (* baz *) z, y = () + +let (* baz *) z, y = () + +let z (* baz *), y = () + +let z, (* baz *) y = () + +let z, y (* baz *) = () + +let z, y (* baz *) = () + +let (* baz *) 42, (y : int) = () + +let (* baz *) 42, (y : int) = () + +let 42 (* baz *), (y : int) = () + +let 42, ((* baz *) y : int) = () + +let 42, (y : (* baz *) int) = () + +let 42, (y : int (* baz *)) = () + +let 42, (y : int) (* baz *) = () + +let 42, (y : int) (* baz *) = () diff --git a/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.why-no-js b/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.why-no-js new file mode 100644 index 0000000000..0f1aefcf07 --- /dev/null +++ b/test/passing/tests/unboxed_tuples_cmts_attrs-erased.ml.why-no-js @@ -0,0 +1 @@ +Erasure test diff --git a/vendor/parser-extended/parser.mly b/vendor/parser-extended/parser.mly index 7d09f3dab3..be61914dc2 100644 --- a/vendor/parser-extended/parser.mly +++ b/vendor/parser-extended/parser.mly @@ -2844,7 +2844,9 @@ comprehension_clause: | simple_expr DOT mkrhs(label_longident) { Pexp_field($1, $3) } | simple_expr DOTHASH mkrhs(label_longident) - { Pexp_unboxed_field($1, $3) } + { if Erase_jane_syntax.should_erase () + then Pexp_field($1, $3) + else Pexp_unboxed_field($1, $3) } | od=open_dot_declaration DOT LPAREN seq_expr RPAREN { Pexp_open(od, $4) } | od=open_dot_declaration DOT LBRACELESS object_expr_content GREATERRBRACE @@ -2880,7 +2882,9 @@ comprehension_clause: Pexp_record(fields, exten) } | HASHLBRACE record_expr_content RBRACE { let (exten, fields) = $2 in - Pexp_record_unboxed_product(fields, exten) } + if Erase_jane_syntax.should_erase () + then Pexp_record(fields, exten) + else Pexp_record_unboxed_product(fields, exten) } | LBRACE record_expr_content error { unclosed "{" $loc($1) "}" $loc($3) } | od=open_dot_declaration DOT LBRACE record_expr_content RBRACE @@ -2924,7 +2928,9 @@ comprehension_clause: LPAREN MODULE ext_attributes module_expr COLON error { unclosed "(" $loc($3) ")" $loc($8) } | HASHLPAREN labeled_tuple RPAREN - { Pexp_unboxed_tuple $2 } + { if Erase_jane_syntax.should_erase () + then Pexp_tuple $2 + else Pexp_unboxed_tuple $2 } ; labeled_simple_expr: simple_expr %prec below_HASH @@ -3499,7 +3505,9 @@ simple_delimited_pattern: Ppat_record(fields, closed) } | HASHLBRACE record_pat_content RBRACE { let (fields, closed) = $2 in - Ppat_record_unboxed_product(fields, closed) } + if Erase_jane_syntax.should_erase () + then Ppat_record(fields, closed) + else Ppat_record_unboxed_product(fields, closed) } | LBRACE record_pat_content error { unclosed "{" $loc($1) "}" $loc($3) } | LBRACKET pattern_semi_list RBRACKET @@ -3518,7 +3526,9 @@ simple_delimited_pattern: $1 } | HASHLPAREN reversed_labeled_tuple_pattern(pattern) RPAREN { let (closed, fields) = $2 in - Ppat_unboxed_tuple (List.rev fields, closed) } + if Erase_jane_syntax.should_erase () + then Ppat_tuple (List.rev fields, closed) + else Ppat_unboxed_tuple (List.rev fields, closed) } ) { $1 } %inline pattern_semi_list: @@ -3685,7 +3695,12 @@ nonempty_type_kind: | oty = type_synonym priv = inline_private_flag HASHLBRACE ls = label_declarations RBRACE - { (Ptype_record_unboxed_product ls, priv, oty) } + { let record = + if Erase_jane_syntax.should_erase () + then Ptype_record ls + else Ptype_record_unboxed_product ls + in + (record, priv, oty) } ; %inline type_synonym: ioption(terminated(core_type, EQUAL)) @@ -4473,7 +4488,9 @@ atomic_type: | LBRACKETLESS BAR? row_field_list GREATER name_tag_list RBRACKET { Ptyp_variant($3, Closed, Some $5) } | HASHLPAREN unboxed_tuple_type_body RPAREN - { Ptyp_unboxed_tuple $2 } + { if Erase_jane_syntax.should_erase () + then Ptyp_tuple $2 + else Ptyp_unboxed_tuple $2 } | extension { Ptyp_extension $1 } | LPAREN QUOTE name=mkrhs(ident {Some $1}) COLON jkind=jkind_annotation RPAREN