From 88cb36e725e49d3724863dd84d65a2cd3e887228 Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Wed, 8 Jan 2025 09:21:06 +0100 Subject: [PATCH 1/3] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afe24e625b..e0d4e2a751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,11 @@ - AST cleanup: Prepare for ast async cleanup: Refactor code for "@res.async" payload handling and clean up handling of type and term parameters, so that now each `=>` in a function definition corresponds to a function. https://github.com/rescript-lang/rescript/pull/7223 - AST: always put type parameters first in function definitions. https://github.com/rescript-lang/rescript/pull/7233 +#### :house: Internal + +- AST cleanup: Prepare for ast async cleanup: Refactor code for "@res.async" payload handling and clean up handling of type and term parameters, so that now each `=>` in a function definition corresponds to a function. https://github.com/rescript-lang/rescript/pull/7223 + + # 12.0.0-alpha.7 #### :bug: Bug fix From 362426d95833100fd45262751585811c27e0f97b Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Wed, 8 Jan 2025 16:14:57 +0100 Subject: [PATCH 2/3] Extend untyped and types ast with async attribute. --- CHANGELOG.md | 1 + compiler/frontend/ast_compatible.ml | 11 ++++- compiler/frontend/ast_compatible.mli | 1 + compiler/frontend/ast_uncurry_gen.ml | 10 ++--- compiler/frontend/bs_ast_mapper.ml | 5 ++- compiler/frontend/bs_builtin_ppx.ml | 3 +- compiler/ml/ast_async.ml | 17 +------ compiler/ml/ast_helper.ml | 4 +- compiler/ml/ast_helper.mli | 1 + compiler/ml/ast_mapper.ml | 5 ++- compiler/ml/ast_mapper_from0.ml | 3 +- compiler/ml/ast_mapper_to0.ml | 8 +++- compiler/ml/parsetree.ml | 1 + compiler/ml/pprintast.ml | 7 +-- compiler/ml/printast.ml | 3 +- compiler/ml/printtyped.ml | 4 +- compiler/ml/tast_mapper.ml | 5 ++- compiler/ml/translcore.ml | 13 +++--- compiler/ml/typecore.ml | 24 +++++++--- compiler/ml/typedtree.ml | 1 + compiler/ml/typedtree.mli | 1 + compiler/syntax/src/res_parsetree_viewer.ml | 8 ++-- .../expected/UncurriedByDefault.res.txt | 8 ++-- .../expressions/expected/async.res.txt | 45 +++++++++---------- tests/tools_tests/ppx/TestPpx.res | 7 +++ .../src/expected/TestPpx.res.jsout | 12 +++++ 26 files changed, 124 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0d4e2a751..a3936f7618 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - AST cleanup: Prepare for ast async cleanup: Refactor code for "@res.async" payload handling and clean up handling of type and term parameters, so that now each `=>` in a function definition corresponds to a function. https://github.com/rescript-lang/rescript/pull/7223 - AST: always put type parameters first in function definitions. https://github.com/rescript-lang/rescript/pull/7233 +- AST cleanup: Remove `@res.async` attribute from the internal representation, and add a flag to untyped and typed ASTs instead. https://github.com/rescript-lang/rescript/pull/7234 #### :house: Internal diff --git a/compiler/frontend/ast_compatible.ml b/compiler/frontend/ast_compatible.ml index 965c25151b..7dcd98418f 100644 --- a/compiler/frontend/ast_compatible.ml +++ b/compiler/frontend/ast_compatible.ml @@ -64,13 +64,20 @@ let app3 ?(loc = default_loc) ?(attrs = []) fn arg1 arg2 arg3 : expression = Pexp_apply (fn, [(Nolabel, arg1); (Nolabel, arg2); (Nolabel, arg3)]); } -let fun_ ?(loc = default_loc) ?(attrs = []) ~arity pat exp = +let fun_ ?(loc = default_loc) ?(attrs = []) ?(async = false) ~arity pat exp = { pexp_loc = loc; pexp_attributes = attrs; pexp_desc = Pexp_fun - {arg_label = Nolabel; default = None; lhs = pat; rhs = exp; arity}; + { + arg_label = Nolabel; + default = None; + lhs = pat; + rhs = exp; + arity; + async; + }; } let const_exp_string ?(loc = default_loc) ?(attrs = []) ?delimiter (s : string) diff --git a/compiler/frontend/ast_compatible.mli b/compiler/frontend/ast_compatible.mli index 185d14c93a..63201f9ef8 100644 --- a/compiler/frontend/ast_compatible.mli +++ b/compiler/frontend/ast_compatible.mli @@ -74,6 +74,7 @@ val apply_labels : val fun_ : ?loc:Location.t -> ?attrs:attrs -> + ?async:bool -> arity:int option -> pattern -> expression -> diff --git a/compiler/frontend/ast_uncurry_gen.ml b/compiler/frontend/ast_uncurry_gen.ml index eae466b275..c055f530a7 100644 --- a/compiler/frontend/ast_uncurry_gen.ml +++ b/compiler/frontend/ast_uncurry_gen.ml @@ -36,16 +36,16 @@ let to_method_callback loc (self : Bs_ast_mapper.mapper) label match Ast_attributes.process_attributes_rev body.pexp_attributes with | Nothing, attrs -> ( match body.pexp_desc with - | Pexp_fun {arg_label; lhs = arg; rhs = body} -> + | Pexp_fun {arg_label; lhs = arg; rhs = body; async} -> Bs_syntaxerr.optional_err loc arg_label; - aux ((arg_label, self.pat self arg, attrs) :: acc) body + aux ((arg_label, self.pat self arg, attrs, async) :: acc) body | _ -> (self.expr self body, acc)) | _, _ -> (self.expr self body, acc) in - let result, rev_extra_args = aux [(label, self_pat, [])] body in + let result, rev_extra_args = aux [(label, self_pat, [], false)] body in let body = - Ext_list.fold_left rev_extra_args result (fun e (label, p, attrs) -> - Ast_helper.Exp.fun_ ~loc ~attrs ~arity:None label None p e) + Ext_list.fold_left rev_extra_args result (fun e (label, p, attrs, async) -> + Ast_helper.Exp.fun_ ~loc ~attrs ~arity:None ~async label None p e) in let arity = List.length rev_extra_args in let arity_s = string_of_int arity in diff --git a/compiler/frontend/bs_ast_mapper.ml b/compiler/frontend/bs_ast_mapper.ml index 2c0cf55145..99742c849c 100644 --- a/compiler/frontend/bs_ast_mapper.ml +++ b/compiler/frontend/bs_ast_mapper.ml @@ -315,8 +315,9 @@ module E = struct sub vbs) (sub.expr sub e) (* #end *) - | Pexp_fun {arg_label = lab; default = def; lhs = p; rhs = e; arity} -> - fun_ ~loc ~attrs ~arity lab + | Pexp_fun {arg_label = lab; default = def; lhs = p; rhs = e; arity; async} + -> + fun_ ~loc ~attrs ~arity ~async lab (map_opt (sub.expr sub) def) (sub.pat sub p) (sub.expr sub e) | Pexp_apply (e, l) -> diff --git a/compiler/frontend/bs_builtin_ppx.ml b/compiler/frontend/bs_builtin_ppx.ml index 34d7835cec..054a9976a3 100644 --- a/compiler/frontend/bs_builtin_ppx.ml +++ b/compiler/frontend/bs_builtin_ppx.ml @@ -113,8 +113,7 @@ let expr_mapper ~async_context ~in_function_def (self : mapper) | Pexp_newtype (s, body) -> let res = self.expr self body in {e with pexp_desc = Pexp_newtype (s, res)} - | Pexp_fun {arg_label = label; lhs = pat; rhs = body} -> ( - let async = Ast_async.has_async_payload e.pexp_attributes in + | Pexp_fun {arg_label = label; lhs = pat; rhs = body; async} -> ( match Ast_attributes.process_attributes_rev e.pexp_attributes with | Nothing, _ -> (* Handle @async x => y => ... is in async context *) diff --git a/compiler/ml/ast_async.ml b/compiler/ml/ast_async.ml index f102660066..bd0b8f48ef 100644 --- a/compiler/ml/ast_async.ml +++ b/compiler/ml/ast_async.ml @@ -1,29 +1,16 @@ -let has_async_payload attrs = - Ext_list.exists attrs (fun ({Location.txt}, _) -> txt = "res.async") - let rec dig_async_payload_from_function (expr : Parsetree.expression) = match expr.pexp_desc with - | Pexp_fun _ -> has_async_payload expr.pexp_attributes + | Pexp_fun {async} -> async | Pexp_newtype (_, body) -> dig_async_payload_from_function body | _ -> false let add_async_attribute ~async (body : Parsetree.expression) = - let add (exp : Parsetree.expression) = - if has_async_payload exp.pexp_attributes then exp - else - { - exp with - pexp_attributes = - ({txt = "res.async"; loc = Location.none}, PStr []) - :: exp.pexp_attributes; - } - in if async then let rec add_to_fun (exp : Parsetree.expression) = match exp.pexp_desc with | Pexp_newtype (txt, e) -> {exp with pexp_desc = Pexp_newtype (txt, add_to_fun e)} - | Pexp_fun _ -> add exp + | Pexp_fun f -> {exp with pexp_desc = Pexp_fun {f with async}} | _ -> exp in add_to_fun body diff --git a/compiler/ml/ast_helper.ml b/compiler/ml/ast_helper.ml index b167349f9a..e9ddd8630b 100644 --- a/compiler/ml/ast_helper.ml +++ b/compiler/ml/ast_helper.ml @@ -151,9 +151,9 @@ module Exp = struct let ident ?loc ?attrs a = mk ?loc ?attrs (Pexp_ident a) let constant ?loc ?attrs a = mk ?loc ?attrs (Pexp_constant a) let let_ ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_let (a, b, c)) - let fun_ ?loc ?attrs ~arity a b c d = + let fun_ ?loc ?attrs ?(async = false) ~arity a b c d = mk ?loc ?attrs - (Pexp_fun {arg_label = a; default = b; lhs = c; rhs = d; arity}) + (Pexp_fun {arg_label = a; default = b; lhs = c; rhs = d; arity; async}) let apply ?loc ?attrs a b = mk ?loc ?attrs (Pexp_apply (a, b)) let match_ ?loc ?attrs a b = mk ?loc ?attrs (Pexp_match (a, b)) let try_ ?loc ?attrs a b = mk ?loc ?attrs (Pexp_try (a, b)) diff --git a/compiler/ml/ast_helper.mli b/compiler/ml/ast_helper.mli index a8969d2d08..99b5018583 100644 --- a/compiler/ml/ast_helper.mli +++ b/compiler/ml/ast_helper.mli @@ -138,6 +138,7 @@ module Exp : sig val fun_ : ?loc:loc -> ?attrs:attrs -> + ?async:bool -> arity:int option -> arg_label -> expression option -> diff --git a/compiler/ml/ast_mapper.ml b/compiler/ml/ast_mapper.ml index d2ab209b64..eb08e516f0 100644 --- a/compiler/ml/ast_mapper.ml +++ b/compiler/ml/ast_mapper.ml @@ -278,8 +278,9 @@ module E = struct | Pexp_constant x -> constant ~loc ~attrs x | Pexp_let (r, vbs, e) -> let_ ~loc ~attrs r (List.map (sub.value_binding sub) vbs) (sub.expr sub e) - | Pexp_fun {arg_label = lab; default = def; lhs = p; rhs = e; arity} -> - fun_ ~loc ~attrs ~arity lab + | Pexp_fun {arg_label = lab; default = def; lhs = p; rhs = e; arity; async} + -> + fun_ ~loc ~attrs ~arity ~async lab (map_opt (sub.expr sub) def) (sub.pat sub p) (sub.expr sub e) | Pexp_apply (e, l) -> diff --git a/compiler/ml/ast_mapper_from0.ml b/compiler/ml/ast_mapper_from0.ml index da1b3ace49..345354d616 100644 --- a/compiler/ml/ast_mapper_from0.ml +++ b/compiler/ml/ast_mapper_from0.ml @@ -304,7 +304,8 @@ module E = struct | Pexp_let (r, vbs, e) -> let_ ~loc ~attrs r (List.map (sub.value_binding sub) vbs) (sub.expr sub e) | Pexp_fun (lab, def, p, e) -> - fun_ ~loc ~attrs ~arity:None lab + let async = Ext_list.exists attrs (fun ({txt}, _) -> txt = "res.async") in + fun_ ~loc ~attrs ~async ~arity:None lab (map_opt (sub.expr sub) def) (sub.pat sub p) (sub.expr sub e) | Pexp_function _ -> assert false diff --git a/compiler/ml/ast_mapper_to0.ml b/compiler/ml/ast_mapper_to0.ml index 0064aa6afa..c23c292b9b 100644 --- a/compiler/ml/ast_mapper_to0.ml +++ b/compiler/ml/ast_mapper_to0.ml @@ -295,7 +295,13 @@ module E = struct | Pexp_constant x -> constant ~loc ~attrs (map_constant x) | Pexp_let (r, vbs, e) -> let_ ~loc ~attrs r (List.map (sub.value_binding sub) vbs) (sub.expr sub e) - | Pexp_fun {arg_label = lab; default = def; lhs = p; rhs = e; arity} -> ( + | Pexp_fun {arg_label = lab; default = def; lhs = p; rhs = e; arity; async} + -> ( + let attrs = + if async then + ({txt = "res.async"; loc = Location.none}, Pt.PStr []) :: attrs + else attrs + in let e = fun_ ~loc ~attrs lab (map_opt (sub.expr sub) def) diff --git a/compiler/ml/parsetree.ml b/compiler/ml/parsetree.ml index d4a02a6d56..d4a75b32e3 100644 --- a/compiler/ml/parsetree.ml +++ b/compiler/ml/parsetree.ml @@ -230,6 +230,7 @@ and expression_desc = lhs: pattern; rhs: expression; arity: arity; + async: bool; } (* fun P -> E1 (Simple, None) fun ~l:P -> E1 (Labelled l, None) diff --git a/compiler/ml/pprintast.ml b/compiler/ml/pprintast.ml index 838a29f24e..9826b3bc87 100644 --- a/compiler/ml/pprintast.ml +++ b/compiler/ml/pprintast.ml @@ -605,14 +605,15 @@ and expression ctxt f x = | (Pexp_let _ | Pexp_letmodule _ | Pexp_open _ | Pexp_letexception _) when ctxt.semi -> paren true (expression reset_ctxt) f x - | Pexp_fun {arg_label = l; default = e0; lhs = p; rhs = e; arity} -> + | Pexp_fun {arg_label = l; default = e0; lhs = p; rhs = e; arity; async} -> let arity_str = match arity with | None -> "" | Some arity -> "[arity:" ^ string_of_int arity ^ "]" in - pp f "@[<2>fun@;%s%a->@;%a@]" arity_str (label_exp ctxt) (l, e0, p) - (expression ctxt) e + let async_str = if async then "async " else "" in + pp f "@[<2>%sfun@;%s%a->@;%a@]" async_str arity_str (label_exp ctxt) + (l, e0, p) (expression ctxt) e | Pexp_match (e, l) -> pp f "@[@[@[<2>match %a@]@ with@]%a@]" (expression reset_ctxt) e (case_list ctxt) l diff --git a/compiler/ml/printast.ml b/compiler/ml/printast.ml index d71f798265..b521072bb8 100644 --- a/compiler/ml/printast.ml +++ b/compiler/ml/printast.ml @@ -238,8 +238,9 @@ and expression i ppf x = line i ppf "Pexp_let %a\n" fmt_rec_flag rf; list i value_binding ppf l; expression i ppf e - | Pexp_fun {arg_label = l; default = eo; lhs = p; rhs = e; arity} -> + | Pexp_fun {arg_label = l; default = eo; lhs = p; rhs = e; arity; async} -> line i ppf "Pexp_fun\n"; + let () = if async then line i ppf "async\n" in let () = match arity with | None -> () diff --git a/compiler/ml/printtyped.ml b/compiler/ml/printtyped.ml index af090ac79c..686caa4083 100644 --- a/compiler/ml/printtyped.ml +++ b/compiler/ml/printtyped.ml @@ -285,8 +285,10 @@ and expression i ppf x = line i ppf "Texp_let %a\n" fmt_rec_flag rf; list i value_binding ppf l; expression i ppf e - | Texp_function {arg_label = p; arity; param; case = case_; partial = _} -> + | Texp_function + {arg_label = p; arity; async; param; case = case_; partial = _} -> line i ppf "Texp_function\n"; + if async then line i ppf "async\n"; (match arity with | Some arity -> line i ppf "arity: %d\n" arity | None -> ()); diff --git a/compiler/ml/tast_mapper.ml b/compiler/ml/tast_mapper.ml index bce2002a35..24541f60e8 100644 --- a/compiler/ml/tast_mapper.ml +++ b/compiler/ml/tast_mapper.ml @@ -199,8 +199,9 @@ let expr sub x = | Texp_let (rec_flag, list, exp) -> let rec_flag, list = sub.value_bindings sub (rec_flag, list) in Texp_let (rec_flag, list, sub.expr sub exp) - | Texp_function {arg_label; arity; param; case; partial} -> - Texp_function {arg_label; arity; param; case = sub.case sub case; partial} + | Texp_function {arg_label; arity; param; case; partial; async} -> + Texp_function + {arg_label; arity; param; case = sub.case sub case; partial; async} | Texp_apply (exp, list) -> Texp_apply (sub.expr sub exp, List.map (tuple2 id (opt (sub.expr sub))) list) diff --git a/compiler/ml/translcore.ml b/compiler/ml/translcore.ml index 0ff4b76a28..73986b5d57 100644 --- a/compiler/ml/translcore.ml +++ b/compiler/ml/translcore.ml @@ -555,7 +555,8 @@ let rec push_defaults loc bindings case partial = c_lhs = pat; c_guard = None; c_rhs = - {exp_desc = Texp_function {arg_label; arity; param; case; partial}} as exp; + {exp_desc = Texp_function {arg_label; arity; param; case; partial; async}} + as exp; } -> let case = push_defaults exp.exp_loc bindings case partial in @@ -565,7 +566,8 @@ let rec push_defaults loc bindings case partial = c_rhs = { exp with - exp_desc = Texp_function {arg_label; arity; param; case; partial}; + exp_desc = + Texp_function {arg_label; arity; param; case; partial; async}; }; } | { @@ -671,8 +673,7 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = | Texp_constant cst -> Lconst (Const_base cst) | Texp_let (rec_flag, pat_expr_list, body) -> transl_let rec_flag pat_expr_list (transl_exp body) - | Texp_function {arg_label = _; arity; param; case; partial} -> ( - let async = Ast_async.has_async_payload e.exp_attributes in + | Texp_function {arg_label = _; arity; param; case; partial; async} -> ( let directive = match extract_directive_for_fn e with | None -> None @@ -1050,11 +1051,11 @@ and transl_function loc partial param case = param = param'; case; partial = partial'; + async; }; } as exp; } - when Parmatch.inactive ~partial pat - && not (Ast_async.has_async_payload exp.exp_attributes) -> + when Parmatch.inactive ~partial pat && not async -> let params, body, return_unit = transl_function exp.exp_loc partial' param' case in diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 5253cb557e..43d834a8e2 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -2364,7 +2364,14 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg = Rejected) env sexp exp_env = env; } | Pexp_fun - {arg_label = l; default = Some default; lhs = spat; rhs = sbody; arity} -> + { + arg_label = l; + default = Some default; + lhs = spat; + rhs = sbody; + arity; + async; + } -> assert (is_optional l); (* default allowed only with optional argument *) let open Ast_helper in @@ -2402,10 +2409,13 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg = Rejected) env sexp [Vb.mk spat smatch] sbody in - type_function ?in_function ~arity loc sexp.pexp_attributes env ty_expected l + type_function ?in_function ~arity ~async loc sexp.pexp_attributes env + ty_expected l [Exp.case pat body] - | Pexp_fun {arg_label = l; default = None; lhs = spat; rhs = sbody; arity} -> - type_function ?in_function ~arity loc sexp.pexp_attributes env ty_expected l + | Pexp_fun + {arg_label = l; default = None; lhs = spat; rhs = sbody; arity; async} -> + type_function ?in_function ~arity ~async loc sexp.pexp_attributes env + ty_expected l [Ast_helper.Exp.case spat sbody] | Pexp_apply (sfunct, sargs) -> assert (sargs <> []); @@ -3246,7 +3256,8 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg = Rejected) env sexp | Pexp_extension ext -> raise (Error_forward (Builtin_attributes.error_of_extension ext)) -and type_function ?in_function ~arity loc attrs env ty_expected_ l caselist = +and type_function ?in_function ~arity ~async loc attrs env ty_expected_ l + caselist = let state = Warnings.backup () in (* Disable Unerasable_optional_argument for uncurried functions *) let unerasable_optional_argument = @@ -3304,7 +3315,8 @@ and type_function ?in_function ~arity loc attrs env ty_expected_ l caselist = Warnings.restore state; re { - exp_desc = Texp_function {arg_label = l; arity; param; case; partial}; + exp_desc = + Texp_function {arg_label = l; arity; param; case; partial; async}; exp_loc = loc; exp_extra = []; exp_type; diff --git a/compiler/ml/typedtree.ml b/compiler/ml/typedtree.ml index 43d13cf450..c3af7028fd 100644 --- a/compiler/ml/typedtree.ml +++ b/compiler/ml/typedtree.ml @@ -82,6 +82,7 @@ and expression_desc = param: Ident.t; case: case; partial: partial; + async: bool; } | Texp_apply of expression * (arg_label * expression option) list | Texp_match of expression * case list * case list * partial diff --git a/compiler/ml/typedtree.mli b/compiler/ml/typedtree.mli index d6c6988078..2aabedb4aa 100644 --- a/compiler/ml/typedtree.mli +++ b/compiler/ml/typedtree.mli @@ -136,6 +136,7 @@ and expression_desc = param: Ident.t; case: case; partial: partial; + async: bool; } (** [Pexp_fun] and [Pexp_function] both translate to [Texp_function]. See {!Parsetree} for more details. diff --git a/compiler/syntax/src/res_parsetree_viewer.ml b/compiler/syntax/src/res_parsetree_viewer.ml index 7331d89ef4..a2578e5ade 100644 --- a/compiler/syntax/src/res_parsetree_viewer.ml +++ b/compiler/syntax/src/res_parsetree_viewer.ml @@ -214,7 +214,7 @@ let filter_parsing_attrs attrs = | ( { Location.txt = ( "res.braces" | "ns.braces" | "res.iflet" | "res.namedArgLoc" - | "res.ternary" | "res.async" | "res.await" | "res.template" + | "res.ternary" | "res.await" | "res.template" | "res.taggedTemplate" | "res.patVariantSpread" | "res.dictPattern" ); }, @@ -365,7 +365,7 @@ let has_attributes attrs = | ( { Location.txt = ( "res.braces" | "ns.braces" | "res.iflet" | "res.ternary" - | "res.async" | "res.await" | "res.template" ); + | "res.await" | "res.template" ); }, _ ) -> false @@ -548,8 +548,8 @@ let is_printable_attribute attr = match attr with | ( { Location.txt = - ( "res.iflet" | "res.braces" | "ns.braces" | "JSX" | "res.async" - | "res.await" | "res.template" | "res.ternary" ); + ( "res.iflet" | "res.braces" | "ns.braces" | "JSX" | "res.await" + | "res.template" | "res.ternary" ); }, _ ) -> false diff --git a/tests/syntax_tests/data/parsing/grammar/expressions/expected/UncurriedByDefault.res.txt b/tests/syntax_tests/data/parsing/grammar/expressions/expected/UncurriedByDefault.res.txt index d2a3bf9c58..2b8c88feb1 100644 --- a/tests/syntax_tests/data/parsing/grammar/expressions/expected/UncurriedByDefault.res.txt +++ b/tests/syntax_tests/data/parsing/grammar/expressions/expected/UncurriedByDefault.res.txt @@ -37,9 +37,9 @@ type nonrec unested = (string -> unit (a:1)) -> unit (a:1) let (uannpoly : 'a -> string (a:1)) = xx let (uannint : int -> string (a:1)) = xx let _ = ((fun [arity:1]x -> 34)[@att ]) -let _ = ((fun [arity:1]x -> 34)[@res.async ][@att ]) +let _ = ((async fun [arity:1]x -> 34)[@att ]) let _ = preserveAttr ((fun [arity:1]x -> 34)[@att ]) -let _ = preserveAttr ((fun [arity:1]x -> 34)[@res.async ][@att ]) +let _ = preserveAttr ((async fun [arity:1]x -> 34)[@att ]) let t0 (type a) (type b) [arity:2](l : a list) (x : a) = x :: l let t1 (type a) (type b) [arity:2](l : a list) (x : a) = x :: l let t2 (type a) (type b) [arity:2](l : a list) (x : a) = x :: l @@ -95,9 +95,9 @@ let pipe1 = 3 |.u f let (uannpoly : 'a -> string (a:1)) = xx let (uannint : int -> string (a:1)) = xx let _ = ((fun [arity:1]x -> 34)[@att ]) -let _ = ((fun [arity:1]x -> 34)[@res.async ][@att ]) +let _ = ((async fun [arity:1]x -> 34)[@att ]) let _ = preserveAttr ((fun [arity:1]x -> 34)[@att ]) -let _ = preserveAttr ((fun [arity:1]x -> 34)[@res.async ][@att ]) +let _ = preserveAttr ((async fun [arity:1]x -> 34)[@att ]) let t0 (type a) (type b) [arity:2](l : a list) (x : a) = x :: l let t1 (type a) (type b) [arity:2](l : a list) (x : a) = x :: l let t2 (type a) (type b) [arity:2](l : a list) (x : a) = x :: l diff --git a/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt b/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt index 532bd33f9e..3410ad4918 100644 --- a/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt +++ b/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt @@ -1,17 +1,12 @@ -let greetUser = - ((fun [arity:1]userId -> - ((let name = ((getUserName userId)[@res.await ]) in - ({js|Hello |js} ^ name) ^ {js|!|js}) - [@res.braces ])) - [@res.async ]) -;;((fun [arity:1]() -> 123)[@res.async ]) -let fetch = ((fun [arity:1]url -> browserFetch url) - [@res.braces ][@res.async ]) +let greetUser [arity:1]userId = + ((let name = ((getUserName userId)[@res.await ]) in + ({js|Hello |js} ^ name) ^ {js|!|js}) + [@res.braces ]) +;;async fun [arity:1]() -> 123 +let fetch = ((async fun [arity:1]url -> browserFetch url)[@res.braces ]) let fetch2 = - (((((fun [arity:1]url -> browserFetch url)) - [@res.async ]); - (((fun [arity:1]url -> browserFetch2 url)) - [@res.async ])) + (((async fun [arity:1]url -> browserFetch url); + (async fun [arity:1]url -> browserFetch2 url)) [@res.braces ]) let async = ((let f = async () in @@ -23,27 +18,27 @@ let async = [@res.braces ]) let f = ((if isPositive - then ((fun [arity:2]a -> fun b -> (a + b : int))[@res.async ]) - else (((fun [arity:2]c -> fun d -> (c - d : int)))[@res.async ])) + then async fun [arity:2]a -> fun b -> (a + b : int) + else (async fun [arity:2]c -> fun d -> (c - d : int))) [@res.ternary ]) let foo = async ~a:((34)[@res.namedArgLoc ]) -let bar = ((fun [arity:1]~a:((a)[@res.namedArgLoc ]) -> a + 1)[@res.async ]) +let bar [arity:1]~a:((a)[@res.namedArgLoc ]) = a + 1 let ex1 = ((3)[@res.await ]) + ((4)[@res.await ]) let ex2 = ((3)[@res.await ]) ** ((4)[@res.await ]) let ex3 = ((foo |.u (bar ~arg:((arg)[@res.namedArgLoc ])))[@res.await ]) let ex4 = (((foo.bar).baz)[@res.await ]) -let attr1 = ((fun [arity:1]x -> x + 1)[@res.async ][@a ]) +let attr1 = ((async fun [arity:1]x -> x + 1)[@a ]) let attr2 = ((fun (type a) -> - ((fun [arity:1]() -> fun (type b) -> fun (type c) -> fun [arity:1]x -> 3) - [@res.async ]))[@a ]) + async fun [arity:1]() -> fun (type b) -> fun (type c) -> + fun [arity:1]x -> 3) + [@a ]) let attr3 = ((fun (type a) -> - fun [arity:1]() -> fun (type b) -> fun (type c) -> ((fun [arity:1]x -> 3) - [@res.async ])) + fun [arity:1]() -> fun (type b) -> fun (type c) -> + async fun [arity:1]x -> 3) [@a ]) let attr4 = ((fun (type a) -> - fun [arity:1]() -> ((fun (type b) -> fun (type c) -> ((fun [arity:1]x -> 3) - [@res.async ]))[@b ])) + fun [arity:1]() -> ((fun (type b) -> fun (type c) -> + async fun [arity:1]x -> 3)[@b ])) [@a ]) let (attr5 : int) = ((fun (type a) -> fun (type b) -> fun (type c) -> - ((fun [arity:1]() -> fun [arity:1](x : a) -> x)[@res.async ]))[@a ] - [@b ]) \ No newline at end of file + async fun [arity:1]() -> fun [arity:1](x : a) -> x)[@a ][@b ]) \ No newline at end of file diff --git a/tests/tools_tests/ppx/TestPpx.res b/tests/tools_tests/ppx/TestPpx.res index a3288f33e2..641821fb6d 100644 --- a/tests/tools_tests/ppx/TestPpx.res +++ b/tests/tools_tests/ppx/TestPpx.res @@ -35,3 +35,10 @@ module Uncurried = { type f1 = int => string type f2 = (int, int) => string } + +let async_succ = async x => x + 1 +let async_foo = async (x, y) => { + let a: promise = async_succ(x) + let b: promise = async_succ(y) + (await a) + (await b) +} diff --git a/tests/tools_tests/src/expected/TestPpx.res.jsout b/tests/tools_tests/src/expected/TestPpx.res.jsout index 8235042c40..bcd68f7e14 100644 --- a/tests/tools_tests/src/expected/TestPpx.res.jsout +++ b/tests/tools_tests/src/expected/TestPpx.res.jsout @@ -41,6 +41,16 @@ async function fpromise(promise, _x) { let Uncurried = {}; +async function async_succ(x) { + return x + 1 | 0; +} + +async function async_foo(x, y) { + let a = async_succ(x); + let b = async_succ(y); + return await a + await b | 0; +} + let a = "A"; let b = "B"; @@ -55,4 +65,6 @@ exports.OptionalFields = OptionalFields; exports.Arity = Arity; exports.fpromise = fpromise; exports.Uncurried = Uncurried; +exports.async_succ = async_succ; +exports.async_foo = async_foo; /* Not a pure module */ From 56e5aea37ac4a4417a808fc48de37f276808143b Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Wed, 8 Jan 2025 17:12:01 +0100 Subject: [PATCH 3/3] Simplify ast async: add async flag directly where it's needed. --- CHANGELOG.md | 5 ----- compiler/ml/ast_async.ml | 12 ------------ compiler/ml/ast_uncurried.ml | 4 ++-- compiler/ml/pprintast.ml | 8 +++++--- compiler/syntax/src/jsx_v4.ml | 3 +-- compiler/syntax/src/res_core.ml | 14 ++++++++------ .../grammar/expressions/expected/async.res.txt | 4 ++-- 7 files changed, 18 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3936f7618..8f81f0d1ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,11 +24,6 @@ - AST: always put type parameters first in function definitions. https://github.com/rescript-lang/rescript/pull/7233 - AST cleanup: Remove `@res.async` attribute from the internal representation, and add a flag to untyped and typed ASTs instead. https://github.com/rescript-lang/rescript/pull/7234 -#### :house: Internal - -- AST cleanup: Prepare for ast async cleanup: Refactor code for "@res.async" payload handling and clean up handling of type and term parameters, so that now each `=>` in a function definition corresponds to a function. https://github.com/rescript-lang/rescript/pull/7223 - - # 12.0.0-alpha.7 #### :bug: Bug fix diff --git a/compiler/ml/ast_async.ml b/compiler/ml/ast_async.ml index bd0b8f48ef..d5494ebfba 100644 --- a/compiler/ml/ast_async.ml +++ b/compiler/ml/ast_async.ml @@ -4,18 +4,6 @@ let rec dig_async_payload_from_function (expr : Parsetree.expression) = | Pexp_newtype (_, body) -> dig_async_payload_from_function body | _ -> false -let add_async_attribute ~async (body : Parsetree.expression) = - if async then - let rec add_to_fun (exp : Parsetree.expression) = - match exp.pexp_desc with - | Pexp_newtype (txt, e) -> - {exp with pexp_desc = Pexp_newtype (txt, add_to_fun e)} - | Pexp_fun f -> {exp with pexp_desc = Pexp_fun {f with async}} - | _ -> exp - in - add_to_fun body - else body - let add_promise_type ?(loc = Location.none) ~async (result : Parsetree.expression) = if async then diff --git a/compiler/ml/ast_uncurried.ml b/compiler/ml/ast_uncurried.ml index 98b898675b..9834af1087 100644 --- a/compiler/ml/ast_uncurried.ml +++ b/compiler/ml/ast_uncurried.ml @@ -6,11 +6,11 @@ let uncurried_type ~arity (t_arg : Parsetree.core_type) = {t_arg with ptyp_desc = Ptyp_arrow (l, t1, t2, Some arity)} | _ -> assert false -let uncurried_fun ~arity fun_expr = +let uncurried_fun ?(async = false) ~arity fun_expr = let fun_expr = match fun_expr.Parsetree.pexp_desc with | Pexp_fun f -> - {fun_expr with pexp_desc = Pexp_fun {f with arity = Some arity}} + {fun_expr with pexp_desc = Pexp_fun {f with arity = Some arity; async}} | _ -> assert false in fun_expr diff --git a/compiler/ml/pprintast.ml b/compiler/ml/pprintast.ml index 9826b3bc87..ea826c2689 100644 --- a/compiler/ml/pprintast.ml +++ b/compiler/ml/pprintast.ml @@ -993,17 +993,19 @@ and binding ctxt f {pvb_pat = p; pvb_expr = x; _} = if x.pexp_attributes <> [] then pp f "=@;%a" (expression ctxt) x else match x.pexp_desc with - | Pexp_fun {arg_label = label; default = eo; lhs = p; rhs = e; arity} -> + | Pexp_fun + {arg_label = label; default = eo; lhs = p; rhs = e; arity; async} -> let arity_str = match arity with | None -> "" | Some arity -> "[arity:" ^ string_of_int arity ^ "]" in + let async_str = if async then "async " else "" in if label = Nolabel then - pp f "%s%a@ %a" arity_str (simple_pattern ctxt) p + pp f "%s%s%a@ %a" async_str arity_str (simple_pattern ctxt) p pp_print_pexp_function e else - pp f "%s%a@ %a" arity_str (label_exp ctxt) (label, eo, p) + pp f "%s%s%a@ %a" async_str arity_str (label_exp ctxt) (label, eo, p) pp_print_pexp_function e | Pexp_newtype (str, e) -> pp f "(type@ %s)@ %a" str.txt pp_print_pexp_function e diff --git a/compiler/syntax/src/jsx_v4.ml b/compiler/syntax/src/jsx_v4.ml index c0b31afe31..e4c853e31a 100644 --- a/compiler/syntax/src/jsx_v4.ml +++ b/compiler/syntax/src/jsx_v4.ml @@ -1125,7 +1125,7 @@ let map_binding ~config ~empty_loc ~pstr_loc ~file_name ~rec_flag binding = | _ -> Pat.record (List.rev patterns_with_label) Open in let expression = - Exp.fun_ ~arity:(Some 1) Nolabel None + Exp.fun_ ~arity:(Some 1) ~async:is_async Nolabel None (Pat.constraint_ record_pattern (Typ.constr ~loc:empty_loc {txt = Lident "props"; loc = empty_loc} @@ -1140,7 +1140,6 @@ let map_binding ~config ~empty_loc ~pstr_loc ~file_name ~rec_flag binding = | _ -> [Typ.any ()])))) expression in - let expression = Ast_async.add_async_attribute ~async:is_async expression in let expression = (* Add new tupes (type a,b,c) to make's definition *) newtypes diff --git a/compiler/syntax/src/res_core.ml b/compiler/syntax/src/res_core.ml index 7a1fbeb610..8c3095ebb0 100644 --- a/compiler/syntax/src/res_core.ml +++ b/compiler/syntax/src/res_core.ml @@ -1537,7 +1537,7 @@ and parse_ternary_expr left_operand p = | _ -> left_operand and parse_es6_arrow_expression ?(arrow_attrs = []) ?(arrow_start_pos = None) - ?context ?term_parameters p = + ?context ?term_parameters ~async p = let start_pos = p.Parser.start_pos in Parser.leave_breadcrumb p Grammar.Es6ArrowExpr; (* Parsing function parameters and attributes: @@ -1609,7 +1609,9 @@ and parse_es6_arrow_expression ?(arrow_attrs = []) ?(arrow_start_pos = None) term_parameters body in let arrow_expr = - Ast_uncurried.uncurried_fun ~arity:(List.length term_parameters) arrow_expr + Ast_uncurried.uncurried_fun + ~arity:(List.length term_parameters) + ~async arrow_expr in let arrow_expr = match type_param_opt with @@ -2159,7 +2161,7 @@ and parse_operand_expr ~context p = then let arrow_attrs = !attrs in let () = attrs := [] in - parse_es6_arrow_expression ~arrow_attrs ~context p + parse_es6_arrow_expression ~async:false ~arrow_attrs ~context p else parse_unary_expr p in (* let endPos = p.Parser.prevEndPos in *) @@ -3000,7 +3002,7 @@ and parse_braced_or_record_expr p = let loc = mk_loc start_pos ident_end_pos in let ident = Location.mkloc (Longident.last path_ident.txt) loc in let a = - parse_es6_arrow_expression + parse_es6_arrow_expression ~async:false ~term_parameters: [ { @@ -3303,8 +3305,8 @@ and parse_expr_block ?first p = and parse_async_arrow_expression ?(arrow_attrs = []) p = let start_pos = p.Parser.start_pos in Parser.expect (Lident "async") p; - Ast_async.add_async_attribute ~async:true - (parse_es6_arrow_expression ~arrow_attrs ~arrow_start_pos:(Some start_pos) p) + parse_es6_arrow_expression ~async:true ~arrow_attrs + ~arrow_start_pos:(Some start_pos) p and parse_await_expression p = let await_loc = mk_loc p.Parser.start_pos p.end_pos in diff --git a/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt b/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt index 3410ad4918..0601fabd7b 100644 --- a/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt +++ b/tests/syntax_tests/data/parsing/grammar/expressions/expected/async.res.txt @@ -1,4 +1,4 @@ -let greetUser [arity:1]userId = +let greetUser async [arity:1]userId = ((let name = ((getUserName userId)[@res.await ]) in ({js|Hello |js} ^ name) ^ {js|!|js}) [@res.braces ]) @@ -22,7 +22,7 @@ let f = else (async fun [arity:2]c -> fun d -> (c - d : int))) [@res.ternary ]) let foo = async ~a:((34)[@res.namedArgLoc ]) -let bar [arity:1]~a:((a)[@res.namedArgLoc ]) = a + 1 +let bar async [arity:1]~a:((a)[@res.namedArgLoc ]) = a + 1 let ex1 = ((3)[@res.await ]) + ((4)[@res.await ]) let ex2 = ((3)[@res.await ]) ** ((4)[@res.await ]) let ex3 = ((foo |.u (bar ~arg:((arg)[@res.namedArgLoc ])))[@res.await ])