Skip to content

Commit 9c33052

Browse files
authored
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
1 parent 8ba0142 commit 9c33052

File tree

5 files changed

+94
-11
lines changed

5 files changed

+94
-11
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ cfg-if = "0.1.9"
4444
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
4545
js-sys = { path = 'crates/js-sys', version = '0.3.27' }
4646
wasm-bindgen-test = { path = 'crates/test', version = '=0.3.0' }
47+
wasm-bindgen-futures = { path = 'crates/futures', version = '=0.4.0' }
4748
serde_derive = "1.0"
4849
wasm-bindgen-test-crate-a = { path = 'tests/crates/a', version = '0.1' }
4950
wasm-bindgen-test-crate-b = { path = 'tests/crates/b', version = '0.1' }

crates/backend/src/codegen.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -446,36 +446,31 @@ impl TryToTokens for ast::Export {
446446
// For an `async` function we always run it through `future_to_promise`
447447
// since we're returning a promise to JS, and this will implicitly
448448
// require that the function returns a `Future<Output = Result<...>>`
449-
let (ret_expr, projection) = if self.function.r#async {
449+
let (ret_ty, ret_expr) = if self.function.r#async {
450450
(
451+
quote! { wasm_bindgen::JsValue },
451452
quote! {
452453
wasm_bindgen_futures::future_to_promise(async {
453454
wasm_bindgen::__rt::IntoJsResult::into_js_result(#ret.await)
454455
}).into()
455456
},
456-
quote! {
457-
<wasm_bindgen::JsValue as wasm_bindgen::convert::ReturnWasmAbi>
458-
},
459457
)
460458
} else {
461459
(
460+
quote! { #syn_ret },
462461
quote! { #ret },
463-
quote! {
464-
<#syn_ret as wasm_bindgen::convert::ReturnWasmAbi>
465-
},
466462
)
467463
};
464+
let projection = quote! { <#ret_ty as wasm_bindgen::convert::ReturnWasmAbi> };
468465
let convert_ret = quote! { #projection::return_abi(#ret_expr) };
469466
let describe_ret = quote! {
470-
<#syn_ret as WasmDescribe>::describe();
467+
<#ret_ty as WasmDescribe>::describe();
471468
};
472469
let nargs = self.function.arguments.len() as u32;
473470
let attrs = &self.function.rust_attrs;
474471

475472
let start_check = if self.start {
476-
quote! {
477-
const _ASSERT: fn() = || -> #projection::Abi { loop {} };
478-
}
473+
quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; }
479474
} else {
480475
quote! {}
481476
};

tests/wasm/futures.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const assert = require('assert');
2+
const wasm = require('wasm-bindgen-test');
3+
4+
exports.call_exports = async function() {
5+
await wasm.async_do_nothing();
6+
assert.strictEqual(1, await wasm.async_return_1());
7+
assert.strictEqual(2, await wasm.async_return_2());
8+
await wasm.async_nothing_again();
9+
assert.strictEqual(3, await wasm.async_return_3());
10+
assert.strictEqual(4, await wasm.async_return_4());
11+
assert.strictEqual(5, (await wasm.async_return_5()).val);
12+
assert.strictEqual(6, (await wasm.async_return_6()).val);
13+
assert.strictEqual(7, (await wasm.async_return_7()).val);
14+
assert.strictEqual(8, (await wasm.async_return_8()).val);
15+
await assert.rejects(wasm.async_throw(), /async message/);
16+
};

tests/wasm/futures.rs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use wasm_bindgen::prelude::*;
2+
use wasm_bindgen_test::*;
3+
4+
#[wasm_bindgen(module = "tests/wasm/futures.js")]
5+
extern "C" {
6+
fn call_exports() -> js_sys::Promise;
7+
}
8+
9+
#[wasm_bindgen_test]
10+
async fn smoke() {
11+
wasm_bindgen_futures::JsFuture::from(call_exports()).await.unwrap();
12+
}
13+
14+
#[wasm_bindgen]
15+
pub async fn async_do_nothing() {}
16+
17+
#[wasm_bindgen]
18+
pub async fn async_return_1() -> JsValue {
19+
1.into()
20+
}
21+
22+
#[wasm_bindgen]
23+
pub async fn async_return_2() -> u32 {
24+
2
25+
}
26+
27+
#[wasm_bindgen]
28+
pub async fn async_nothing_again() -> Result<(), JsValue> {
29+
Ok(())
30+
}
31+
32+
#[wasm_bindgen]
33+
pub async fn async_return_3() -> Result<u32, JsValue> {
34+
Ok(3)
35+
}
36+
37+
#[wasm_bindgen]
38+
pub async fn async_return_4() -> Result<JsValue, JsValue> {
39+
Ok(4.into())
40+
}
41+
42+
#[wasm_bindgen]
43+
pub struct AsyncCustomReturn {
44+
pub val: u32,
45+
}
46+
47+
#[wasm_bindgen]
48+
pub async fn async_return_5() -> AsyncCustomReturn {
49+
AsyncCustomReturn { val: 5 }
50+
}
51+
52+
#[wasm_bindgen]
53+
pub async fn async_return_6() -> Result<AsyncCustomReturn, JsValue> {
54+
Ok(AsyncCustomReturn { val: 6 })
55+
}
56+
57+
#[wasm_bindgen]
58+
pub async fn async_return_7() -> Result<AsyncCustomReturn, u32> {
59+
Ok(AsyncCustomReturn { val: 7 })
60+
}
61+
62+
#[wasm_bindgen]
63+
pub async fn async_return_8() -> Result<AsyncCustomReturn, AsyncCustomReturn> {
64+
Ok(AsyncCustomReturn { val: 8 })
65+
}
66+
67+
#[wasm_bindgen]
68+
pub async fn async_throw() -> Result<(), js_sys::Error> {
69+
Err(js_sys::Error::new("async message"))
70+
}

tests/wasm/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub mod duplicates;
2323
pub mod enums;
2424
#[path = "final.rs"]
2525
pub mod final_;
26+
pub mod futures;
2627
pub mod getters_and_setters;
2728
pub mod import_class;
2829
pub mod imports;

0 commit comments

Comments
 (0)