diff --git a/.github/workflows/opam-build.yml b/.github/workflows/opam-build.yml index e8826404a2..618aa8d8b2 100644 --- a/.github/workflows/opam-build.yml +++ b/.github/workflows/opam-build.yml @@ -72,7 +72,8 @@ jobs: - name: Install all deps working-directory: melange-opam-template run: | - opam install -y reason-react + opam pin add reason-react-ppx.dev git+https://github.com/reasonml/reason-react.git#c97615d62311f32c2dbb1e5d159c06e147ca7545 -y + opam pin add reason-react.dev git+https://github.com/reasonml/reason-react.git#c97615d62311f32c2dbb1e5d159c06e147ca7545 -y npm install - name: Build basic template diff --git a/dune-project b/dune-project index 00db48861a..f0f5cfd73c 100644 --- a/dune-project +++ b/dune-project @@ -42,10 +42,7 @@ (ounit :with-test) (reason (and :dev :with-test)) - (ppxlib - (and - (>= "0.30.0") - (< "0.36.0"))) + (ppxlib (>= "0.36.0")) (menhir (>= 20201214)) (reason-react-ppx diff --git a/flake.nix b/flake.nix index 3bd081ff83..0fa8c41201 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,51 @@ forAllSystems = f: nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (system: let pkgs = nixpkgs.legacyPackages.${system}.extend (self: super: { - ocamlPackages = super.ocaml-ng.ocamlPackages_5_3; + ocamlPackages = super.ocaml-ng.ocamlPackages_5_3.overrideScope (oself: osuper: { + js_of_ocaml-compiler = osuper.js_of_ocaml-compiler.overrideAttrs (_: { + src = super.fetchFromGitHub { + owner = "ocsigen"; + repo = "js_of_ocaml"; + rev = "c76316cb4f07fc0b1ffc46805fd350d4be77e0dc"; + hash = "sha256-9aYCYQ+wt5INgm54COeUcbAAqUfpWruLh1TyRDy0Fp0="; + }; + }); + sedlex = osuper.sedlex.overrideAttrs (_: { + src = super.fetchFromGitHub { + owner = "ocaml-community"; + repo = "sedlex"; + rev = "4dbaf572ed52281140be924a2c16fa4f287d88f0"; + hash = "sha256-pRZ/GRTpBIa8ZcKdmCo1pmAHR3tJrIfNqU4IreEhO7g="; + }; + }); + ppxlib = osuper.ppxlib.overrideAttrs (_: { + src = builtins.fetchurl { + url = "https://github.com/ocaml-ppx/ppxlib/releases/download/0.36.0/ppxlib-0.36.0.tbz"; + sha256 = "0d54j19vi1khzmw0ffngs8xzjjq07n20q49h85hhhcf52k71pfjs"; + }; + }); + reason = osuper.reason.overrideAttrs (_: { + src = super.fetchFromGitHub { + owner = "reasonml"; + repo = "reason"; + rev = "0b2f1aa14f5722a07a63bedb608c381d218f24cf"; + hash = "sha256-rtFEhEdNwHgRFAk9S7xx9MKvn9/gtTrIcVZp6d45Fxk="; + }; + patches = [ ]; + doCheck = false; + }); + reason-react-ppx = osuper.reason-react-ppx.overrideAttrs (_: { + src = super.fetchFromGitHub { + owner = "reasonml"; + repo = "reason-react"; + rev = "c97615d62311f32c2dbb1e5d159c06e147ca7545"; + hash = "sha256-dZZyjc+G2erukLXsICExaKwWqs6eqGLrkHTouoe8k40="; + }; + }); + pp = osuper.pp.overrideAttrs (o: { + doCheck = false; + }); + }); }); in f pkgs); diff --git a/jscomp/core/gen/dune b/jscomp/core/gen/dune index 48587b76d0..781b65e6b1 100644 --- a/jscomp/core/gen/dune +++ b/jscomp/core/gen/dune @@ -1,6 +1,6 @@ (executable (name gen_traversal) - (libraries ppxlib.ast cmdliner) + (libraries ppxlib.ast ppxlib cmdliner) (flags :standard -open StdLabels -open Ppxlib_ast) (preprocess (pps ppxlib.metaquot))) diff --git a/jscomp/melstd/gen/dune b/jscomp/melstd/gen/dune index 6d26b5325b..a06bdb8733 100644 --- a/jscomp/melstd/gen/dune +++ b/jscomp/melstd/gen/dune @@ -2,4 +2,4 @@ (name build_reserved) (preprocess (pps ppxlib.metaquot)) - (libraries ppxlib.ast)) + (libraries ppxlib ppxlib.ast)) diff --git a/melange-playground.opam b/melange-playground.opam index d5ed90eed5..4c647dbf57 100644 --- a/melange-playground.opam +++ b/melange-playground.opam @@ -30,3 +30,11 @@ build: [ ] ] dev-repo: "git+https://github.com/melange-re/melange.git" +pin-depends: [ + [ "js_of_ocaml-compiler.dev" "git+https://github.com/ocsigen/js_of_ocaml.git#c76316cb4f07fc0b1ffc46805fd350d4be77e0dc" ] + [ "js_of_ocaml.dev" "git+https://github.com/ocsigen/js_of_ocaml.git#c76316cb4f07fc0b1ffc46805fd350d4be77e0dc" ] + [ "sedlex.dev" "git+https://github.com/ocaml-community/sedlex.git#4dbaf572ed52281140be924a2c16fa4f287d88f0"] + [ "reason.dev" "git+https://github.com/reasonml/reason.git" ] + [ "reason-react-ppx.dev" "git+https://github.com/reasonml/reason-react.git#c97615d62311f32c2dbb1e5d159c06e147ca7545"] +] + diff --git a/melange-playground.opam.template b/melange-playground.opam.template new file mode 100644 index 0000000000..dbeb49d1ec --- /dev/null +++ b/melange-playground.opam.template @@ -0,0 +1,8 @@ +pin-depends: [ + [ "js_of_ocaml-compiler.dev" "git+https://github.com/ocsigen/js_of_ocaml.git#c76316cb4f07fc0b1ffc46805fd350d4be77e0dc" ] + [ "js_of_ocaml.dev" "git+https://github.com/ocsigen/js_of_ocaml.git#c76316cb4f07fc0b1ffc46805fd350d4be77e0dc" ] + [ "sedlex.dev" "git+https://github.com/ocaml-community/sedlex.git#4dbaf572ed52281140be924a2c16fa4f287d88f0"] + [ "reason.dev" "git+https://github.com/reasonml/reason.git" ] + [ "reason-react-ppx.dev" "git+https://github.com/reasonml/reason-react.git#c97615d62311f32c2dbb1e5d159c06e147ca7545"] +] + diff --git a/melange.opam b/melange.opam index 1a83b3e9cd..a96b361d05 100644 --- a/melange.opam +++ b/melange.opam @@ -14,7 +14,7 @@ depends: [ "cppo" {build} "ounit" {with-test} "reason" {dev & with-test} - "ppxlib" {>= "0.30.0" & < "0.36.0"} + "ppxlib" {>= "0.36.0"} "menhir" {>= "20201214"} "reason-react-ppx" {with-test & post} "merlin" {with-test} @@ -35,3 +35,7 @@ build: [ ] ] dev-repo: "git+https://github.com/melange-re/melange.git" +pin-depends: [ + [ "reason.dev" "git+https://github.com/reasonml/reason.git" ] + [ "reason-react-ppx.dev" "git+https://github.com/reasonml/reason-react.git#c97615d62311f32c2dbb1e5d159c06e147ca7545"] +] diff --git a/melange.opam.template b/melange.opam.template new file mode 100644 index 0000000000..0b72685b2d --- /dev/null +++ b/melange.opam.template @@ -0,0 +1,4 @@ +pin-depends: [ + [ "reason.dev" "git+https://github.com/reasonml/reason.git" ] + [ "reason-react-ppx.dev" "git+https://github.com/reasonml/reason-react.git#c97615d62311f32c2dbb1e5d159c06e147ca7545"] +] diff --git a/ppx/ast_derive/ast_derive_projector.ml b/ppx/ast_derive/ast_derive_projector.ml index fefb8b3791..fac398a504 100644 --- a/ppx/ast_derive/ast_derive_projector.ml +++ b/ppx/ast_derive/ast_derive_projector.ml @@ -99,7 +99,9 @@ let derive_structure tdcls = in List.fold_right ~f:(fun var b -> - Exp.fun_ Nolabel None (Pat.var { loc; txt = var }) b) + Ast_builder.Default.pexp_fun ~loc Nolabel None + (Pat.var { loc; txt = var }) + b) vars ~init:exp); ]) constructor_declarations diff --git a/ppx/ast_object.ml b/ppx/ast_object.ml index 8e047ec4e6..711030ee59 100644 --- a/ppx/ast_object.ml +++ b/ppx/ast_object.ml @@ -128,11 +128,16 @@ let ocaml_object_as_js_object = match x.pcf_desc with | Pcf_method (label, public_flag, Cfk_concrete (Fresh, e)) -> ( match e.pexp_desc with - | Pexp_poly ({ pexp_desc = Pexp_fun (lbl, _, pat, e); _ }, None) - -> + | Pexp_poly + ( { pexp_desc = Pexp_function (_, _, Pfunction_cases _); _ }, + None ) -> + assert false + | Pexp_poly + ( { pexp_desc = Pexp_function (args, _, Pfunction_body e); _ }, + None ) -> let method_type = - Ast_typ_uncurry.generate_arg_type x.pcf_loc mapper label.txt - lbl pat e + Ast_typ_uncurry.generate_arg_type ~loc:x.pcf_loc mapper + label.txt args e in ( Of.tag label method_type :: label_attr_types, if public_flag = Public then @@ -180,24 +185,55 @@ let ocaml_object_as_js_object = | Pcf_method (label, _public_flag, Cfk_concrete (Fresh, e)) -> ( match e.pexp_desc with | Pexp_poly - (({ pexp_desc = Pexp_fun (ll, None, pat, e); _ } as f), None) - -> + ( { pexp_desc = Pexp_function (_, _, Pfunction_cases _); _ }, + None ) -> + assert false + | Pexp_poly + ( ({ + pexp_desc = Pexp_function (params, _, Pfunction_body e); + _; + } as f), + None ) -> let alias_type = if aliased then None else Some internal_obj_type in let label_type = Ast_typ_uncurry.generate_method_type ?alias_type x.pcf_loc - mapper label.txt ll pat e + mapper label.txt params e in ( label :: labels, label_type :: label_types, { f with pexp_desc = - (let f = Ast_pat.is_unit_cont pat ~yes:e ~no:f in - Ast_uncurry_gen.to_method_callback loc mapper Nolabel - self_pat f) - (* the first argument is this*); + (let f = + let first_arg = + match + List.find_opt + ~f:(function + | { pparam_desc = Pparam_val _; _ } -> true + | { pparam_desc = Pparam_newtype _; _ } -> + false) + params + with + | Some { pparam_desc = Pparam_val (_, _, pat); _ } + -> + pat + | Some { pparam_desc = Pparam_newtype _; _ } | None + -> + assert false + in + if Ast_pat.is_unit first_arg then e else f + in + Ast_uncurry_gen.to_method_callback ~loc mapper + [ + { + pparam_desc = Pparam_val (Nolabel, None, self_pat); + pparam_loc = x.pcf_loc; + }; + ] + f) + (* the first argument is this *); } :: exprs, true ) diff --git a/ppx/ast_pat.ml b/ppx/ast_pat.ml index 938d0c5fc2..b92863d998 100644 --- a/ppx/ast_pat.ml +++ b/ppx/ast_pat.ml @@ -24,25 +24,64 @@ open Import -let is_unit_cont ~yes ~no p = +let is_unit p = match p with - | { ppat_desc = Ppat_construct ({ txt = Lident "()"; _ }, None); _ } -> yes - | _ -> no + | { ppat_desc = Ppat_construct ({ txt = Lident "()"; _ }, None); _ } -> true + | _ -> false (** [arity_of_fun pat e] tells the arity of expression [fun pat -> e] *) -let arity_of_fun pat e = - let rec aux e = - match e.pexp_desc with - | Pexp_fun (_, _, _, e) -> 1 + aux e (*FIXME error on optional*) - | _ -> 0 +let arity_of_fun = + let rec arity_of_fun = + let arity_aux params ~init = + (* FIXME error on optional *) + List.fold_left ~init + ~f:(fun acc param -> + match param with + | { pparam_desc = Pparam_newtype _; _ } -> acc + | { + pparam_desc = + Pparam_val + ( _, + _, + { + ppat_desc = Ppat_construct ({ txt = Lident "()"; _ }, None); + _; + } ); + _; + } + when acc = 0 -> + acc + | { pparam_desc = Pparam_val (_, _, _); _ } -> acc + 1) + params + in + fun acc params body -> + let base = arity_aux params ~init:acc in + match body with + | { pexp_desc = Pexp_function (params', _, Pfunction_body body); _ } -> + arity_of_fun base params' body + | _ -> base in - is_unit_cont ~yes:0 ~no:1 pat + aux e + fun params body -> arity_of_fun 0 params body -let rec labels_of_fun e = - match e.pexp_desc with - | Pexp_fun (l, _, _, e) -> l :: labels_of_fun e - | _ -> [] +let labels_of_fun = + let rec labels_of_fun = + let lbls_aux params ~init = + List.fold_left ~init + ~f:(fun acc param -> + match param with + | { pparam_desc = Pparam_newtype _; _ } -> acc + | { pparam_desc = Pparam_val (l, _, _); _ } -> l :: acc) + params + in + fun acc params body -> + let base = lbls_aux params ~init:acc in + match body with + | { pexp_desc = Pexp_function (params', _, Pfunction_body body); _ } -> + labels_of_fun base params' body + | _ -> List.rev base + in + fun params body -> labels_of_fun [] params body let rec is_single_variable_pattern_conservative p = match p.ppat_desc with diff --git a/ppx/ast_pat.mli b/ppx/ast_pat.mli index f795445c5b..c7f059a7c9 100644 --- a/ppx/ast_pat.mli +++ b/ppx/ast_pat.mli @@ -24,11 +24,11 @@ open Import -val is_unit_cont : yes:'a -> no:'a -> pattern -> 'a +val is_unit : pattern -> bool -val arity_of_fun : pattern -> expression -> int +val arity_of_fun : function_param list -> expression -> int (** [arity_of_fun pat e] tells the arity of expression [fun pat -> e]*) -val labels_of_fun : expression -> Asttypes.arg_label list +val labels_of_fun : function_param list -> expression -> Asttypes.arg_label list val is_single_variable_pattern_conservative : pattern -> bool diff --git a/ppx/ast_tuple_pattern_flatten.ml b/ppx/ast_tuple_pattern_flatten.ml index 35e3d3378e..fd164598a7 100644 --- a/ppx/ast_tuple_pattern_flatten.ml +++ b/ppx/ast_tuple_pattern_flatten.ml @@ -48,6 +48,7 @@ let flatten_tuple_pattern_vb (self : Ast_traverse.map) (vb : value_binding) let pvb_pat = self#pattern vb.pvb_pat in let pvb_expr = self#expression vb.pvb_expr in let pvb_attributes = self#attributes vb.pvb_attributes in + let pvb_constraint = Option.map self#value_constraint vb.pvb_constraint in match (pvb_pat.ppat_desc, pvb_expr.pexp_desc) with | Ppat_tuple xs, _ when List.for_all ~f:is_simple_pattern xs -> ( match Ast_open_cxt.destruct_open_tuple pvb_expr [] with @@ -62,10 +63,19 @@ let flatten_tuple_pattern_vb (self : Ast_traverse.map) (vb : value_binding) pvb_expr = Ast_open_cxt.restore_exp exp wholes; pvb_attributes; pvb_loc = vb.pvb_loc; + pvb_constraint; } :: acc) xs es ~init:acc - | _ -> { pvb_pat; pvb_expr; pvb_loc = vb.pvb_loc; pvb_attributes } :: acc) + | _ -> + { + pvb_pat; + pvb_expr; + pvb_loc = vb.pvb_loc; + pvb_attributes; + pvb_constraint; + } + :: acc) | Ppat_record (lid_pats, _), Pexp_pack { pmod_desc = Pmod_ident id; _ } -> List.map ~f:(fun (lid, pat) -> @@ -78,13 +88,22 @@ let flatten_tuple_pattern_vb (self : Ast_traverse.map) (vb : value_binding) { lid with txt = Ldot (id.txt, s) }; pvb_attributes = []; pvb_loc = pat.ppat_loc; + pvb_constraint; } | _ -> Location.raise_errorf ~loc:lid.loc "Pattern matching on modules requires simple labels") lid_pats @ acc - | _ -> { pvb_pat; pvb_expr; pvb_loc = vb.pvb_loc; pvb_attributes } :: acc + | _ -> + { + pvb_pat; + pvb_expr; + pvb_loc = vb.pvb_loc; + pvb_attributes; + pvb_constraint; + } + :: acc (* XXX(anmonteiro): this one is a little brittle. Because it might introduce new value bindings, it must be called at every AST node that has a diff --git a/ppx/ast_typ_uncurry.ml b/ppx/ast_typ_uncurry.ml index 73560f8b70..5f8a767d77 100644 --- a/ppx/ast_typ_uncurry.ml +++ b/ppx/ast_typ_uncurry.ml @@ -50,34 +50,31 @@ let to_method_callback_type loc (mapper : Ast_traverse.map) let self_type_lit = "self_type" let generate_method_type loc (mapper : Ast_traverse.map) ?alias_type method_name - lbl pat e : core_type = - let arity = Ast_pat.arity_of_fun pat e in + params body : core_type = let result = Typ.var ~loc method_name in - let self_type loc = Typ.var ~loc self_type_lit in - let self_type = - let v = self_type loc in match alias_type with - | None -> v - | Some ty -> Typ.alias ~loc ty self_type_lit + | None -> Typ.var ~loc self_type_lit + | Some ty -> Typ.alias ~loc ty { loc; txt = self_type_lit } in - if arity = 0 then to_method_callback_type loc mapper Nolabel self_type result - else - let tyvars = - List.mapi - ~f:(fun i x -> (x, Typ.var ~loc (method_name ^ string_of_int i))) - (lbl :: Ast_pat.labels_of_fun e) - in - match tyvars with - | (label, x) :: rest -> - let method_rest = - List.fold_right - ~f:(fun (label, v) acc -> Typ.arrow ~loc label v acc) - rest ~init:result - in - to_method_callback_type loc mapper Nolabel self_type - (Typ.arrow ~loc label x method_rest) - | _ -> assert false + match Ast_pat.arity_of_fun params body with + | 0 -> to_method_callback_type loc mapper Nolabel self_type result + | _n -> ( + let tyvars = + List.mapi + ~f:(fun i x -> (x, Typ.var ~loc (method_name ^ string_of_int i))) + (Ast_pat.labels_of_fun params body) + in + match tyvars with + | (label, x) :: rest -> + let method_rest = + List.fold_right + ~f:(fun (label, v) acc -> Typ.arrow ~loc label v acc) + rest ~init:result + in + to_method_callback_type loc mapper Nolabel self_type + (Typ.arrow ~loc label x method_rest) + | _ -> assert false) let to_method_type loc (mapper : Ast_traverse.map) (label : Asttypes.arg_label) (first_arg : core_type) (typ : core_type) = @@ -94,16 +91,16 @@ let to_method_type loc (mapper : Ast_traverse.map) (label : Asttypes.arg_label) [ meth_type ] | None -> assert false -let generate_arg_type loc (mapper : Ast_traverse.map) method_name label pat body - : core_type = - let arity = Ast_pat.arity_of_fun pat body in +let generate_arg_type ~loc (mapper : Ast_traverse.map) method_name params body : + core_type = + let arity = Ast_pat.arity_of_fun params body in let result = Typ.var ~loc method_name in if arity = 0 then to_method_type loc mapper Nolabel [%type: unit] result else let tyvars = List.mapi ~f:(fun i x -> (x, Typ.var ~loc (method_name ^ string_of_int i))) - (label :: Ast_pat.labels_of_fun body) + (Ast_pat.labels_of_fun params body) in match tyvars with | (label, x) :: rest -> diff --git a/ppx/ast_typ_uncurry.mli b/ppx/ast_typ_uncurry.mli index 980bc840e1..4b91546637 100644 --- a/ppx/ast_typ_uncurry.mli +++ b/ppx/ast_typ_uncurry.mli @@ -69,16 +69,14 @@ val generate_method_type : Ast_traverse.map -> ?alias_type:core_type -> string -> - Asttypes.arg_label -> - pattern -> + function_param list -> expression -> core_type val generate_arg_type : - Location.t -> + loc:Location.t -> Ast_traverse.map -> string -> - Asttypes.arg_label -> - pattern -> + function_param list -> expression -> core_type diff --git a/ppx/ast_uncurry_gen.ml b/ppx/ast_uncurry_gen.ml index a9175a8789..e8b8e46f09 100644 --- a/ppx/ast_uncurry_gen.ml +++ b/ppx/ast_uncurry_gen.ml @@ -23,77 +23,100 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) open Import -open Ast_helper + +let process_args ~loc self args ~init = + List.fold_left ~init + ~f:(fun acc param -> + match param with + | { pparam_desc = Pparam_newtype _; _ } -> acc + | { pparam_desc = Pparam_val (arg_label, _, arg); _ } -> + Error.optional_err ~loc arg_label; + (arg_label, self#pattern arg) :: acc) + args + +let rec aux ~loc self acc (body : expression) = + match Ast_attributes.process_attributes_rev body.pexp_attributes with + | Nothing, _ -> ( + match body.pexp_desc with + | Pexp_function (args, _, Pfunction_body body) -> + aux ~loc self (process_args ~loc self args ~init:acc) body + | _ -> (self#expression body, acc)) + | _, _ -> (self#expression body, acc) (* Handling `fun [@this]` used in `object [@u] end` *) -let to_method_callback loc (self : Ast_traverse.map) 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 - | Nothing, _ -> ( - match body.pexp_desc with - | Pexp_fun (arg_label, _, arg, body) -> - Error.optional_err ~loc arg_label; - aux ((arg_label, self#pattern arg) :: acc) body - | _ -> (self#expression body, acc)) - | _, _ -> (self#expression body, acc) +let to_method_callback = + fun ~loc (self : Ast_traverse.map) args body : expression_desc -> + let first_arg = + match + List.find_opt + ~f:(function + | { pparam_desc = Pparam_val _; _ } -> true + | { pparam_desc = Pparam_newtype _; _ } -> false) + args + with + | Some { pparam_desc = Pparam_val (_, _, pat); _ } -> self#pattern pat + | Some { pparam_desc = Pparam_newtype _; _ } | None -> assert false in - let first_arg = self#pattern pat in if not (Ast_pat.is_single_variable_pattern_conservative first_arg) then Error.err ~loc:first_arg.ppat_loc Mel_this_simple_pattern; - let result, rev_extra_args = aux [ (label, first_arg) ] body in + let result, rev_extra_args = + let rev_args = process_args ~loc self args ~init:[] in + aux ~loc self rev_args body + in let body = - List.fold_left - ~f:(fun e (label, p) -> Ast_helper.Exp.fun_ ~loc label None p e) - ~init:result rev_extra_args + Ast_helper.Exp.mk ~loc + (Pexp_function + ( List.rev_map + ~f:(fun (label, p) -> + { pparam_desc = Pparam_val (label, None, p); pparam_loc = loc }) + rev_extra_args, + None, + Pfunction_body result )) in let arity = List.length rev_extra_args in let arity_s = string_of_int arity in - Pexp_apply - ( Exp.ident ~loc { loc; txt = Ast_literal.unsafe_to_method }, - [ - ( Nolabel, - Exp.constraint_ ~loc - (Exp.record ~loc - [ ({ loc; txt = Ast_literal.hidden_field arity_s }, body) ] - None) - (Typ.constr ~loc - { - loc; - txt = Ldot (Ast_literal.js_meth_callback, "arity" ^ arity_s); - } - [ Typ.any ~loc () ]) ); - ] ) + Ast_helper.( + Pexp_apply + ( Exp.ident ~loc { loc; txt = Ast_literal.unsafe_to_method }, + [ + ( Nolabel, + Exp.constraint_ ~loc + (Exp.record ~loc + [ ({ loc; txt = Ast_literal.hidden_field arity_s }, body) ] + None) + (Typ.constr ~loc + { + loc; + txt = Ldot (Ast_literal.js_meth_callback, "arity" ^ arity_s); + } + [ Typ.any ~loc () ]) ); + ] )) -let to_uncurry_fn loc (self : Ast_traverse.map) (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 - | Nothing, _ -> ( - match body.pexp_desc with - | Pexp_fun (arg_label, _, arg, body) -> - Error.optional_err ~loc arg_label; - aux ((arg_label, self#pattern arg) :: acc) body - | _ -> (self#expression body, acc)) - | _, _ -> (self#expression body, acc) +let to_uncurry_fn ~loc (self : Ast_traverse.map) args body : expression_desc = + let result, rev_extra_args = + let rev_args = process_args ~loc self args ~init:[] in + aux ~loc self rev_args body in - let first_arg = self#pattern pat in - - let result, rev_extra_args = aux [ (label, first_arg) ] body in - let body = - List.fold_left - ~f:(fun e (label, p) -> Ast_helper.Exp.fun_ ~loc label None p e) - ~init:result rev_extra_args - in - let len = List.length rev_extra_args in let arity = + let len = List.length rev_extra_args in match rev_extra_args with - | [ (_, p) ] -> Ast_pat.is_unit_cont ~yes:0 ~no:len p + | [ (_, p) ] -> if Ast_pat.is_unit p then 0 else len | _ -> len in Error.err_large_arity ~loc arity; - let arity_s = string_of_int arity in + let body = + Ast_helper.Exp.mk ~loc + (Pexp_function + ( List.rev_map + ~f:(fun (label, p) -> + { pparam_desc = Pparam_val (label, None, p); pparam_loc = loc }) + rev_extra_args, + None, + Pfunction_body result )) + in Pexp_record - ([ ({ txt = Ldot (Ast_literal.js_fn, "I" ^ arity_s); loc }, body) ], None) + ( [ + ( { txt = Ldot (Ast_literal.js_fn, "I" ^ string_of_int arity); loc }, + body ); + ], + None ) diff --git a/ppx/ast_uncurry_gen.mli b/ppx/ast_uncurry_gen.mli index cbf138ad72..c3380d7146 100644 --- a/ppx/ast_uncurry_gen.mli +++ b/ppx/ast_uncurry_gen.mli @@ -25,10 +25,9 @@ open Import val to_uncurry_fn : - Location.t -> + loc:Location.t -> Ast_traverse.map -> - Asttypes.arg_label -> - pattern -> + function_param list -> expression -> expression_desc (** @@ -40,10 +39,9 @@ val to_uncurry_fn : *) val to_method_callback : - Location.t -> + loc:Location.t -> Ast_traverse.map -> - Asttypes.arg_label -> - pattern -> + function_param list -> expression -> expression_desc (** syntax: diff --git a/ppx/melange_ppx.cppo.ml b/ppx/melange_ppx.cppo.ml index 13b0011b59..2a6690cc9b 100644 --- a/ppx/melange_ppx.cppo.ml +++ b/ppx/melange_ppx.cppo.ml @@ -412,7 +412,7 @@ module Mapper = struct Ast_exp_apply.app_exp_mapper e (self, super#expression) fn args | Pexp_constant (Pconst_string (s, loc, Some delim)) -> String_interp.transform e s ~loc ~delim - | Pexp_function cases -> ( + | Pexp_function (_, _, Pfunction_cases (cases, _, _)) -> ( (* {[ function [@mel.open] | Not_found -> 0 | Invalid_argument -> 1 @@ -424,14 +424,14 @@ module Mapper = struct | true, pexp_attributes -> Ast_mel_open.convert_mel_error_function e.pexp_loc self pexp_attributes cases) - | Pexp_fun (label, _, pat, body) -> ( + | Pexp_function (args, _, Pfunction_body body) -> ( match Ast_attributes.process_attributes_rev e.pexp_attributes with | Nothing, _ -> super#expression e | Uncurry _, 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 ~loc:e.pexp_loc self args body; pexp_attributes; } | Method _, _ -> @@ -449,7 +449,7 @@ module Mapper = struct { e with pexp_desc = - Ast_uncurry_gen.to_method_callback e.pexp_loc self label pat + Ast_uncurry_gen.to_method_callback ~loc:e.pexp_loc self args body; pexp_attributes; }) @@ -581,6 +581,7 @@ module Mapper = struct pvb_expr; pvb_attributes; pvb_loc; + pvb_constraint }; ] ) -> ( let attrs, found = @@ -721,7 +722,7 @@ module Mapper = struct Pstr_value ( Nonrecursive, Ast_tuple_pattern_flatten.value_bindings_mapper self - [ { pvb_pat; pvb_expr; pvb_attributes; pvb_loc } ] ); + [ { pvb_pat; pvb_expr; pvb_attributes; pvb_loc; pvb_constraint } ] ); }) | Pstr_value (r, vbs) -> { diff --git a/test/blackbox-tests/melange-ppx-private.t b/test/blackbox-tests/melange-ppx-private.t index 8eb7c32490..e0bfec4dd1 100644 --- a/test/blackbox-tests/melange-ppx-private.t +++ b/test/blackbox-tests/melange-ppx-private.t @@ -21,6 +21,9 @@ Test to showcase errors when using %%private extensions with melange ppx > Webapi.Dom.MouseEvent.t -> Webapi.Dom.Event.t = "%identity"] > EOF $ dune build @mel - File "main.ml", lines 1-3: + File "main.ml", lines 1-3, characters 0-2: + 1 | (** + 2 | Hey + 3 | *) Error: Attributes not allowed here [1]