From 861e7044624952189972bd7c7b10ed5c5d72b6f7 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sun, 3 Dec 2023 09:20:21 -0800 Subject: [PATCH 1/8] feat: uncurry 0 --- ppx/ast_attributes.ml | 17 +++++++++++------ ppx/ast_attributes.mli | 2 +- ppx/ast_core_type_class_type.ml | 9 ++++++--- ppx/ast_uncurry_gen.ml | 19 +++++++++++-------- ppx/ast_uncurry_gen.mli | 1 + ppx/melange_ppx.ml | 5 +++-- 6 files changed, 33 insertions(+), 20 deletions(-) diff --git a/ppx/ast_attributes.ml b/ppx/ast_attributes.ml index aed7ac012..88d805358 100644 --- a/ppx/ast_attributes.ml +++ b/ppx/ast_attributes.ml @@ -107,24 +107,29 @@ let process_method_attributes_rev attrs = type attr_kind = | Nothing | Meth_callback of attribute - | Uncurry of attribute + | Uncurry of { attribute : attribute; zero_arity : bool } | Method of attribute let process_attributes_rev attrs : attr_kind * attribute list = List.fold_left - ~f:(fun (st, acc) ({ attr_name = { txt; loc }; _ } as attr) -> + ~f:(fun (st, acc) ({ attr_name = { txt; loc }; _ } as attribute) -> match (txt, st) with | "u", (Nothing | Uncurry _) -> - (Uncurry attr, acc) (* TODO: warn unused/duplicated attribute *) + (Uncurry { attribute; zero_arity = false }, acc) + (* TODO: warn unused/duplicated attribute *) + | "u0", (Nothing | Uncurry { zero_arity = true; _ }) -> + (Uncurry { attribute; zero_arity = true }, acc) + | "u0", Uncurry { zero_arity = false; _ } -> + Location.raise_errorf ~loc "Cannot use both `[@u0]' and `[@u]'" | ("mel.this" | "this"), (Nothing | Meth_callback _) -> warn_if_non_namespaced ~loc txt; - (Meth_callback attr, acc) + (Meth_callback attribute, acc) | ("mel.meth" | "meth"), (Nothing | Method _) -> warn_if_non_namespaced ~loc txt; - (Method attr, acc) + (Method attribute, acc) | ("u" | "mel.this" | "this"), _ -> Error.err ~loc Conflict_u_mel_this_mel_meth - | _, _ -> (st, attr :: acc)) + | _, _ -> (st, attribute :: acc)) ~init:(Nothing, []) attrs let process_pexp_fun_attributes_rev attrs = diff --git a/ppx/ast_attributes.mli b/ppx/ast_attributes.mli index 09c5d8b50..d04d84c96 100644 --- a/ppx/ast_attributes.mli +++ b/ppx/ast_attributes.mli @@ -35,7 +35,7 @@ val process_method_attributes_rev : type attr_kind = | Nothing | Meth_callback of attribute - | Uncurry of attribute + | Uncurry of { attribute : attribute; zero_arity : bool } | Method of attribute val warn_if_non_namespaced : loc:location -> label -> unit diff --git a/ppx/ast_core_type_class_type.ml b/ppx/ast_core_type_class_type.ml index 9aa21ea2f..244c1abcc 100644 --- a/ppx/ast_core_type_class_type.ml +++ b/ppx/ast_core_type_class_type.ml @@ -107,7 +107,8 @@ let typ_mapper ((self, super) : Ast_traverse.map * (core_type -> core_type)) let attrs, core_type = match Ast_attributes.process_attributes_rev attrs with | Nothing, attrs -> (attrs, ty) (* #1678 *) - | Uncurry attr, attrs -> (attrs, attr +> ty) + | Uncurry { attribute; _ }, attrs -> + (attrs, attribute +> ty) | Method _, _ -> Location.raise_errorf ~loc "`%@mel.get' / `%@mel.set' cannot be used with \ @@ -120,7 +121,8 @@ let typ_mapper ((self, super) : Ast_traverse.map * (core_type -> core_type)) let attrs, core_type = match Ast_attributes.process_attributes_rev attrs with | Nothing, attrs -> (attrs, ty) - | Uncurry attr, attrs -> (attrs, attr +> ty) + | Uncurry { attribute; _ }, attrs -> + (attrs, attribute +> ty) | Method _, _ -> Location.raise_errorf ~loc "`%@mel.get' / `%@mel.set' cannot be used with \ @@ -138,7 +140,8 @@ let typ_mapper ((self, super) : Ast_traverse.map * (core_type -> core_type)) meth_.pof_attributes with | Nothing, attrs -> (attrs, ty) - | Uncurry attr, attrs -> (attrs, attr +> ty) + | Uncurry { attribute; _ }, attrs -> + (attrs, attribute +> ty) | Method attr, attrs -> (attrs, attr +> ty) | Meth_callback attr, attrs -> (attrs, attr +> ty) in diff --git a/ppx/ast_uncurry_gen.ml b/ppx/ast_uncurry_gen.ml index 2cf22a6e2..daff7f62b 100644 --- a/ppx/ast_uncurry_gen.ml +++ b/ppx/ast_uncurry_gen.ml @@ -66,8 +66,8 @@ let to_method_callback loc (self : Ast_traverse.map) label pat body : [ Typ.any ~loc () ]) ); ] ) -let to_uncurry_fn loc (self : Ast_traverse.map) (label : Asttypes.arg_label) pat - body : expression_desc = +let to_uncurry_fn loc (self : Ast_traverse.map) ~zero_arity + (label : Asttypes.arg_label) pat body : expression_desc = Error.optional_err ~loc label; let rec aux acc (body : expression) = match Ast_attributes.process_attributes_rev body.pexp_attributes with @@ -89,11 +89,14 @@ let to_uncurry_fn loc (self : Ast_traverse.map) (label : Asttypes.arg_label) pat in let len = List.length rev_extra_args in let arity = - match rev_extra_args with - | [ (_, p) ] -> Ast_pat.is_unit_cont ~yes:0 ~no:len p - | _ -> len + let arity = + match (rev_extra_args, zero_arity) with + | [ (_, _) ], true -> 0 + | [ _ ], false -> len (* Ast_pat.is_unit_cont ~yes:0 ~no:len p *) + | _ -> len + in + Error.err_large_arity ~loc arity; + string_of_int arity in - Error.err_large_arity ~loc arity; - let arity_s = string_of_int arity in Pexp_record - ([ ({ txt = Ldot (Ast_literal.js_fn, "I" ^ arity_s); loc }, body) ], None) + ([ ({ txt = Ldot (Ast_literal.js_fn, "I" ^ arity); loc }, body) ], None) diff --git a/ppx/ast_uncurry_gen.mli b/ppx/ast_uncurry_gen.mli index cbf138ad7..5b817873d 100644 --- a/ppx/ast_uncurry_gen.mli +++ b/ppx/ast_uncurry_gen.mli @@ -27,6 +27,7 @@ open Import val to_uncurry_fn : Location.t -> Ast_traverse.map -> + zero_arity:bool -> Asttypes.arg_label -> pattern -> expression -> diff --git a/ppx/melange_ppx.ml b/ppx/melange_ppx.ml index f486e6412..d6a07a97c 100644 --- a/ppx/melange_ppx.ml +++ b/ppx/melange_ppx.ml @@ -416,11 +416,12 @@ module Mapper = struct | Pexp_fun (label, _, pat, body) -> ( match Ast_attributes.process_attributes_rev e.pexp_attributes with | Nothing, _ -> super#expression e - | Uncurry _, pexp_attributes -> + | Uncurry { zero_arity; _ }, pexp_attributes -> { e with pexp_desc = - Ast_uncurry_gen.to_uncurry_fn e.pexp_loc self label pat body; + Ast_uncurry_gen.to_uncurry_fn e.pexp_loc self ~zero_arity + label pat body; pexp_attributes; } | Method _, _ -> From da4fb307748524c9ba98971c2c097d27d582640a Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Thu, 28 Dec 2023 20:41:01 +0000 Subject: [PATCH 2/8] progress --- ppx/ast_attributes.ml | 6 +-- ppx/ast_attributes.mli | 1 - ppx/ast_core_type.ml | 89 ++++++++++++++++++++++++--------- ppx/ast_core_type.mli | 2 +- ppx/ast_core_type_class_type.ml | 3 +- ppx/ast_exp_apply.ml | 79 +++++++++++++++++------------ ppx/ast_typ_uncurry.ml | 6 +-- ppx/ast_typ_uncurry.mli | 14 +++++- ppx/ast_uncurry_apply.ml | 26 +++++----- ppx/ast_uncurry_apply.mli | 2 + ppx/ast_uncurry_gen.ml | 2 +- test/blackbox-tests/uncurry-0.t | 24 +++++++++ 12 files changed, 171 insertions(+), 83 deletions(-) create mode 100644 test/blackbox-tests/uncurry-0.t diff --git a/ppx/ast_attributes.ml b/ppx/ast_attributes.ml index 88d805358..b9bafb2c6 100644 --- a/ppx/ast_attributes.ml +++ b/ppx/ast_attributes.ml @@ -138,17 +138,13 @@ let process_pexp_fun_attributes_rev attrs = match txt with "mel.open" -> (true, acc) | _ -> (st, attr :: acc)) ~init:(false, []) attrs +(* TODO: recognize `@u0` *) let process_uncurried attrs = List.fold_left ~f:(fun (st, acc) ({ attr_name = { txt; _ }; _ } as attr) -> match (txt, st) with "u", _ -> (true, acc) | _, _ -> (st, attr :: acc)) ~init:(false, []) attrs -let is_uncurried attr = - match attr with - | { attr_name = { Location.txt = "u"; _ }; _ } -> true - | _ -> false - let mel_get = { attr_name = { txt = "mel.get"; loc = Location.none }; diff --git a/ppx/ast_attributes.mli b/ppx/ast_attributes.mli index d04d84c96..7b46c81b4 100644 --- a/ppx/ast_attributes.mli +++ b/ppx/ast_attributes.mli @@ -42,7 +42,6 @@ val warn_if_non_namespaced : loc:location -> label -> unit val process_attributes_rev : attribute list -> attr_kind * attribute list val process_pexp_fun_attributes_rev : attribute list -> bool * attribute list val process_uncurried : attribute list -> bool * attribute list -val is_uncurried : attribute -> bool val mel_get : attribute val mel_get_index : attribute val mel_get_arity : attribute diff --git a/ppx/ast_core_type.ml b/ppx/ast_core_type.ml index e8e375dd7..fb93e3e32 100644 --- a/ppx/ast_core_type.ml +++ b/ppx/ast_core_type.ml @@ -47,32 +47,73 @@ let is_unit ty = let to_js_type ~loc x = Typ.constr ~loc { txt = Ast_literal.js_obj; loc } [ x ] let make_obj ~loc xs = to_js_type ~loc (Typ.object_ ~loc xs Closed) -(** - -{[ 'a . 'a -> 'b ]} -OCaml does not support such syntax yet -{[ 'a -> ('a. 'a -> 'b) ]} - -*) -let rec get_uncurry_arity_aux ty acc = - match ty.ptyp_desc with - | Ptyp_arrow (_, _, new_ty) -> get_uncurry_arity_aux new_ty (succ acc) - | Ptyp_poly (_, ty) -> get_uncurry_arity_aux ty acc - | _ -> acc - +(* (** {[ unit -> 'b ]} return arity 0 {[ unit -> 'a1 -> a2']} arity 2 {[ 'a1 -> 'a2 -> ... 'aN -> 'b ]} return arity N *) -let get_uncurry_arity ty = - match ty.ptyp_desc with - | Ptyp_arrow - ( Nolabel, - { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, - rest ) -> ( - match rest with - | { ptyp_desc = Ptyp_arrow _; _ } -> Some (get_uncurry_arity_aux rest 1) - | _ -> Some 0) - | Ptyp_arrow (_, _, rest) -> Some (get_uncurry_arity_aux rest 1) - | _ -> None +let get_uncurry_arity = + let rec get_uncurry_arity_aux ty acc = + (* {[ 'a . 'a -> 'b ]} + OCaml does not support such syntax yet + {[ 'a -> ('a. 'a -> 'b) ]} *) + match ty.ptyp_desc with + | Ptyp_arrow (_, _, new_ty) -> get_uncurry_arity_aux new_ty (succ acc) + | Ptyp_poly (_, ty) -> get_uncurry_arity_aux ty acc + | _ -> acc + in + fun ty -> + match ty.ptyp_desc with + | Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + rest ) -> ( + match rest with + | { ptyp_desc = Ptyp_arrow _; _ } -> Some (get_uncurry_arity_aux rest 1) + | _ -> + Format.eprintf "A FUCKIN HOY@."; + Some 0) + | Ptyp_arrow (_, _, rest) -> Some (get_uncurry_arity_aux rest 1) + | _ -> None + *) +let get_uncurry_arity = + let rec get_uncurry_arity_aux ty acc = + (* {[ 'a . 'a -> 'b ]} + OCaml does not support such syntax yet + {[ 'a -> ('a. 'a -> 'b) ]} *) + match ty.ptyp_desc with + | Ptyp_arrow (_, _, new_ty) -> get_uncurry_arity_aux new_ty (succ acc) + | Ptyp_poly (_, ty) -> get_uncurry_arity_aux ty acc + | _ -> acc + in + fun ?zero_arity ty -> + match (ty.ptyp_desc, zero_arity) with + | ( Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + ({ ptyp_desc = Ptyp_arrow _; _ } as rest) ), + (None | Some false) ) -> + Some (get_uncurry_arity_aux rest 1) + | ( Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + { ptyp_desc = Ptyp_arrow _; ptyp_loc; _ } ), + Some true ) -> + (* TODO: test this *) + Location.raise_errorf ~loc:ptyp_loc + "`[@u0]' cannot be used with multiple arguments" + | ( Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + _ ), + Some true ) -> + Format.eprintf "indeed@."; + Some 0 + | ( Ptyp_arrow (Nolabel, { ptyp_desc = Ptyp_constr _; ptyp_loc; _ }, _), + Some true ) -> + (* TODO: test this *) + Location.raise_errorf ~loc:ptyp_loc + "`[@u0]' can only be used with the `unit' type" + | Ptyp_arrow (_, _, rest), _ -> Some (get_uncurry_arity_aux rest 1) + | _ -> None diff --git a/ppx/ast_core_type.mli b/ppx/ast_core_type.mli index 4fce18ba5..62b2e258c 100644 --- a/ppx/ast_core_type.mli +++ b/ppx/ast_core_type.mli @@ -29,6 +29,6 @@ val is_unit : core_type -> bool val to_js_type : loc:Location.t -> core_type -> core_type val make_obj : loc:Location.t -> object_field list -> core_type -val get_uncurry_arity : core_type -> int option +val get_uncurry_arity : ?zero_arity:bool -> core_type -> int option (** returns 0 when it can not tell arity from the syntax. [None] means not a function *) diff --git a/ppx/ast_core_type_class_type.ml b/ppx/ast_core_type_class_type.ml index 244c1abcc..5f8091762 100644 --- a/ppx/ast_core_type_class_type.ml +++ b/ppx/ast_core_type_class_type.ml @@ -87,7 +87,8 @@ let typ_mapper ((self, super) : Ast_traverse.map * (core_type -> core_type)) _; } -> ( match fst (Ast_attributes.process_attributes_rev ptyp_attributes) with - | Uncurry _ -> Ast_typ_uncurry.to_uncurry_type loc self label args body + | Uncurry { zero_arity; _ } -> + Ast_typ_uncurry.to_uncurry_type loc self ~zero_arity label args body | Meth_callback _ -> Ast_typ_uncurry.to_method_callback_type loc self label args body | Method _ -> Ast_typ_uncurry.to_method_type loc self label args body diff --git a/ppx/ast_exp_apply.ml b/ppx/ast_exp_apply.ml index 5d51f2e8d..240e91d69 100644 --- a/ppx/ast_exp_apply.ml +++ b/ppx/ast_exp_apply.ml @@ -68,26 +68,40 @@ let view_as_app fn (s : string list) : app_pattern option = let inner_ops = [ "##"; "#@" ] -let rec exclude_with_val = - let rec exclude (xs : 'a list) (p : 'a -> bool) : 'a list = - match xs with - | [] -> [] - | x :: xs -> if p x then exclude xs p else x :: exclude xs p +let is_uncurried = + let is_uncurried attr = + match attr with + | { attr_name = { Location.txt = "u0"; _ }; _ } -> `Arity_0 + | { attr_name = { Location.txt = "u"; _ }; _ } -> `Arity_n + | _ -> `No in - fun l p -> - match l with - | [] -> None - | a0 :: xs -> ( - if p a0 then Some (exclude xs p) - else - match xs with - | [] -> None - | a1 :: rest -> ( - if p a1 then Some (a0 :: exclude rest p) - else - match exclude_with_val rest p with - | None -> None - | Some rest -> Some (a0 :: a1 :: rest))) + let pred x = match is_uncurried x with `No -> false | _ -> true in + let rec exclude_with_val = + let rec exclude (xs : 'a list) = + match xs with + | [] -> [] + | x :: xs -> if pred x then exclude xs else x :: exclude xs + in + fun l -> + match l with + | [] -> None + | a0 :: xs -> ( + match is_uncurried a0 with + | `Arity_0 -> Some (exclude xs, true) + | `Arity_n -> Some (exclude xs, false) + | `No -> ( + match xs with + | [] -> None + | a1 :: rest -> ( + match is_uncurried a1 with + | `Arity_0 -> Some (a0 :: exclude rest, true) + | `Arity_n -> Some (a0 :: exclude rest, false) + | `No -> ( + match exclude_with_val rest with + | None -> None + | Some (rest, u) -> Some (a0 :: a1 :: rest, u))))) + in + fun l -> exclude_with_val l let app_exp_mapper e ((self, super) : Ast_traverse.map * (expression -> expression)) fn args = @@ -105,7 +119,10 @@ let app_exp_mapper e pexp_desc = (if op = "##" then Ast_uncurry_apply.method_apply loc self obj name args - else Ast_uncurry_apply.property_apply loc self obj name args); + else + (* TODO(anmonteiro): check this zero_arity *) + Ast_uncurry_apply.property_apply loc self ~zero_arity:false obj + name args); } | Some { op; loc; _ } -> Location.raise_errorf ~loc "%s expect f%sproperty arg0 arg2 form" op op @@ -208,12 +225,9 @@ let app_exp_mapper e pexp_loc_stack = []; } | _ -> ( - match - ( exclude_with_val f_.pexp_attributes - Ast_attributes.is_uncurried, - f_.pexp_desc ) - with - | Some other_attributes, Pexp_apply (fn1, args) -> + match (is_uncurried f_.pexp_attributes, f_.pexp_desc) with + | Some (other_attributes, zero_arity), Pexp_apply (fn1, args) + -> (* a |. f b c [@u] Cannot process uncurried application early as the arity is wip *) let fn1 = self#expression fn1 in @@ -225,8 +239,8 @@ let app_exp_mapper e fn1.pexp_attributes; { pexp_desc = - Ast_uncurry_apply.uncurry_fn_apply e.pexp_loc self fn1 - ((Nolabel, a) :: args); + Ast_uncurry_apply.uncurry_fn_apply e.pexp_loc self + ~zero_arity fn1 ((Nolabel, a) :: args); pexp_loc = e.pexp_loc; pexp_loc_stack = e.pexp_loc_stack; pexp_attributes = e.pexp_attributes @ other_attributes; @@ -327,15 +341,14 @@ let app_exp_mapper e | Some { op; _ } -> Location.raise_errorf "invalid %s syntax" op | None -> let e = - match - exclude_with_val e.pexp_attributes Ast_attributes.is_uncurried - with + match is_uncurried e.pexp_attributes with | None -> super e - | Some pexp_attributes -> + | Some (pexp_attributes, zero_arity) -> { e with pexp_desc = - Ast_uncurry_apply.uncurry_fn_apply e.pexp_loc self fn args; + Ast_uncurry_apply.uncurry_fn_apply e.pexp_loc self + ~zero_arity fn args; pexp_attributes; } in diff --git a/ppx/ast_typ_uncurry.ml b/ppx/ast_typ_uncurry.ml index 73560f8b7..e6695704b 100644 --- a/ppx/ast_typ_uncurry.ml +++ b/ppx/ast_typ_uncurry.ml @@ -115,8 +115,8 @@ let generate_arg_type loc (mapper : Ast_traverse.map) method_name label pat body to_method_type loc mapper label x method_rest | _ -> assert false -let to_uncurry_type loc (mapper : Ast_traverse.map) (label : Asttypes.arg_label) - (first_arg : core_type) (typ : core_type) = +let to_uncurry_type loc (mapper : Ast_traverse.map) ~(zero_arity : bool) + (label : Asttypes.arg_label) (first_arg : core_type) (typ : core_type) = (* no need to error for optional here, since we can not make it TODO: still error out for external? @@ -127,7 +127,7 @@ let to_uncurry_type loc (mapper : Ast_traverse.map) (label : Asttypes.arg_label) let typ = mapper#core_type typ in let fn_type = Typ.arrow ~loc label first_arg typ in - let arity = Ast_core_type.get_uncurry_arity fn_type in + let arity = Ast_core_type.get_uncurry_arity ~zero_arity fn_type in match arity with | Some 0 -> Typ.constr { txt = Ldot (Ast_literal.js_fn, "arity0"); loc } [ typ ] diff --git a/ppx/ast_typ_uncurry.mli b/ppx/ast_typ_uncurry.mli index 980bc840e..925262047 100644 --- a/ppx/ast_typ_uncurry.mli +++ b/ppx/ast_typ_uncurry.mli @@ -49,9 +49,19 @@ type uncurry_type_gen = core_type) cxt -val to_uncurry_type : uncurry_type_gen +val to_uncurry_type : + Ast_helper.loc -> + Ast_traverse.map -> + zero_arity:bool -> + Asttypes.arg_label -> + (* label for error checking *) + core_type -> + (* First arg *) + core_type -> + (* Tail *) + core_type (** syntax : - {[ int -> int -> int [@bs]]} + {[ int -> int -> int [@u]]} *) val to_method_type : uncurry_type_gen diff --git a/ppx/ast_uncurry_apply.ml b/ppx/ast_uncurry_apply.ml index da2a751a6..bcb3bafd8 100644 --- a/ppx/ast_uncurry_apply.ml +++ b/ppx/ast_uncurry_apply.ml @@ -29,7 +29,6 @@ open Ast_helper have a final checking for property arities [#=], *) -let jsInternal = Ast_literal.js_internal (* we use the trick [( opaque e : _) ] to avoid it being inspected, @@ -56,7 +55,7 @@ let opaque_full_apply ~loc e = [ (Nolabel, e) ], Typ.any ~loc () ) -let generic_apply loc (self : Ast_traverse.map) obj args +let generic_apply loc (self : Ast_traverse.map) ~zero_arity obj args (cb : loc -> expression -> expression) = let obj = self#expression obj in let args = @@ -68,18 +67,21 @@ let generic_apply loc (self : Ast_traverse.map) obj args in let fn = cb loc obj in let args = - match args with - | [ - ( Nolabel, - { pexp_desc = Pexp_construct ({ txt = Lident "()"; _ }, None); _ } ); - ] -> + match (args, zero_arity) with + | ( [ + ( Nolabel, + { pexp_desc = Pexp_construct ({ txt = Lident "()"; _ }, None); _ } + ); + ], + true ) -> [] | _ -> args in let arity = List.length args in if arity = 0 then Pexp_apply - (Exp.ident { txt = Ldot (jsInternal, "run"); loc }, [ (Nolabel, fn) ]) + ( Exp.ident { txt = Ldot (Ast_literal.js_internal, "run"); loc }, + [ (Nolabel, fn) ] ) else let arity_s = string_of_int arity in opaque_full_apply ~loc @@ -145,9 +147,9 @@ let method_apply loc (self : Ast_traverse.map) obj name args = ]) args) -let uncurry_fn_apply loc self fn args = - generic_apply loc self fn args (fun _ obj -> obj) +let uncurry_fn_apply loc self ~zero_arity fn args = + generic_apply loc self ~zero_arity fn args (fun _ obj -> obj) -let property_apply loc self obj name args = - generic_apply loc self obj args (fun loc obj -> +let property_apply loc self ~zero_arity obj name args = + generic_apply loc self ~zero_arity obj args (fun loc obj -> Exp.mk ~loc (Ast_util.js_property loc obj name)) diff --git a/ppx/ast_uncurry_apply.mli b/ppx/ast_uncurry_apply.mli index 2ed24cb61..2e5a6fa4b 100644 --- a/ppx/ast_uncurry_apply.mli +++ b/ppx/ast_uncurry_apply.mli @@ -29,6 +29,7 @@ open Import val uncurry_fn_apply : Location.t -> Ast_traverse.map -> + zero_arity:bool -> expression -> (Asttypes.arg_label * expression) list -> expression_desc @@ -46,6 +47,7 @@ val method_apply : val property_apply : Location.t -> Ast_traverse.map -> + zero_arity:bool -> expression -> string -> (Asttypes.arg_label * expression) list -> diff --git a/ppx/ast_uncurry_gen.ml b/ppx/ast_uncurry_gen.ml index daff7f62b..a66f4b0b6 100644 --- a/ppx/ast_uncurry_gen.ml +++ b/ppx/ast_uncurry_gen.ml @@ -91,7 +91,7 @@ let to_uncurry_fn loc (self : Ast_traverse.map) ~zero_arity let arity = let arity = match (rev_extra_args, zero_arity) with - | [ (_, _) ], true -> 0 + | [ _ ], true -> 0 | [ _ ], false -> len (* Ast_pat.is_unit_cont ~yes:0 ~no:len p *) | _ -> len in diff --git a/test/blackbox-tests/uncurry-0.t b/test/blackbox-tests/uncurry-0.t new file mode 100644 index 000000000..34b465794 --- /dev/null +++ b/test/blackbox-tests/uncurry-0.t @@ -0,0 +1,24 @@ + + $ . ./setup.sh + +Test some error cases + + $ cat > x.ml < external valToFn : 'a -> (int -> 'a[@u0]) = "foo" + > EOF + $ melc -ppx melppx x.ml + File "x.ml", line 1, characters 26-29: + 1 | external valToFn : 'a -> (int -> 'a[@u0]) = "foo" + ^^^ + Error: `[@u0]' can only be used with the `unit' type + [2] + + $ cat > x.ml < external valToFn : 'a -> (unit -> int -> 'a[@u0]) = "foo" + > EOF + $ melc -ppx melppx x.ml + File "x.ml", line 1, characters 34-43: + 1 | external valToFn : 'a -> (unit -> int -> 'a[@u0]) = "foo" + ^^^^^^^^^ + Error: `[@u0]' cannot be used with multiple arguments + [2] From 40f2444c0b58d4366100bb844a8db5428cb23a6b Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Mon, 1 Jan 2024 18:17:01 -0800 Subject: [PATCH 3/8] revert `@mel.meth` stuff to old behavior, add uncurried_arity0 alert --- ppx/ast_core_type.ml | 115 ++++++++++++++++---------------------- ppx/ast_core_type.mli | 7 ++- ppx/ast_exp_apply.ml | 3 +- ppx/ast_typ_uncurry.ml | 26 ++++++--- ppx/ast_uncurry_apply.ml | 11 +++- ppx/ast_uncurry_apply.mli | 1 - ppx/mel_ast_invariant.ml | 12 +++- ppx/mel_ast_invariant.mli | 1 + 8 files changed, 92 insertions(+), 84 deletions(-) diff --git a/ppx/ast_core_type.ml b/ppx/ast_core_type.ml index fb93e3e32..1c004c6da 100644 --- a/ppx/ast_core_type.ml +++ b/ppx/ast_core_type.ml @@ -47,73 +47,54 @@ let is_unit ty = let to_js_type ~loc x = Typ.constr ~loc { txt = Ast_literal.js_obj; loc } [ x ] let make_obj ~loc xs = to_js_type ~loc (Typ.object_ ~loc xs Closed) +let rec get_uncurry_arity_aux ty acc = + (* {[ 'a . 'a -> 'b ]} + OCaml does not support such syntax yet + {[ 'a -> ('a. 'a -> 'b) ]} *) + match ty.ptyp_desc with + | Ptyp_arrow (_, _, new_ty) -> get_uncurry_arity_aux new_ty (succ acc) + | Ptyp_poly (_, ty) -> get_uncurry_arity_aux ty acc + | _ -> acc + +let get_uncurry_arity_from_attribute ~zero_arity ty = + match (ty.ptyp_desc, zero_arity) with + | ( Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + ({ ptyp_desc = Ptyp_arrow _; _ } as rest) ), + false ) -> + Some (get_uncurry_arity_aux rest 1) + | ( Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + { ptyp_desc = Ptyp_arrow _; ptyp_loc; _ } ), + true ) -> + Location.raise_errorf ~loc:ptyp_loc + "`[@u0]' cannot be used with multiple arguments" + | ( Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + _ ), + true ) -> + Some 0 + | Ptyp_arrow (Nolabel, { ptyp_desc = Ptyp_constr _; ptyp_loc; _ }, _), true -> + Location.raise_errorf ~loc:ptyp_loc + "`[@u0]' can only be used with the `unit' type" + | Ptyp_arrow (_, _, rest), _ -> Some (get_uncurry_arity_aux rest 1) + | _ -> None + (* -(** {[ unit -> 'b ]} return arity 0 {[ unit -> 'a1 -> a2']} arity 2 - {[ 'a1 -> 'a2 -> ... 'aN -> 'b ]} return arity N -*) -let get_uncurry_arity = - let rec get_uncurry_arity_aux ty acc = - (* {[ 'a . 'a -> 'b ]} - OCaml does not support such syntax yet - {[ 'a -> ('a. 'a -> 'b) ]} *) - match ty.ptyp_desc with - | Ptyp_arrow (_, _, new_ty) -> get_uncurry_arity_aux new_ty (succ acc) - | Ptyp_poly (_, ty) -> get_uncurry_arity_aux ty acc - | _ -> acc - in - fun ty -> - match ty.ptyp_desc with - | Ptyp_arrow - ( Nolabel, - { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, - rest ) -> ( - match rest with - | { ptyp_desc = Ptyp_arrow _; _ } -> Some (get_uncurry_arity_aux rest 1) - | _ -> - Format.eprintf "A FUCKIN HOY@."; - Some 0) - | Ptyp_arrow (_, _, rest) -> Some (get_uncurry_arity_aux rest 1) - | _ -> None - *) -let get_uncurry_arity = - let rec get_uncurry_arity_aux ty acc = - (* {[ 'a . 'a -> 'b ]} - OCaml does not support such syntax yet - {[ 'a -> ('a. 'a -> 'b) ]} *) - match ty.ptyp_desc with - | Ptyp_arrow (_, _, new_ty) -> get_uncurry_arity_aux new_ty (succ acc) - | Ptyp_poly (_, ty) -> get_uncurry_arity_aux ty acc - | _ -> acc - in - fun ?zero_arity ty -> - match (ty.ptyp_desc, zero_arity) with - | ( Ptyp_arrow - ( Nolabel, - { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, - ({ ptyp_desc = Ptyp_arrow _; _ } as rest) ), - (None | Some false) ) -> - Some (get_uncurry_arity_aux rest 1) - | ( Ptyp_arrow - ( Nolabel, - { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, - { ptyp_desc = Ptyp_arrow _; ptyp_loc; _ } ), - Some true ) -> - (* TODO: test this *) - Location.raise_errorf ~loc:ptyp_loc - "`[@u0]' cannot be used with multiple arguments" - | ( Ptyp_arrow - ( Nolabel, - { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, - _ ), - Some true ) -> - Format.eprintf "indeed@."; - Some 0 - | ( Ptyp_arrow (Nolabel, { ptyp_desc = Ptyp_constr _; ptyp_loc; _ }, _), - Some true ) -> - (* TODO: test this *) - Location.raise_errorf ~loc:ptyp_loc - "`[@u0]' can only be used with the `unit' type" - | Ptyp_arrow (_, _, rest), _ -> Some (get_uncurry_arity_aux rest 1) - | _ -> None + {[ 'a1 -> 'a2 -> ... 'aN -> 'b ]} return arity N *) +let get_uncurry_arity ty = + match ty.ptyp_desc with + | Ptyp_arrow + ( Nolabel, + { ptyp_desc = Ptyp_constr ({ txt = Lident "unit"; _ }, []); _ }, + rest ) -> ( + match rest with + | { ptyp_desc = Ptyp_arrow _; _ } -> Some (get_uncurry_arity_aux rest 1) + | _ -> Some 0) + | Ptyp_arrow (_, _, rest) -> Some (get_uncurry_arity_aux rest 1) + | _ -> None diff --git a/ppx/ast_core_type.mli b/ppx/ast_core_type.mli index 62b2e258c..63b14653f 100644 --- a/ppx/ast_core_type.mli +++ b/ppx/ast_core_type.mli @@ -29,6 +29,11 @@ val is_unit : core_type -> bool val to_js_type : loc:Location.t -> core_type -> core_type val make_obj : loc:Location.t -> object_field list -> core_type -val get_uncurry_arity : ?zero_arity:bool -> core_type -> int option +val get_uncurry_arity : core_type -> int option +(** returns 0 when it can not tell arity from the syntax. [None] means not a + function *) + +val get_uncurry_arity_from_attribute : + zero_arity:bool -> core_type -> int option (** returns 0 when it can not tell arity from the syntax. [None] means not a function *) diff --git a/ppx/ast_exp_apply.ml b/ppx/ast_exp_apply.ml index 240e91d69..72b77bcd9 100644 --- a/ppx/ast_exp_apply.ml +++ b/ppx/ast_exp_apply.ml @@ -121,8 +121,7 @@ let app_exp_mapper e Ast_uncurry_apply.method_apply loc self obj name args else (* TODO(anmonteiro): check this zero_arity *) - Ast_uncurry_apply.property_apply loc self ~zero_arity:false obj - name args); + Ast_uncurry_apply.property_apply loc self obj name args); } | Some { op; loc; _ } -> Location.raise_errorf ~loc "%s expect f%sproperty arg0 arg2 form" op op diff --git a/ppx/ast_typ_uncurry.ml b/ppx/ast_typ_uncurry.ml index e6695704b..08c095be6 100644 --- a/ppx/ast_typ_uncurry.ml +++ b/ppx/ast_typ_uncurry.ml @@ -84,8 +84,9 @@ let to_method_type loc (mapper : Ast_traverse.map) (label : Asttypes.arg_label) let first_arg = mapper#core_type first_arg in let typ = mapper#core_type typ in let meth_type = Typ.arrow ~loc label first_arg typ in - let arity = Ast_core_type.get_uncurry_arity meth_type in - match arity with + (* Use the old `get_uncurry_arity` function to get the old behavior (`unit` + means 0-arity) *) + match Ast_core_type.get_uncurry_arity meth_type with | Some 0 -> Typ.constr { txt = Ldot (Ast_literal.js_meth, "arity0"); loc } [ typ ] | Some n -> @@ -125,14 +126,21 @@ let to_uncurry_type loc (mapper : Ast_traverse.map) ~(zero_arity : bool) *) let first_arg = mapper#core_type first_arg in let typ = mapper#core_type typ in - let fn_type = Typ.arrow ~loc label first_arg typ in - let arity = Ast_core_type.get_uncurry_arity ~zero_arity fn_type in - match arity with - | Some 0 -> - Typ.constr { txt = Ldot (Ast_literal.js_fn, "arity0"); loc } [ typ ] - | Some n -> + match + (* always `Some _` because we're passing it an arrow *) + ( Option.get + (Ast_core_type.get_uncurry_arity_from_attribute ~zero_arity fn_type), + Option.get (Ast_core_type.get_uncurry_arity fn_type) ) + with + | 0, 0 -> Typ.constr { txt = Ldot (Ast_literal.js_fn, "arity0"); loc } [ typ ] + | n, 0 -> + Mel_ast_invariant.warn ~loc Uncurried_arity0; + Typ.constr + { txt = Ldot (Ast_literal.js_fn, "arity" ^ string_of_int n); loc } + [ fn_type ] + | n, m -> + assert (n = m); Typ.constr { txt = Ldot (Ast_literal.js_fn, "arity" ^ string_of_int n); loc } [ fn_type ] - | None -> assert false diff --git a/ppx/ast_uncurry_apply.ml b/ppx/ast_uncurry_apply.ml index bcb3bafd8..b49f4445a 100644 --- a/ppx/ast_uncurry_apply.ml +++ b/ppx/ast_uncurry_apply.ml @@ -150,6 +150,15 @@ let method_apply loc (self : Ast_traverse.map) obj name args = let uncurry_fn_apply loc self ~zero_arity fn args = generic_apply loc self ~zero_arity fn args (fun _ obj -> obj) -let property_apply loc self ~zero_arity obj name args = +let property_apply loc self obj name args = + let zero_arity = + match args with + | [ + ( Nolabel, + { pexp_desc = Pexp_construct ({ txt = Lident "()"; _ }, None); _ } ); + ] -> + true + | _ -> false + in generic_apply loc self ~zero_arity obj args (fun loc obj -> Exp.mk ~loc (Ast_util.js_property loc obj name)) diff --git a/ppx/ast_uncurry_apply.mli b/ppx/ast_uncurry_apply.mli index 2e5a6fa4b..6dbfa4e55 100644 --- a/ppx/ast_uncurry_apply.mli +++ b/ppx/ast_uncurry_apply.mli @@ -47,7 +47,6 @@ val method_apply : val property_apply : Location.t -> Ast_traverse.map -> - zero_arity:bool -> expression -> string -> (Asttypes.arg_label * expression) list -> diff --git a/ppx/mel_ast_invariant.ml b/ppx/mel_ast_invariant.ml index fbdddc433..49a4f82e7 100644 --- a/ppx/mel_ast_invariant.ml +++ b/ppx/mel_ast_invariant.ml @@ -30,12 +30,14 @@ module Warnings = struct | Fragile_external of string | Redundant_mel_string | Deprecated_non_namespaced_attribute + | Uncurried_arity0 let kind = function | Unused_attribute _ -> "unused" | Fragile_external _ -> "fragile" | Redundant_mel_string -> "redundant" | Deprecated_non_namespaced_attribute -> "deprecated" + | Uncurried_arity0 -> "uncurried" let pp fmt t = match t with @@ -43,8 +45,7 @@ module Warnings = struct Format.fprintf fmt "Unused attribute [%@%s]@\n\ This means such annotation is not annotated properly.@\n\ - For example, some annotations are only meaningful in externals\n" - s + For example, some annotations are only meaningful in externals" s | Fragile_external s -> Format.fprintf fmt "%s : the external name is inferred from val name is unsafe from \ @@ -52,12 +53,17 @@ module Warnings = struct s | Redundant_mel_string -> Format.fprintf fmt - "[@mel.string] is redundant here, you can safely remove it" + "`[@mel.string]' is redundant here, you can safely remove it" | Deprecated_non_namespaced_attribute -> Format.fprintf fmt "FFI attributes without a namespace are deprecated and will be \ removed in the next release.@\n\ Use `mel.*' instead." + | Uncurried_arity0 -> + Format.fprintf fmt + "This uncurried function takes a single unit argument, but will be \ + applied with `undefined' in the compiled JS.@\n\ + Use `[@u0]' if it is intended to have 0-arity." end let warn = diff --git a/ppx/mel_ast_invariant.mli b/ppx/mel_ast_invariant.mli index 44a19b535..af6293e81 100644 --- a/ppx/mel_ast_invariant.mli +++ b/ppx/mel_ast_invariant.mli @@ -30,6 +30,7 @@ module Warnings : sig | Fragile_external of string | Redundant_mel_string | Deprecated_non_namespaced_attribute + | Uncurried_arity0 end val is_mel_attribute : string -> bool From 2c4b763bd507963a064a4dee3e3b44b969c5f51c Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Mon, 8 Jan 2024 19:14:10 -0800 Subject: [PATCH 4/8] chore: fix blackbox tests --- test/blackbox-tests/legacy-ounit-cmd.t | 6 ------ test/blackbox-tests/mel-as-string-warnings.t | 2 +- test/blackbox-tests/mel-uncurry-nesting.t | 10 +++++----- test/blackbox-tests/melange-playground/ppx-alerts.t | 8 ++++---- test/blackbox-tests/unused-attributes.t | 1 - 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/test/blackbox-tests/legacy-ounit-cmd.t b/test/blackbox-tests/legacy-ounit-cmd.t index 808229064..e5f1649f5 100644 --- a/test/blackbox-tests/legacy-ounit-cmd.t +++ b/test/blackbox-tests/legacy-ounit-cmd.t @@ -47,7 +47,6 @@ Skip over the temporary file name printed in the error trace Alert unused: Unused attribute [@u] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - // Generated by Melange 'use strict'; @@ -66,7 +65,6 @@ Skip over the temporary file name printed in the error trace Alert unused: Unused attribute [@mel.string] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - // Generated by Melange /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ @@ -95,7 +93,6 @@ Skip over the temporary file name printed in the error trace Alert unused: Unused attribute [@mel.uncurry] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - // Generated by Melange /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ @@ -120,7 +117,6 @@ Skip over the temporary file name printed in the error trace Alert unused: Unused attribute [@mel.string] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - // Generated by Melange /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ @@ -237,7 +233,6 @@ Skip over the temporary file name printed in the error trace Alert unused: Unused attribute [@u] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - // Generated by Melange 'use strict'; @@ -264,7 +259,6 @@ Skip over the temporary file name printed in the error trace Alert unused: Unused attribute [@mel.string] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - // Generated by Melange /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/test/blackbox-tests/mel-as-string-warnings.t b/test/blackbox-tests/mel-as-string-warnings.t index 2e85b0159..6282e9c0f 100644 --- a/test/blackbox-tests/mel-as-string-warnings.t +++ b/test/blackbox-tests/mel-as-string-warnings.t @@ -11,7 +11,7 @@ This external triggers the `redundant` alert File "x.ml", line 1, characters 16-24: 1 | external foo : ([ `foo ][@mel.string]) -> string = "foo" ^^^^^^^^ - Alert redundant: [@mel.string] is redundant here, you can safely remove it + Alert redundant: `[@mel.string]' is redundant here, you can safely remove it // Generated by Melange 'use strict'; diff --git a/test/blackbox-tests/mel-uncurry-nesting.t b/test/blackbox-tests/mel-uncurry-nesting.t index 3081fd6cc..b6e8268db 100644 --- a/test/blackbox-tests/mel-uncurry-nesting.t +++ b/test/blackbox-tests/mel-uncurry-nesting.t @@ -38,21 +38,21 @@ Using `mel.uncurry` at 2nd level of callbacks raises some alerts This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - File "x.ml", line 2, characters 52-63: 2 | (((unit -> unit)[@mel.uncurry]) -> (unit -> unit[@mel.uncurry])) -> unit ^^^^^^^^^^^ Alert unused: Unused attribute [@mel.uncurry] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - -In the case of uncurry nesting, we have to resort to the `[@u]` attribute + +In the case of uncurry nesting, we have to resort to the `[@u]` / `[@u0]` +attributes $ cat > x.ml < external foo : (((unit -> unit)[@u]) -> unit) -> unit = "foo" - > let () = foo (fun f -> f () [@u]) + > external foo : (((unit -> unit)[@u0]) -> unit) -> unit = "foo" + > let () = foo (fun f -> f () [@u0]) > EOF $ dune build @melange diff --git a/test/blackbox-tests/melange-playground/ppx-alerts.t b/test/blackbox-tests/melange-playground/ppx-alerts.t index c317afa9f..2438f6e7d 100644 --- a/test/blackbox-tests/melange-playground/ppx-alerts.t +++ b/test/blackbox-tests/melange-playground/ppx-alerts.t @@ -13,28 +13,28 @@ js_warning_error_msg: 'Line 1, 18:\n' + ' Alert: unused Unused attribute [@mel.uncurry]\n' + 'This means such annotation is not annotated properly.\n' + - 'For example, some annotations are only meaningful in externals\n', + 'For example, some annotations are only meaningful in externals', row: 0, column: 18, endRow: 0, endColumn: 29, text: 'Unused attribute [@mel.uncurry]\n' + 'This means such annotation is not annotated properly.\n' + - 'For example, some annotations are only meaningful in externals\n', + 'For example, some annotations are only meaningful in externals', type: 'alert' }, { js_warning_error_msg: 'Line 1, 52:\n' + ' Alert: unused Unused attribute [@mel.uncurry]\n' + 'This means such annotation is not annotated properly.\n' + - 'For example, some annotations are only meaningful in externals\n', + 'For example, some annotations are only meaningful in externals', row: 0, column: 52, endRow: 0, endColumn: 63, text: 'Unused attribute [@mel.uncurry]\n' + 'This means such annotation is not annotated properly.\n' + - 'For example, some annotations are only meaningful in externals\n', + 'For example, some annotations are only meaningful in externals', type: 'alert' } ], diff --git a/test/blackbox-tests/unused-attributes.t b/test/blackbox-tests/unused-attributes.t index b6d32c8cc..467354d30 100644 --- a/test/blackbox-tests/unused-attributes.t +++ b/test/blackbox-tests/unused-attributes.t @@ -14,7 +14,6 @@ Alert unused: Unused attribute [@mel.string] This means such annotation is not annotated properly. For example, some annotations are only meaningful in externals - // Generated by Melange /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ From 0f4178b3783363d0cda2dbb702964f65bc4f6227 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 9 Jan 2024 09:07:28 -0800 Subject: [PATCH 5/8] test: show the uncurried alert during migration to `[@u0]` --- test/blackbox-tests/uncurry-0.t | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/blackbox-tests/uncurry-0.t b/test/blackbox-tests/uncurry-0.t index 34b465794..b191802ed 100644 --- a/test/blackbox-tests/uncurry-0.t +++ b/test/blackbox-tests/uncurry-0.t @@ -22,3 +22,26 @@ Test some error cases ^^^^^^^^^ Error: `[@u0]' cannot be used with multiple arguments [2] + +PPX shows an alert when `@u` is used with `unit` + + $ cat > x.ml < external foo : (((unit -> unit)[@u]) -> unit) -> unit = "foo" + > let () = foo (fun f -> f () [@u]) + > EOF + + $ melc -ppx melppx x.ml + File "x.ml", line 1, characters 18-30: + 1 | external foo : (((unit -> unit)[@u]) -> unit) -> unit = "foo" + ^^^^^^^^^^^^ + Alert uncurried: This uncurried function takes a single unit argument, but will be applied with `undefined' in the compiled JS. + Use `[@u0]' if it is intended to have 0-arity. + // Generated by Melange + 'use strict'; + + + foo(function (f) { + f(undefined); + }); + + /* Not a pure module */ From 419b8d5801b0552bdb1bad131e1194bc5211f8b2 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 16 Jan 2024 19:22:52 -0800 Subject: [PATCH 6/8] update submodule --- flake.lock | 32 ++++++++++++++++---------------- vendor/melange-compiler-libs | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index a3cfac102..ef85a98c8 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", "type": "github" }, "original": { @@ -28,11 +28,11 @@ ] }, "locked": { - "lastModified": 1704861910, - "narHash": "sha256-1dub8rJZkAjZiKR0EopdXVP3JCbSq/8fAw2Fei0Hh+E=", + "lastModified": 1705459919, + "narHash": "sha256-tMXzgPoT2DMLftT/4ntFAfbXZ76Wjgji942rlZlCi9o=", "owner": "melange-re", "repo": "melange-compiler-libs", - "rev": "61653c60844cd04af5733512768618fa9b05ec71", + "rev": "3ef2115fb156d28aad4564fbfdb3df125fe5ba4d", "type": "github" }, "original": { @@ -43,11 +43,11 @@ }, "nix-filter": { "locked": { - "lastModified": 1701697642, - "narHash": "sha256-L217WytWZHSY8GW9Gx1A64OnNctbuDbfslaTEofXXRw=", + "lastModified": 1705332318, + "narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=", "owner": "numtide", "repo": "nix-filter", - "rev": "c843418ecfd0344ecb85844b082ff5675e02c443", + "rev": "3449dc925982ad46246cfc36469baf66e1b64f17", "type": "github" }, "original": { @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1705277551, - "narHash": "sha256-T/HpuRjBj4CRGYSLvs3ezlzcp2WlRr5eBUrGfrCBGKc=", + "lastModified": 1705460136, + "narHash": "sha256-4bl+nspzOzkCt1m+jo8KkT2G+ckSUekyr8lY56oklCc=", "owner": "nix-ocaml", "repo": "nix-overlays", - "rev": "4798c7a11836ba876bf5e0402d4dd730139c8ebb", + "rev": "e44898b2f22f6cac71a8a8f687d1b2ff52d12a79", "type": "github" }, "original": { @@ -79,17 +79,17 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1705069489, - "narHash": "sha256-kXk4DUZS5uEdowgcv5PWVJ1s37xZKPvhpD/CFNdWMbs=", + "lastModified": 1705293701, + "narHash": "sha256-yJs738MxB+RsxGETqESof15lRJ5za6s3NmhjbXt8Kt4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "391d29cb04fe2ca9a4744c10d6b8a7783f6b0f6d", + "rev": "715fac4e39626ca0d24481f3d1fdd54dbeeaced8", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "391d29cb04fe2ca9a4744c10d6b8a7783f6b0f6d", + "rev": "715fac4e39626ca0d24481f3d1fdd54dbeeaced8", "type": "github" } }, diff --git a/vendor/melange-compiler-libs b/vendor/melange-compiler-libs index 61653c608..3ef2115fb 160000 --- a/vendor/melange-compiler-libs +++ b/vendor/melange-compiler-libs @@ -1 +1 @@ -Subproject commit 61653c60844cd04af5733512768618fa9b05ec71 +Subproject commit 3ef2115fb156d28aad4564fbfdb3df125fe5ba4d From 033f8469bb88fde962a87d30726ff2f9907321c0 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 16 Jan 2024 20:03:33 -0800 Subject: [PATCH 7/8] chore: add changelog entry --- Changes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changes.md b/Changes.md index f102f68e9..8799ad9b3 100644 --- a/Changes.md +++ b/Changes.md @@ -139,6 +139,12 @@ Unreleased ([#1017](https://github.com/melange-re/melange/pull/1017)) - BREAKING(core): only allow strings in `{j| ... |j}` interpolation ([#1024](https://github.com/melange-re/melange/pull/1024)) +- BREAKING(ppx): use `[@u0]` for 0-arity uncurried application instead of `()` + ([#949](https://github.com/melange-re/melange/pull/949)) + - Melange wouldn't previously allow to invoke a 1-argument uncurried + function with `()` (`unit`). After this change, 0-arity functions must be + applied with `[@u0]`. Melange will issue an alert if old 0-arity + functions are applied with `[@u]` to help upgrade codebases. 2.2.0 2023-12-05 --------------- From 6b1e290c39f63fae8fefdd80ff0e4deed5eb8bb4 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Tue, 16 Jan 2024 20:35:58 -0800 Subject: [PATCH 8/8] fix instances of @u that should be @u0 --- jscomp/others/node_fs.ml | 2 +- jscomp/runtime/caml_external_polyfill.ml | 2 +- jscomp/stdlib/camlinternalLazy.ml | 12 +-- jscomp/test/demo.ml | 2 +- jscomp/test/demo_binding.ml | 2 +- jscomp/test/dist/jscomp/test/event_ffi.js | 6 +- .../dist/jscomp/test/exception_raise_test.js | 2 +- .../test/dist/jscomp/test/ffi_arity_test.js | 8 +- .../dist/jscomp/test/ocaml_parsetree_test.js | 98 +++++++++---------- .../test/dist/jscomp/test/ppx_apply_test.js | 2 +- .../test/dist/jscomp/test/raw_output_test.js | 4 +- .../jscomp/test/re_or_res/reactTestUtils.js | 4 +- .../dist/jscomp/test/uncurry_glob_test.js | 4 +- jscomp/test/gpr_2682_test.ml | 5 +- jscomp/test/http_types.ml | 2 +- jscomp/test/mt.ml | 8 +- jscomp/test/ocaml_typedtree_test.ml | 8 +- jscomp/test/pipe_send_readline.ml | 5 +- jscomp/test/test_http_server.ml | 6 +- jscomp/test/tramp_fib.ml | 8 +- jscomp/test/uncurry_test.ml | 6 +- jscomp/test/uncurry_test.mli | 4 +- 22 files changed, 97 insertions(+), 103 deletions(-) diff --git a/jscomp/others/node_fs.ml b/jscomp/others/node_fs.ml index d0640bea9..14ca2ed80 100644 --- a/jscomp/others/node_fs.ml +++ b/jscomp/others/node_fs.ml @@ -67,7 +67,7 @@ module Watch = struct f: ([ `change of (string (*eventType*) -> Node.string_buffer (* filename *) -> unit[@u]) - | `error of (unit -> unit[@u]) ] + | `error of (unit -> unit[@u0]) ] [@mel.string]) -> t = "on" [@@mel.send] diff --git a/jscomp/runtime/caml_external_polyfill.ml b/jscomp/runtime/caml_external_polyfill.ml index 7f668f78e..fd11ced25 100644 --- a/jscomp/runtime/caml_external_polyfill.ml +++ b/jscomp/runtime/caml_external_polyfill.ml @@ -28,7 +28,7 @@ open struct module Js = Js_internal end -let getGlobalThis : (unit -> global[@u]) = +let getGlobalThis : (unit -> global[@u0]) = [%raw {| function(){ if (typeof globalThis !== 'undefined') return globalThis; diff --git a/jscomp/stdlib/camlinternalLazy.ml b/jscomp/stdlib/camlinternalLazy.ml index 61edcf460..5414ee9ab 100644 --- a/jscomp/stdlib/camlinternalLazy.ml +++ b/jscomp/stdlib/camlinternalLazy.ml @@ -36,8 +36,8 @@ type 'a concrete = { exception Undefined -external fnToVal : (unit -> 'a [@u]) -> 'a = "%identity" -external valToFn : 'a -> (unit -> 'a [@u]) = "%identity" +external fnToVal : (unit -> 'a [@u0]) -> 'a = "%identity" +external valToFn : 'a -> (unit -> 'a [@u0]) = "%identity" external castToConcrete : 'a lazy_t -> 'a concrete = "%identity" external of_concrete : 'a concrete -> 'a lazy_t = "%identity" @@ -46,15 +46,15 @@ let is_val (type a ) (l : a lazy_t) : bool = -let forward_with_closure (type a ) (blk : a concrete) (closure : unit -> a [@u]) : a = - let result = closure () [@u] in +let forward_with_closure (type a ) (blk : a concrete) (closure : unit -> a [@u0]) : a = + let result = closure () [@u0] in (* do set_field BEFORE set_tag *) blk.value <- result; blk.tag<- true; result -let raise_undefined = (fun [@u] () -> raise Undefined) +let raise_undefined = (fun [@u0] () -> raise Undefined) (* Assume [blk] is a block with tag lazy *) let force_lazy_block (type a ) (blk : a t) : a = @@ -64,7 +64,7 @@ let force_lazy_block (type a ) (blk : a t) : a = try forward_with_closure blk closure with e -> - blk.value <- fnToVal (fun [@u] () -> raise e); + blk.value <- fnToVal (fun [@u0] () -> raise e); raise e diff --git a/jscomp/test/demo.ml b/jscomp/test/demo.ml index fee9fe057..e89e094ff 100644 --- a/jscomp/test/demo.ml +++ b/jscomp/test/demo.ml @@ -94,7 +94,7 @@ let ui_layout with e -> () end; let fmt v = toFixed v 2 in - set_interval (fun [@u] () -> + set_interval (fun [@u0] () -> grid##dataSource #= ( array_map data (fun [@u] {ticker; price } -> diff --git a/jscomp/test/demo_binding.ml b/jscomp/test/demo_binding.ml index 6dc23ce64..e77dbeec1 100644 --- a/jscomp/test/demo_binding.ml +++ b/jscomp/test/demo_binding.ml @@ -102,7 +102,7 @@ class type textArea = end[@u] -external set_interval : (unit -> unit [@u]) -> float -> unit = "setInterval" +external set_interval : (unit -> unit [@u0]) -> float -> unit = "setInterval" [@@mel.module "@runtime", "Runtime"] external toFixed : float -> int -> string = "toFixed" [@@mel.send] diff --git a/jscomp/test/dist/jscomp/test/event_ffi.js b/jscomp/test/dist/jscomp/test/event_ffi.js index a2847be6f..470821e5d 100644 --- a/jscomp/test/dist/jscomp/test/event_ffi.js +++ b/jscomp/test/dist/jscomp/test/event_ffi.js @@ -5,11 +5,11 @@ var Curry = require("melange.js/curry.js"); var Stdlib__List = require("melange/list.js"); function h0(x) { - return x(); + return x(undefined); } function h00(x) { - return x(); + return x(undefined); } function h1(x, y) { @@ -39,7 +39,7 @@ function ocaml_run(b, c) { return (x + b | 0) + c | 0; } -function a0() { +function a0(param) { console.log("hi"); } diff --git a/jscomp/test/dist/jscomp/test/exception_raise_test.js b/jscomp/test/dist/jscomp/test/exception_raise_test.js index 4e5222398..ccdf6afc7 100644 --- a/jscomp/test/dist/jscomp/test/exception_raise_test.js +++ b/jscomp/test/dist/jscomp/test/exception_raise_test.js @@ -196,7 +196,7 @@ function eq(loc, x, y) { try { ((()=>{throw 2} - )()); + )(undefined)); } catch (raw_e$2){ var e = Caml_js_exceptions.internalToOCamlException(raw_e$2); diff --git a/jscomp/test/dist/jscomp/test/ffi_arity_test.js b/jscomp/test/dist/jscomp/test/ffi_arity_test.js index 12b5daa48..8e9a99f42 100644 --- a/jscomp/test/dist/jscomp/test/ffi_arity_test.js +++ b/jscomp/test/dist/jscomp/test/ffi_arity_test.js @@ -40,7 +40,7 @@ var hh = [ return parseInt(x); }); -function u() { +function u(param) { return 3; } @@ -54,8 +54,8 @@ function fff(param) { vvv.contents = vvv.contents + 1 | 0; } -function g() { - return fff(undefined); +function g(param) { + fff(undefined); } function abc(x, y, z) { @@ -66,7 +66,7 @@ function abc(x, y, z) { var abc_u = abc; -g(); +g(undefined); Mt.from_pair_suites("Ffi_arity_test", { hd: [ diff --git a/jscomp/test/dist/jscomp/test/ocaml_parsetree_test.js b/jscomp/test/dist/jscomp/test/ocaml_parsetree_test.js index 93de45ca1..3c858e244 100644 --- a/jscomp/test/dist/jscomp/test/ocaml_parsetree_test.js +++ b/jscomp/test/dist/jscomp/test/ocaml_parsetree_test.js @@ -2042,56 +2042,56 @@ function from_pair_suites(name, suites) { var match = Stdlib__Array.to_list(Process.argv); if (match) { if (is_mocha(undefined)) { - describe(name, (function () { - return Stdlib__List.iter((function (param) { - var code = param[1]; - it(param[0], (function () { - var spec = Curry._1(code, undefined); - switch (spec.TAG | 0) { - case /* Eq */0 : - Assert.deepEqual(spec._0, spec._1); - return ; - case /* Neq */1 : - Assert.notDeepEqual(spec._0, spec._1); - return ; - case /* StrictEq */2 : - Assert.strictEqual(spec._0, spec._1); - return ; - case /* StrictNeq */3 : - Assert.notStrictEqual(spec._0, spec._1); - return ; - case /* Ok */4 : - Assert.ok(spec._0); - return ; - case /* Approx */5 : - var b = spec._1; - var a = spec._0; - if (!close_enough(undefined, a, b)) { - Assert.deepEqual(a, b); - return ; - } else { - return ; - } - case /* ApproxThreshold */6 : - var b$1 = spec._2; - var a$1 = spec._1; - if (!close_enough(spec._0, a$1, b$1)) { - Assert.deepEqual(a$1, b$1); - return ; - } else { - return ; - } - case /* ThrowAny */7 : - Assert.throws(spec._0); - return ; - case /* Fail */8 : - return assert_fail("failed"); - case /* FailWith */9 : - return assert_fail(spec._0); - + describe(name, (function (param) { + Stdlib__List.iter((function (param) { + var code = param[1]; + it(param[0], (function () { + var spec = Curry._1(code, undefined); + switch (spec.TAG | 0) { + case /* Eq */0 : + Assert.deepEqual(spec._0, spec._1); + return ; + case /* Neq */1 : + Assert.notDeepEqual(spec._0, spec._1); + return ; + case /* StrictEq */2 : + Assert.strictEqual(spec._0, spec._1); + return ; + case /* StrictNeq */3 : + Assert.notStrictEqual(spec._0, spec._1); + return ; + case /* Ok */4 : + Assert.ok(spec._0); + return ; + case /* Approx */5 : + var b = spec._1; + var a = spec._0; + if (!close_enough(undefined, a, b)) { + Assert.deepEqual(a, b); + return ; + } else { + return ; + } + case /* ApproxThreshold */6 : + var b$1 = spec._2; + var a$1 = spec._1; + if (!close_enough(spec._0, a$1, b$1)) { + Assert.deepEqual(a$1, b$1); + return ; + } else { + return ; } - })); - }), suites); + case /* ThrowAny */7 : + Assert.throws(spec._0); + return ; + case /* Fail */8 : + return assert_fail("failed"); + case /* FailWith */9 : + return assert_fail(spec._0); + + } + })); + }), suites); })); return ; } else { diff --git a/jscomp/test/dist/jscomp/test/ppx_apply_test.js b/jscomp/test/dist/jscomp/test/ppx_apply_test.js index 04694dcd3..ae7d13de8 100644 --- a/jscomp/test/dist/jscomp/test/ppx_apply_test.js +++ b/jscomp/test/dist/jscomp/test/ppx_apply_test.js @@ -30,7 +30,7 @@ function eq(loc, x, y) { var u = 3; -function nullary() { +function nullary(param) { return 3; } diff --git a/jscomp/test/dist/jscomp/test/raw_output_test.js b/jscomp/test/dist/jscomp/test/raw_output_test.js index be06893a9..a1974236a 100644 --- a/jscomp/test/dist/jscomp/test/raw_output_test.js +++ b/jscomp/test/dist/jscomp/test/raw_output_test.js @@ -10,9 +10,9 @@ function mk(fn) { (((_)=> console.log('should works') )(undefined)); -console.log((function () { +console.log((function (param) { return 1; - })()); + })(undefined)); exports.mk = mk; /* Not a pure module */ diff --git a/jscomp/test/dist/jscomp/test/re_or_res/reactTestUtils.js b/jscomp/test/dist/jscomp/test/re_or_res/reactTestUtils.js index 5c9543624..f3ff88ef9 100644 --- a/jscomp/test/dist/jscomp/test/re_or_res/reactTestUtils.js +++ b/jscomp/test/dist/jscomp/test/re_or_res/reactTestUtils.js @@ -8,14 +8,14 @@ var Curry = require("melange.js/curry.js"); var TestUtils = require("react-dom/test-utils"); function act(func) { - var reactFunc = function () { + var reactFunc = function (param) { Curry._1(func, undefined); }; TestUtils.act(reactFunc); } function actAsync(func) { - return TestUtils.act(function () { + return TestUtils.act(function (param) { return Curry._1(func, undefined); }); } diff --git a/jscomp/test/dist/jscomp/test/uncurry_glob_test.js b/jscomp/test/dist/jscomp/test/uncurry_glob_test.js index f8ce2fb1f..67cd5f61c 100644 --- a/jscomp/test/dist/jscomp/test/uncurry_glob_test.js +++ b/jscomp/test/dist/jscomp/test/uncurry_glob_test.js @@ -9,11 +9,11 @@ function M(U) { }; } -function f() { +function f(param) { return 3; } -f(); +f(undefined); function $plus$great(a, h) { return h(a); diff --git a/jscomp/test/gpr_2682_test.ml b/jscomp/test/gpr_2682_test.ml index 70523f9de..a09359f30 100644 --- a/jscomp/test/gpr_2682_test.ml +++ b/jscomp/test/gpr_2682_test.ml @@ -52,9 +52,8 @@ end ;; forIn [%obj{x = 3 ; y = 3}] (fun[@u] x -> Js.log x) -let f3 : unit -> bool [@u] = [%raw"()=>true"] +let f3 : unit -> bool [@u0] = [%raw"()=>true"] -let bbbb = f3 () [@u] +let bbbb = f3 () [@u0] ;;assert (bbbb) - diff --git a/jscomp/test/http_types.ml b/jscomp/test/http_types.ml index df1e866ec..fa49571ed 100644 --- a/jscomp/test/http_types.ml +++ b/jscomp/test/http_types.ml @@ -23,7 +23,7 @@ class type _resp = type resp = _resp Js.t class type _server = object - method listen : int -> string -> (unit -> unit [@u]) -> unit + method listen : int -> string -> (unit -> unit [@u0]) -> unit end[@u] type server = _server Js.t class type _http = diff --git a/jscomp/test/mt.ml b/jscomp/test/mt.ml index 22171618a..ce1f5ae37 100644 --- a/jscomp/test/mt.ml +++ b/jscomp/test/mt.ml @@ -1,4 +1,4 @@ -external describe : string -> (unit -> unit[@u]) -> unit = "describe" +external describe : string -> (unit -> unit[@u0]) -> unit = "describe" external it : string -> (unit -> unit[@mel.uncurry]) -> unit = "it" external it_promise : string -> (unit -> _ Js.Promise.t [@mel.uncurry]) -> unit = "it" @@ -37,7 +37,7 @@ let from_suites name (suite : (string * ('a -> unit)) list) = match Array.to_list Node.Process.process##argv with | _cmd :: _ -> if is_mocha () then - describe name (fun [@u] () -> + describe name (fun [@u0] () -> List.iter (fun (name, code) -> it name code) suite) | _ -> () @@ -96,7 +96,7 @@ let from_pair_suites name (suites : pair_suites) = match Array.to_list Node.Process.process##argv with | _cmd :: _ -> if is_mocha () then - describe name (fun [@u] () -> + describe name (fun [@u0] () -> suites |> List.iter (fun (name, code) -> it name (fun _ -> @@ -111,7 +111,7 @@ let from_promise_suites name (suites : (string * _ Js.Promise.t ) list) = match Array.to_list Node.Process.process##argv with | _cmd :: _ -> if is_mocha () then - describe name (fun [@u] () -> + describe name (fun [@u0] () -> suites |> List.iter (fun (name, code) -> it_promise name (fun _ -> diff --git a/jscomp/test/ocaml_typedtree_test.ml b/jscomp/test/ocaml_typedtree_test.ml index be366f210..a288d5707 100644 --- a/jscomp/test/ocaml_typedtree_test.ml +++ b/jscomp/test/ocaml_typedtree_test.ml @@ -11621,7 +11621,7 @@ end = struct -external describe : string -> (unit -> unit[@u]) -> unit = "describe" +external describe : string -> (unit -> unit[@u0]) -> unit = "describe" external it : string -> (unit -> unit[@mel.uncurry]) -> unit = "it" @@ -11677,7 +11677,7 @@ let from_suites name (suite : (string * ('a -> unit)) list) = match Array.to_list Node.Process.process##argv with | cmd :: _ -> if is_mocha () then - describe name (fun [@u] () -> + describe name (fun [@u0] () -> List.iter (fun (name, code) -> it name code) suite) | _ -> () @@ -11736,7 +11736,7 @@ let from_pair_suites name (suites : pair_suites) = match Array.to_list Node.Process.process##argv with | cmd :: _ -> if is_mocha () then - describe name (fun [@u] () -> + describe name (fun [@u0] () -> suites |> List.iter (fun (name, code) -> it name (fun _ -> @@ -11751,7 +11751,7 @@ let from_promise_suites name (suites : (string * _ Js.Promise.t ) list) = match Array.to_list Node.Process.process##argv with | cmd :: _ -> if is_mocha () then - describe name (fun [@u] () -> + describe name (fun [@u0] () -> suites |> List.iter (fun (name, code) -> it_promise name (fun _ -> diff --git a/jscomp/test/pipe_send_readline.ml b/jscomp/test/pipe_send_readline.ml index 2295841ef..1bf2f4915 100644 --- a/jscomp/test/pipe_send_readline.ml +++ b/jscomp/test/pipe_send_readline.ml @@ -1,18 +1,17 @@ - (* should give a warning on unused attribute.. [@@mel.xx] *) type readline external on : ([ `line of (string -> unit [@u]) - | `close of (unit -> unit [@u])] + | `close of (unit -> unit [@u0])] [@mel.string]) -> 'self = "on" [@@mel.send.pipe:readline as 'self] let u rl = rl |> on (`line (fun [@u] x -> Js.log x )) - |> on (`close (fun [@u] () -> Js.log "finished")) + |> on (`close (fun [@u0] () -> Js.log "finished")) diff --git a/jscomp/test/test_http_server.ml b/jscomp/test/test_http_server.ml index 485eee4f0..7903e93e6 100644 --- a/jscomp/test/test_http_server.ml +++ b/jscomp/test/test_http_server.ml @@ -1,6 +1,3 @@ - - - let port = 3000 let hostname = "127.0.0.1" let create_server http = @@ -9,11 +6,10 @@ let create_server http = resp##setHeader "Content-Type" "text/plain"; resp##_end "Hello world\n" end in - server##listen port hostname begin fun [@u] () -> + server##listen port hostname begin fun [@u0] () -> Js.log ("Server running at http://"^ hostname ^ ":" ^ string_of_int port ^ "/") end let () = create_server Http_types.http - diff --git a/jscomp/test/tramp_fib.ml b/jscomp/test/tramp_fib.ml index 05d83dfb5..a0b187589 100644 --- a/jscomp/test/tramp_fib.ml +++ b/jscomp/test/tramp_fib.ml @@ -5,7 +5,7 @@ let test_id = ref 0 let eq loc x y = Mt.eq_suites ~test_id ~suites loc x y -type 'a bounce = Continue of 'a | Suspend of (unit -> 'a bounce [@u]) +type 'a bounce = Continue of 'a | Suspend of (unit -> 'a bounce [@u0]) (* https://eli.thegreenplace.net/2017/on-recursion-continuations-and-trampolines/ *) (* http://gallium.inria.fr/seminaires/transparents/20141027.Frederic.Bour.pdf *) (* http://www.usrsb.in/blog/blog/2012/08/12/bouncing-pythons-generators-with-a-trampoline/ *) @@ -17,7 +17,7 @@ let rec fib n k = (* Suspend (fun [@u]() -> k (Continue 1 ) [@u]) *) k 1 [@u] | _ -> - Suspend (fun [@u] () -> + Suspend (fun [@u0] () -> fib (n-1) (fun [@u] v0 -> fib (n-2) (fun [@u] v1 -> k (v0 + v1) [@u] @@ -37,7 +37,7 @@ let u = fib 10 (fun [@u] x -> Continue x) let rec iter (bounce : 'a bounce) : 'a = match bounce with | Continue v -> v - | Suspend f -> iter (f () [@u]) + | Suspend f -> iter (f () [@u0]) (* first it needs to be tailcall *) @@ -45,7 +45,7 @@ let rec isEven n = match n with | 0 -> Continue true | 1 -> Continue false - | _ -> Suspend (fun [@u] () -> isOdd (n - 1)) + | _ -> Suspend (fun [@u0] () -> isOdd (n - 1)) and isOdd n = match n with | 0 -> Continue false diff --git a/jscomp/test/uncurry_test.ml b/jscomp/test/uncurry_test.ml index c514a5552..812c61166 100644 --- a/jscomp/test/uncurry_test.ml +++ b/jscomp/test/uncurry_test.ml @@ -1,6 +1,6 @@ type ('a0, 'a1) t = ('a0 -> 'a1 [@u]) -let f0 = fun [@u] () -> 0 +let f0 = fun [@u0] () -> 0 let f1 = fun [@u] a0 -> a0 let f2 = fun [@u] a0 a1 -> (a0,a1) let f3= fun [@u]a0 a1 a2 -> ( a0,a1,a2) @@ -25,7 +25,7 @@ let f21= fun [@u]a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a let f22= fun [@u]a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21 -> ( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21) (* let f23= fun [@u]a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21 a22 -> ( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21) *) (* TODO: better errror message than Unbound record field Js.Fn.I_23 *) -;; f0 () [@u] |. Js.log +;; f0 () [@u0] |. Js.log ;; f1 0 [@u] |. Js.log ;; f2 0 1 [@u] |. Js.log @@ -50,4 +50,4 @@ let f22= fun [@u]a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a ;; f21 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [@u] |. Js.log ;; f22 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [@u] |. Js.log -let rec xx = fun [@u] () -> xx () [@u] +let rec xx = fun [@u0] () -> xx () [@u0] diff --git a/jscomp/test/uncurry_test.mli b/jscomp/test/uncurry_test.mli index 97493544d..3246e4303 100644 --- a/jscomp/test/uncurry_test.mli +++ b/jscomp/test/uncurry_test.mli @@ -1,5 +1,5 @@ type ('a0, 'a1) t = ('a0 -> 'a1 [@u]) -val f0 : (unit -> int [@u]) +val f0 : (unit -> int [@u0]) val f1 : ('a -> 'a [@u]) val f2 : ('a -> 'b -> 'a * 'b [@u]) val f3 : ('a -> 'b -> 'c -> 'a * 'b * 'c [@u]) @@ -265,4 +265,4 @@ val f22 : 'p * 'q * 'r * 's * 't * 'u * 'v [@u]) -val xx : unit -> 'a [@u] +val xx : unit -> 'a [@u0]