diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 16ceda1ad34..18d6c33592b 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -447,17 +447,37 @@ impl TryToTokens for ast::Export { // since we're returning a promise to JS, and this will implicitly // require that the function returns a `Future>` let (ret_ty, ret_expr) = if self.function.r#async { + if self.start { + ( + quote! { () }, + quote! { + wasm_bindgen_futures::spawn_local(async move { + <#syn_ret as wasm_bindgen::__rt::Start>::start(#ret.await); + }) + }, + ) + + } else { + ( + quote! { wasm_bindgen::JsValue }, + quote! { + wasm_bindgen_futures::future_to_promise(async move { + <#syn_ret as wasm_bindgen::__rt::IntoJsResult>::into_js_result(#ret.await) + }).into() + }, + ) + } + + } else if self.start { ( - quote! { wasm_bindgen::JsValue }, - quote! { - wasm_bindgen_futures::future_to_promise(async { - wasm_bindgen::__rt::IntoJsResult::into_js_result(#ret.await) - }).into() - }, + quote! { () }, + quote! { <#syn_ret as wasm_bindgen::__rt::Start>::start(#ret) }, ) + } else { (quote! { #syn_ret }, quote! { #ret }) }; + let projection = quote! { <#ret_ty as wasm_bindgen::convert::ReturnWasmAbi> }; let convert_ret = quote! { #projection::return_abi(#ret_expr) }; let describe_ret = quote! { diff --git a/crates/macro/ui-tests/start-function.rs b/crates/macro/ui-tests/start-function.rs index 3947840cd5b..65ad90bf283 100644 --- a/crates/macro/ui-tests/start-function.rs +++ b/crates/macro/ui-tests/start-function.rs @@ -9,4 +9,25 @@ pub fn foo2(x: u32) {} #[wasm_bindgen(start)] pub fn foo3() {} +#[wasm_bindgen(start)] +pub fn foo4() -> Result<(), JsValue> { Ok(()) } + +#[wasm_bindgen(start)] +pub fn foo5() -> Result { Err(()) } + +#[wasm_bindgen(start)] +pub fn foo6() -> Result { Ok(JsValue::from(1u32)) } + +#[wasm_bindgen(start)] +pub async fn foo_async1() {} + +#[wasm_bindgen(start)] +pub async fn foo_async2() -> Result<(), JsValue> { Ok(()) } + +#[wasm_bindgen(start)] +pub async fn foo_async3() -> Result { Err(()) } + +#[wasm_bindgen(start)] +pub async fn foo_async4() -> Result { Ok(JsValue::from(1u32)) } + fn main() {} diff --git a/crates/macro/ui-tests/start-function.stderr b/crates/macro/ui-tests/start-function.stderr index 43d845f94ca..81814584cd8 100644 --- a/crates/macro/ui-tests/start-function.stderr +++ b/crates/macro/ui-tests/start-function.stderr @@ -9,3 +9,23 @@ error: the start function cannot have generics | 10 | pub fn foo3() {} | ^^^ + +error[E0277]: the trait bound `std::result::Result: wasm_bindgen::__rt::Start` is not satisfied + --> $DIR/start-function.rs:27:1 + | +27 | #[wasm_bindgen(start)] + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `wasm_bindgen::__rt::Start` is not implemented for `std::result::Result` + | + = help: the following implementations were found: + as wasm_bindgen::__rt::Start> + = note: required by `wasm_bindgen::__rt::Start::start` + +error[E0277]: the trait bound `std::result::Result: wasm_bindgen::__rt::Start` is not satisfied + --> $DIR/start-function.rs:30:1 + | +30 | #[wasm_bindgen(start)] + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `wasm_bindgen::__rt::Start` is not implemented for `std::result::Result` + | + = help: the following implementations were found: + as wasm_bindgen::__rt::Start> + = note: required by `wasm_bindgen::__rt::Start::start` diff --git a/src/lib.rs b/src/lib.rs index 3b54fb47b28..536dcdb7496 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1116,6 +1116,27 @@ pub mod __rt { } } } + + + /// An internal helper trait for usage in `#[wasm_bindgen(start)]` + /// functions to throw the error (if it is `Err`). + pub trait Start { + fn start(self); + } + + impl Start for () { + #[inline] + fn start(self) {} + } + + impl> Start for Result<(), E> { + #[inline] + fn start(self) { + if let Err(e) = self { + crate::throw_val(e.into()); + } + } + } } /// A wrapper type around slices and vectors for binding the `Uint8ClampedArray`