Skip to content

Move async function arguments into spawned futures #3043

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 1 commit into from
Aug 30, 2022
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
43 changes: 29 additions & 14 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,19 +470,15 @@ impl TryToTokens for ast::Export {
quote! { () },
quote! { () },
quote! {
wasm_bindgen_futures::spawn_local(async move {
<#syn_ret as wasm_bindgen::__rt::Start>::start(#ret.await);
})
<#syn_ret as wasm_bindgen::__rt::Start>::start(#ret.await)
},
)
} else {
(
quote! { wasm_bindgen::JsValue },
quote! { #syn_ret },
quote! {
wasm_bindgen_futures::future_to_promise(async move {
<#syn_ret as wasm_bindgen::__rt::IntoJsResult>::into_js_result(#ret.await)
}).into()
<#syn_ret as wasm_bindgen::__rt::IntoJsResult>::into_js_result(#ret.await)
},
)
}
Expand All @@ -496,8 +492,32 @@ impl TryToTokens for ast::Export {
(quote! { #syn_ret }, quote! { #syn_ret }, quote! { #ret })
};

let mut call = quote! {
{
#(#arg_conversions)*
let #ret = #receiver(#(#converted_arguments),*);
#ret_expr
}
};

if self.function.r#async {
if self.start {
call = quote! {
wasm_bindgen_futures::spawn_local(async move {
#call
})
}
} else {
call = quote! {
wasm_bindgen_futures::future_to_promise(async move {
#call
}).into()
}
}
}

let projection = quote! { <#ret_ty as wasm_bindgen::convert::ReturnWasmAbi> };
let convert_ret = quote! { #projection::return_abi(#ret_expr) };
let convert_ret = quote! { #projection::return_abi(#ret) };
let describe_ret = quote! {
<#ret_ty as WasmDescribe>::describe();
<#inner_ret_ty as WasmDescribe>::describe();
Expand All @@ -523,13 +543,8 @@ impl TryToTokens for ast::Export {
)]
pub unsafe extern "C" fn #generated_name(#(#args),*) -> #projection::Abi {
#start_check
// Scope all local variables to be destroyed after we call
// the function to ensure that `#convert_ret`, if it panics,
// doesn't leak anything.
let #ret = {
#(#arg_conversions)*
#receiver(#(#converted_arguments),*)
};

let #ret = #call;
#convert_ret
}
};
Expand Down
3 changes: 3 additions & 0 deletions tests/wasm/futures.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ exports.call_exports = async function() {
await assert.rejects(wasm.async_throw_message(), /async message/);
await assert.rejects(wasm.async_throw_jserror(), /async message/);
await assert.rejects(wasm.async_throw_custom_error(), /custom error/);
assert.strictEqual("Hi, Jim!", await wasm.async_take_reference("Jim"));
const foo = await new wasm.AsyncStruct();
assert.strictEqual(42, await foo.method());
};

exports.call_promise = async function() {
Expand Down
20 changes: 20 additions & 0 deletions tests/wasm/futures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,26 @@ pub async fn async_throw_custom_error() -> Result<AsyncCustomReturn, AsyncCustom
})
}

#[wasm_bindgen]
pub async fn async_take_reference(x: &str) -> String {
format!("Hi, {x}!")
}

#[wasm_bindgen]
pub struct AsyncStruct;

#[wasm_bindgen]
impl AsyncStruct {
#[wasm_bindgen(constructor)]
pub async fn new() -> AsyncStruct {
AsyncStruct
}

pub async fn method(&self) -> u32 {
42
}
}

#[wasm_bindgen_test]
async fn test_promise() {
assert_eq!(call_promise().await.as_string(), Some(String::from("ok")))
Expand Down