Skip to content

Add support for async methods. #7702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
- Fix rewatch not recompiling on changes under windows. https://github.com/rescript-lang/rescript/pull/7690
- Fix locations of regex literals. https://github.com/rescript-lang/rescript/pull/7683
- Fix async React component compilation. https://github.com/rescript-lang/rescript/pull/7704
- Fix @this with async keyword. https://github.com/rescript-lang/rescript/pull/7702

# 12.0.0-beta.2

Expand Down
4 changes: 2 additions & 2 deletions compiler/core/js_exp_make.ml
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ let ocaml_fun ?comment ?immutable_mask ?directive ~return_unit ~async
comment;
}

let method_ ?comment ?immutable_mask ~return_unit params body : t =
let method_ ?comment ?immutable_mask ~async ~return_unit params body : t =
let len = List.length params in
{
expression_desc =
Expand All @@ -265,7 +265,7 @@ let method_ ?comment ?immutable_mask ~return_unit params body : t =
body;
env = Js_fun_env.make ?immutable_mask len;
return_unit;
async = false;
async;
directive = None;
};
comment;
Expand Down
1 change: 1 addition & 0 deletions compiler/core/js_exp_make.mli
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ val ocaml_fun :
val method_ :
?comment:string ->
?immutable_mask:bool array ->
async:bool ->
return_unit:bool ->
J.ident list ->
J.block ->
Expand Down
4 changes: 2 additions & 2 deletions compiler/core/lam_compile.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1623,9 +1623,9 @@ let compile output_prefix =
| {primitive = Pjs_unsafe_downgrade _; args} -> assert false
| {primitive = Pjs_fn_method; args = args_lambda} -> (
match args_lambda with
| [Lfunction {params; body; attr = {return_unit}}] ->
| [Lfunction {params; body; attr = {return_unit; async}}] ->
Js_output.output_of_block_and_expression lambda_cxt.continuation []
(E.method_ params ~return_unit
(E.method_ ~async ~return_unit params
(* Invariant: jmp_table can not across function boundary,
here we share env
*)
Expand Down
6 changes: 4 additions & 2 deletions compiler/frontend/ast_uncurry_gen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
open Ast_helper

(* Handling `fun [@this]` used in `object [@bs] end` *)
let to_method_callback loc (self : Bs_ast_mapper.mapper) label
let to_method_callback ~async loc (self : Bs_ast_mapper.mapper) label
(self_pat : Parsetree.pattern) body : Parsetree.expression_desc =
let self_pat = self.pat self self_pat in
(match Ast_pat.is_single_variable_pattern_conservative self_pat with
Expand All @@ -50,7 +50,9 @@ let to_method_callback loc (self : Bs_ast_mapper.mapper) label
let arity = List.length rev_extra_args in
let body =
match body.pexp_desc with
| Pexp_fun f -> {body with pexp_desc = Pexp_fun {f with arity = Some arity}}
| Pexp_fun f ->
Ast_async.make_function_async ~async
{body with pexp_desc = Pexp_fun {f with arity = Some arity; async}}
| _ -> body
in
let arity_s = string_of_int arity in
Expand Down
1 change: 1 addition & 0 deletions compiler/frontend/ast_uncurry_gen.mli
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)

val to_method_callback :
async:bool ->
Location.t ->
Bs_ast_mapper.mapper ->
Asttypes.arg_label ->
Expand Down
3 changes: 2 additions & 1 deletion compiler/frontend/bs_builtin_ppx.ml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
{
e with
pexp_desc =
Ast_uncurry_gen.to_method_callback e.pexp_loc self label pat body;
Ast_uncurry_gen.to_method_callback ~async e.pexp_loc self label pat
body;
pexp_attributes;
})
| Pexp_apply _ -> Ast_exp_apply.app_exp_mapper e self
Expand Down
12 changes: 12 additions & 0 deletions tests/tests/src/UncurriedExternals.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,20 @@ function methodWithAsync(param) {
return (async arg => $$this + arg | 0)(param);
}

let p1 = {
watch: async function (name, ev) {
let pc = this ;
console.log(pc);
}
};

let AsyncMethod = {
p1: p1
};

export {
StandardNotation,
methodWithAsync,
AsyncMethod,
}
/* h Not a pure module */
14 changes: 14 additions & 0 deletions tests/tests/src/UncurriedExternals.res
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ module StandardNotation = {
}

let methodWithAsync = @this this => async arg => this + arg

module AsyncMethod = {
type pluginContext
type changeEvent

type p = {watch: @this (pluginContext, string, changeEvent) => promise<unit>}

let p1 = {
watch: @this
async (pc, name, ev) => {
Console.log(pc)
},
}
}