From 9c330529f2277e2b34a8189b60c58438b77f3407 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 20 Sep 2019 16:06:27 -0500 Subject: [PATCH] Fix codegen for descriptors of async fn returns (#1782) They erroneously reported returning the original return type, not the promise! Let's also add a bunch of positive tests while we're at it. Closes #1781 --- Cargo.toml | 1 + crates/backend/src/codegen.rs | 17 +++------ tests/wasm/futures.js | 16 ++++++++ tests/wasm/futures.rs | 70 +++++++++++++++++++++++++++++++++++ tests/wasm/main.rs | 1 + 5 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 tests/wasm/futures.js create mode 100644 tests/wasm/futures.rs diff --git a/Cargo.toml b/Cargo.toml index c5730add5..93c8add16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ cfg-if = "0.1.9" [target.'cfg(target_arch = "wasm32")'.dev-dependencies] js-sys = { path = 'crates/js-sys', version = '0.3.27' } wasm-bindgen-test = { path = 'crates/test', version = '=0.3.0' } +wasm-bindgen-futures = { path = 'crates/futures', version = '=0.4.0' } serde_derive = "1.0" wasm-bindgen-test-crate-a = { path = 'tests/crates/a', version = '0.1' } wasm-bindgen-test-crate-b = { path = 'tests/crates/b', version = '0.1' } diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 3361c56bf..f2a2623a3 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -446,36 +446,31 @@ impl TryToTokens for ast::Export { // For an `async` function we always run it through `future_to_promise` // since we're returning a promise to JS, and this will implicitly // require that the function returns a `Future>` - let (ret_expr, projection) = if self.function.r#async { + let (ret_ty, ret_expr) = if self.function.r#async { ( + quote! { wasm_bindgen::JsValue }, quote! { wasm_bindgen_futures::future_to_promise(async { wasm_bindgen::__rt::IntoJsResult::into_js_result(#ret.await) }).into() }, - quote! { - - }, ) } else { ( + quote! { #syn_ret }, quote! { #ret }, - quote! { - <#syn_ret as wasm_bindgen::convert::ReturnWasmAbi> - }, ) }; + let projection = quote! { <#ret_ty as wasm_bindgen::convert::ReturnWasmAbi> }; let convert_ret = quote! { #projection::return_abi(#ret_expr) }; let describe_ret = quote! { - <#syn_ret as WasmDescribe>::describe(); + <#ret_ty as WasmDescribe>::describe(); }; let nargs = self.function.arguments.len() as u32; let attrs = &self.function.rust_attrs; let start_check = if self.start { - quote! { - const _ASSERT: fn() = || -> #projection::Abi { loop {} }; - } + quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; } } else { quote! {} }; diff --git a/tests/wasm/futures.js b/tests/wasm/futures.js new file mode 100644 index 000000000..20cec9a89 --- /dev/null +++ b/tests/wasm/futures.js @@ -0,0 +1,16 @@ +const assert = require('assert'); +const wasm = require('wasm-bindgen-test'); + +exports.call_exports = async function() { + await wasm.async_do_nothing(); + assert.strictEqual(1, await wasm.async_return_1()); + assert.strictEqual(2, await wasm.async_return_2()); + await wasm.async_nothing_again(); + assert.strictEqual(3, await wasm.async_return_3()); + assert.strictEqual(4, await wasm.async_return_4()); + assert.strictEqual(5, (await wasm.async_return_5()).val); + assert.strictEqual(6, (await wasm.async_return_6()).val); + assert.strictEqual(7, (await wasm.async_return_7()).val); + assert.strictEqual(8, (await wasm.async_return_8()).val); + await assert.rejects(wasm.async_throw(), /async message/); +}; diff --git a/tests/wasm/futures.rs b/tests/wasm/futures.rs new file mode 100644 index 000000000..9cf04e774 --- /dev/null +++ b/tests/wasm/futures.rs @@ -0,0 +1,70 @@ +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; + +#[wasm_bindgen(module = "tests/wasm/futures.js")] +extern "C" { + fn call_exports() -> js_sys::Promise; +} + +#[wasm_bindgen_test] +async fn smoke() { + wasm_bindgen_futures::JsFuture::from(call_exports()).await.unwrap(); +} + +#[wasm_bindgen] +pub async fn async_do_nothing() {} + +#[wasm_bindgen] +pub async fn async_return_1() -> JsValue { + 1.into() +} + +#[wasm_bindgen] +pub async fn async_return_2() -> u32 { + 2 +} + +#[wasm_bindgen] +pub async fn async_nothing_again() -> Result<(), JsValue> { + Ok(()) +} + +#[wasm_bindgen] +pub async fn async_return_3() -> Result { + Ok(3) +} + +#[wasm_bindgen] +pub async fn async_return_4() -> Result { + Ok(4.into()) +} + +#[wasm_bindgen] +pub struct AsyncCustomReturn { + pub val: u32, +} + +#[wasm_bindgen] +pub async fn async_return_5() -> AsyncCustomReturn { + AsyncCustomReturn { val: 5 } +} + +#[wasm_bindgen] +pub async fn async_return_6() -> Result { + Ok(AsyncCustomReturn { val: 6 }) +} + +#[wasm_bindgen] +pub async fn async_return_7() -> Result { + Ok(AsyncCustomReturn { val: 7 }) +} + +#[wasm_bindgen] +pub async fn async_return_8() -> Result { + Ok(AsyncCustomReturn { val: 8 }) +} + +#[wasm_bindgen] +pub async fn async_throw() -> Result<(), js_sys::Error> { + Err(js_sys::Error::new("async message")) +} diff --git a/tests/wasm/main.rs b/tests/wasm/main.rs index 24eee1e41..e0064cebc 100644 --- a/tests/wasm/main.rs +++ b/tests/wasm/main.rs @@ -23,6 +23,7 @@ pub mod duplicates; pub mod enums; #[path = "final.rs"] pub mod final_; +pub mod futures; pub mod getters_and_setters; pub mod import_class; pub mod imports;