Skip to content

Commit

Permalink
Fix codegen for descriptors of async fn returns (#1782)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
alexcrichton committed Sep 20, 2019
1 parent 8ba0142 commit 9c33052
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -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' }
Expand Down
17 changes: 6 additions & 11 deletions crates/backend/src/codegen.rs
Expand Up @@ -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<Output = Result<...>>`
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! {
<wasm_bindgen::JsValue as wasm_bindgen::convert::ReturnWasmAbi>
},
)
} 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! {}
};
Expand Down
16 changes: 16 additions & 0 deletions 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/);
};
70 changes: 70 additions & 0 deletions 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<u32, JsValue> {
Ok(3)
}

#[wasm_bindgen]
pub async fn async_return_4() -> Result<JsValue, JsValue> {
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<AsyncCustomReturn, JsValue> {
Ok(AsyncCustomReturn { val: 6 })
}

#[wasm_bindgen]
pub async fn async_return_7() -> Result<AsyncCustomReturn, u32> {
Ok(AsyncCustomReturn { val: 7 })
}

#[wasm_bindgen]
pub async fn async_return_8() -> Result<AsyncCustomReturn, AsyncCustomReturn> {
Ok(AsyncCustomReturn { val: 8 })
}

#[wasm_bindgen]
pub async fn async_throw() -> Result<(), js_sys::Error> {
Err(js_sys::Error::new("async message"))
}
1 change: 1 addition & 0 deletions tests/wasm/main.rs
Expand Up @@ -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;
Expand Down

0 comments on commit 9c33052

Please sign in to comment.