From 965b88cf7eddf607e59af40e09c0967056c5974f Mon Sep 17 00:00:00 2001 From: trevyn Date: Thu, 26 Aug 2021 18:33:36 +0400 Subject: [PATCH] Generate TypeScript return types for `async` functions (#2665) * Generate TypeScript return types for `async` functions * Fix tests to respect returning only `Result` * Fix smoke test * add `simple_async_fn` to `typescript-tests` * cleanup and set JsDoc comment correctly for `Promise` * clean up now that `ts_ret_ty` is complete w/ Promise * add `.d.ts` reference tests * add async reference tests * don't test `.js` and `.wat` in async reference tests --- .gitignore | 1 - crates/backend/src/codegen.rs | 9 +++- crates/backend/src/encode.rs | 1 + crates/cli-support/src/descriptor.rs | 2 + crates/cli-support/src/intrinsic.rs | 1 + crates/cli-support/src/js/binding.rs | 8 +++- crates/cli-support/src/js/mod.rs | 4 +- crates/cli-support/src/wit/mod.rs | 42 +++++++++++++++---- crates/cli-support/src/wit/nonstandard.rs | 2 + crates/cli-support/src/wit/standard.rs | 3 ++ crates/cli/tests/reference.rs | 20 +++++---- crates/cli/tests/reference/add.d.ts | 14 +++++++ crates/cli/tests/reference/anyref-empty.d.ts | 2 + .../tests/reference/anyref-import-catch.d.ts | 5 +++ crates/cli/tests/reference/anyref-nop.d.ts | 5 +++ crates/cli/tests/reference/async-number.d.ts | 6 +++ crates/cli/tests/reference/async-number.rs | 6 +++ crates/cli/tests/reference/async-void.d.ts | 6 +++ crates/cli/tests/reference/async-void.rs | 4 ++ crates/cli/tests/reference/empty.d.ts | 2 + crates/cli/tests/reference/import-catch.d.ts | 5 +++ crates/cli/tests/reference/nop.d.ts | 5 +++ crates/cli/tests/reference/string-arg.d.ts | 6 +++ crates/shared/src/lib.rs | 1 + crates/typescript-tests/Cargo.toml | 1 + crates/typescript-tests/src/lib.rs | 1 + .../typescript-tests/src/simple_async_fn.rs | 9 ++++ .../typescript-tests/src/simple_async_fn.ts | 6 +++ src/convert/closures.rs | 4 ++ tests/wasm/futures.js | 6 +-- tests/wasm/futures.rs | 12 +++--- 31 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 crates/cli/tests/reference/add.d.ts create mode 100644 crates/cli/tests/reference/anyref-empty.d.ts create mode 100644 crates/cli/tests/reference/anyref-import-catch.d.ts create mode 100644 crates/cli/tests/reference/anyref-nop.d.ts create mode 100644 crates/cli/tests/reference/async-number.d.ts create mode 100644 crates/cli/tests/reference/async-number.rs create mode 100644 crates/cli/tests/reference/async-void.d.ts create mode 100644 crates/cli/tests/reference/async-void.rs create mode 100644 crates/cli/tests/reference/empty.d.ts create mode 100644 crates/cli/tests/reference/import-catch.d.ts create mode 100644 crates/cli/tests/reference/nop.d.ts create mode 100644 crates/cli/tests/reference/string-arg.d.ts create mode 100644 crates/typescript-tests/src/simple_async_fn.rs create mode 100644 crates/typescript-tests/src/simple_async_fn.ts diff --git a/.gitignore b/.gitignore index 2abb2923435..8cdf73b9e4f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ node_modules package-lock.json npm-shrinkwrap.json yarn.lock -*.d.ts /publish /publish.exe .vscode diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 4ba3edc5f43..7292b3da0d8 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -459,9 +459,10 @@ 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_ty, ret_expr) = if self.function.r#async { + let (ret_ty, inner_ret_ty, ret_expr) = if self.function.r#async { if self.start { ( + quote! { () }, quote! { () }, quote! { wasm_bindgen_futures::spawn_local(async move { @@ -472,6 +473,7 @@ impl TryToTokens for ast::Export { } 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) @@ -481,17 +483,19 @@ impl TryToTokens for ast::Export { } } else if self.start { ( + quote! { () }, quote! { () }, quote! { <#syn_ret as wasm_bindgen::__rt::Start>::start(#ret) }, ) } else { - (quote! { #syn_ret }, quote! { #ret }) + (quote! { #syn_ret }, 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! { <#ret_ty as WasmDescribe>::describe(); + <#inner_ret_ty as WasmDescribe>::describe(); }; let nargs = self.function.arguments.len() as u32; let attrs = &self.function.rust_attrs; @@ -1171,6 +1175,7 @@ impl<'a> ToTokens for DescribeImport<'a> { inform(#nargs); #(<#argtys as WasmDescribe>::describe();)* #inform_ret + #inform_ret }, attrs: f.function.rust_attrs.clone(), } diff --git a/crates/backend/src/encode.rs b/crates/backend/src/encode.rs index 336a80e60c3..5ff858631f1 100644 --- a/crates/backend/src/encode.rs +++ b/crates/backend/src/encode.rs @@ -205,6 +205,7 @@ fn shared_function<'a>(func: &'a ast::Function, _intern: &'a Interner) -> Functi .collect::>(); Function { arg_names, + asyncness: func.r#async, name: &func.name, generate_typescript: func.generate_typescript, } diff --git a/crates/cli-support/src/descriptor.rs b/crates/cli-support/src/descriptor.rs index 5950242376a..ae65f9e9adf 100644 --- a/crates/cli-support/src/descriptor.rs +++ b/crates/cli-support/src/descriptor.rs @@ -76,6 +76,7 @@ pub struct Function { pub arguments: Vec, pub shim_idx: u32, pub ret: Descriptor, + pub inner_ret: Option, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -237,6 +238,7 @@ impl Function { arguments, shim_idx, ret: Descriptor::_decode(data, false), + inner_ret: Some(Descriptor::_decode(data, false)), } } } diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index 6061d82d8ab..748e313f950 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -45,6 +45,7 @@ macro_rules! intrinsics { shim_idx: 0, arguments: vec![$($arg),*], ret: $ret, + inner_ret: None } } )* diff --git a/crates/cli-support/src/js/binding.rs b/crates/cli-support/src/js/binding.rs index ea79adf9279..3867b6fa6a6 100644 --- a/crates/cli-support/src/js/binding.rs +++ b/crates/cli-support/src/js/binding.rs @@ -101,6 +101,7 @@ impl<'a, 'b> Builder<'a, 'b> { adapter: &Adapter, instructions: &[InstructionData], explicit_arg_names: &Option>, + asyncness: bool, ) -> Result { if self .cx @@ -223,8 +224,9 @@ impl<'a, 'b> Builder<'a, 'b> { let (ts_sig, ts_arg_tys, ts_ret_ty) = self.typescript_signature( &function_args, &arg_tys, - &adapter.results, + &adapter.inner_results, &mut might_be_optional_field, + asyncness, ); let js_doc = self.js_doc_comments(&function_args, &arg_tys, &ts_ret_ty); Ok(JsFunction { @@ -250,6 +252,7 @@ impl<'a, 'b> Builder<'a, 'b> { arg_tys: &[&AdapterType], result_tys: &[AdapterType], might_be_optional_field: &mut bool, + asyncness: bool, ) -> (String, Vec, Option) { // Build up the typescript signature as well let mut omittable = true; @@ -298,6 +301,9 @@ impl<'a, 'b> Builder<'a, 'b> { 1 => adapter2ts(&result_tys[0], &mut ret), _ => ret.push_str("[any]"), } + if asyncness { + ret = format!("Promise<{}>", ret); + } ts.push_str(&ret); ts_ret = Some(ret); } diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index a286adc8808..1e12d158c43 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2325,9 +2325,11 @@ impl<'a> Context<'a> { }); builder.catch(catch); let mut arg_names = &None; + let mut asyncness = false; match kind { Kind::Export(export) => { arg_names = &export.arg_names; + asyncness = export.asyncness; match &export.kind { AuxExportKind::Function(_) => {} AuxExportKind::StaticFunction { .. } => {} @@ -2352,7 +2354,7 @@ impl<'a> Context<'a> { catch, log_error, } = builder - .process(&adapter, instrs, arg_names) + .process(&adapter, instrs, arg_names, asyncness) .with_context(|| match kind { Kind::Export(e) => format!("failed to generate bindings for `{}`", e.debug_name), Kind::Import(i) => { diff --git a/crates/cli-support/src/wit/mod.rs b/crates/cli-support/src/wit/mod.rs index 3b27912653f..0bb382b9cfb 100644 --- a/crates/cli-support/src/wit/mod.rs +++ b/crates/cli-support/src/wit/mod.rs @@ -188,6 +188,7 @@ impl<'a> Context<'a> { shim_idx: 0, arguments: vec![Descriptor::I32; 3], ret: Descriptor::Externref, + inner_ret: None, }; let id = self.import_adapter(*id, signature, AdapterJsImportKind::Normal)?; // Synthesize the two integer pointers we pass through which @@ -455,6 +456,7 @@ impl<'a> Context<'a> { debug_name: wasm_name, comments: concatenate_comments(&export.comments), arg_names: Some(export.function.arg_names), + asyncness: export.function.asyncness, kind, generate_typescript: export.function.generate_typescript, }, @@ -720,6 +722,7 @@ impl<'a> Context<'a> { arguments: Vec::new(), shim_idx: 0, ret: descriptor, + inner_ret: None, }, AdapterJsImportKind::Normal, )?; @@ -748,6 +751,7 @@ impl<'a> Context<'a> { arguments: vec![Descriptor::Ref(Box::new(Descriptor::Externref))], shim_idx: 0, ret: Descriptor::Boolean, + inner_ret: None, }, AdapterJsImportKind::Normal, )?; @@ -797,6 +801,7 @@ impl<'a> Context<'a> { arguments: vec![Descriptor::I32], shim_idx: 0, ret: descriptor.clone(), + inner_ret: None, }; let getter_id = self.export_adapter(getter_id, getter_descriptor)?; self.aux.export_map.insert( @@ -804,6 +809,7 @@ impl<'a> Context<'a> { AuxExport { debug_name: format!("getter for `{}::{}`", struct_.name, field.name), arg_names: None, + asyncness: false, comments: concatenate_comments(&field.comments), kind: AuxExportKind::Getter { class: struct_.name.to_string(), @@ -824,6 +830,7 @@ impl<'a> Context<'a> { arguments: vec![Descriptor::I32, descriptor], shim_idx: 0, ret: Descriptor::Unit, + inner_ret: None, }; let setter_id = self.export_adapter(setter_id, setter_descriptor)?; self.aux.export_map.insert( @@ -831,6 +838,7 @@ impl<'a> Context<'a> { AuxExport { debug_name: format!("setter for `{}::{}`", struct_.name, field.name), arg_names: None, + asyncness: false, comments: concatenate_comments(&field.comments), kind: AuxExportKind::Setter { class: struct_.name.to_string(), @@ -855,6 +863,7 @@ impl<'a> Context<'a> { shim_idx: 0, arguments: vec![Descriptor::I32], ret: Descriptor::Externref, + inner_ret: None, }; let id = self.import_adapter(import_id, signature, AdapterJsImportKind::Normal)?; self.aux @@ -981,6 +990,7 @@ impl<'a> Context<'a> { let id = self.adapters.append( params, results, + vec![], AdapterKind::Import { module: import.module.clone(), name: import.name.clone(), @@ -1015,6 +1025,7 @@ impl<'a> Context<'a> { self.adapters.append( params, results, + vec![], AdapterKind::Local { instructions: Vec::new(), }, @@ -1066,6 +1077,7 @@ impl<'a> Context<'a> { debug_name: format!("standard export {:?}", id), comments: String::new(), arg_names: None, + asyncness: false, kind, generate_typescript: true, }; @@ -1204,6 +1216,7 @@ impl<'a> Context<'a> { let f = args.cx.adapters.append( args.output, ret.input, + vec![], AdapterKind::Import { module: import_module, name: import_name, @@ -1237,10 +1250,12 @@ impl<'a> Context<'a> { } else { ret.output }; - let id = args - .cx - .adapters - .append(args.input, results, AdapterKind::Local { instructions }); + let id = args.cx.adapters.append( + args.input, + results, + vec![], + AdapterKind::Local { instructions }, + ); args.cx.adapters.implements.push((import_id, core_id, id)); Ok(f) } @@ -1279,6 +1294,15 @@ impl<'a> Context<'a> { } // ... then the returned value being translated back + + let inner_ret_output = if signature.inner_ret.is_some() { + let mut inner_ret = args.cx.instruction_builder(true); + inner_ret.outgoing(&signature.inner_ret.unwrap())?; + inner_ret.output + } else { + vec![] + }; + let mut ret = args.cx.instruction_builder(true); ret.outgoing(&signature.ret)?; let uses_retptr = ret.input.len() > 1; @@ -1334,10 +1358,12 @@ impl<'a> Context<'a> { } instructions.extend(ret.instructions); - Ok(ret - .cx - .adapters - .append(args.input, ret.output, AdapterKind::Local { instructions })) + Ok(ret.cx.adapters.append( + args.input, + ret.output, + inner_ret_output, + AdapterKind::Local { instructions }, + )) } fn instruction_builder<'b>(&'b mut self, return_position: bool) -> InstructionBuilder<'b, 'a> { diff --git a/crates/cli-support/src/wit/nonstandard.rs b/crates/cli-support/src/wit/nonstandard.rs index 0c0d94fa967..35d966f602d 100644 --- a/crates/cli-support/src/wit/nonstandard.rs +++ b/crates/cli-support/src/wit/nonstandard.rs @@ -71,6 +71,8 @@ pub struct AuxExport { /// Argument names in Rust forwarded here to configure the names that show /// up in TypeScript bindings. pub arg_names: Option>, + /// Whether this is an async function, to configure the TypeScript return value. + pub asyncness: bool, /// What kind of function this is and where it shows up pub kind: AuxExportKind, /// Whether typescript bindings should be generated for this export. diff --git a/crates/cli-support/src/wit/standard.rs b/crates/cli-support/src/wit/standard.rs index d9c6807620d..dc37aa4f037 100644 --- a/crates/cli-support/src/wit/standard.rs +++ b/crates/cli-support/src/wit/standard.rs @@ -26,6 +26,7 @@ pub struct Adapter { pub id: AdapterId, pub params: Vec, pub results: Vec, + pub inner_results: Vec, pub kind: AdapterKind, } @@ -368,6 +369,7 @@ impl NonstandardWitSection { &mut self, params: Vec, results: Vec, + inner_results: Vec, kind: AdapterKind, ) -> AdapterId { let id = AdapterId(self.adapters.len()); @@ -377,6 +379,7 @@ impl NonstandardWitSection { id, params, results, + inner_results, kind, }, ); diff --git a/crates/cli/tests/reference.rs b/crates/cli/tests/reference.rs index 4e0f806a4d7..e09d0d8f0b9 100644 --- a/crates/cli/tests/reference.rs +++ b/crates/cli/tests/reference.rs @@ -66,12 +66,14 @@ fn runtest(test: &Path) -> Result<()> { [dependencies] wasm-bindgen = {{ path = '{}' }} + wasm-bindgen-futures = {{ path = '{}/crates/futures' }} [lib] crate-type = ['cdylib'] path = '{}' ", repo_root().display(), + repo_root().display(), test.display(), ); let interface_types = contents.contains("// interface-types"); @@ -93,11 +95,7 @@ fn runtest(test: &Path) -> Result<()> { .join("reference_test.wasm"); let mut bindgen = Command::cargo_bin("wasm-bindgen")?; - bindgen - .arg("--out-dir") - .arg(td.path()) - .arg(&wasm) - .arg("--no-typescript"); + bindgen.arg("--out-dir").arg(td.path()).arg(&wasm); if contents.contains("// enable-externref") { bindgen.env("WASM_BINDGEN_EXTERNREF", "1"); } @@ -112,10 +110,14 @@ fn runtest(test: &Path) -> Result<()> { let wat = sanitize_wasm(&wasm)?; assert_same(&wat, &test.with_extension("wat"))?; } else { - let js = fs::read_to_string(td.path().join("reference_test_bg.js"))?; - assert_same(&js, &test.with_extension("js"))?; - let wat = sanitize_wasm(&td.path().join("reference_test_bg.wasm"))?; - assert_same(&wat, &test.with_extension("wat"))?; + if !contents.contains("async") { + let js = fs::read_to_string(td.path().join("reference_test_bg.js"))?; + assert_same(&js, &test.with_extension("js"))?; + let wat = sanitize_wasm(&td.path().join("reference_test_bg.wasm"))?; + assert_same(&wat, &test.with_extension("wat"))?; + } + let d_ts = fs::read_to_string(td.path().join("reference_test.d.ts"))?; + assert_same(&d_ts, &test.with_extension("d.ts"))?; } Ok(()) diff --git a/crates/cli/tests/reference/add.d.ts b/crates/cli/tests/reference/add.d.ts new file mode 100644 index 00000000000..a8ee5f2e475 --- /dev/null +++ b/crates/cli/tests/reference/add.d.ts @@ -0,0 +1,14 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +* @param {number} a +* @param {number} b +* @returns {number} +*/ +export function add_u32(a: number, b: number): number; +/** +* @param {number} a +* @param {number} b +* @returns {number} +*/ +export function add_i32(a: number, b: number): number; diff --git a/crates/cli/tests/reference/anyref-empty.d.ts b/crates/cli/tests/reference/anyref-empty.d.ts new file mode 100644 index 00000000000..5abcaf33bb3 --- /dev/null +++ b/crates/cli/tests/reference/anyref-empty.d.ts @@ -0,0 +1,2 @@ +/* tslint:disable */ +/* eslint-disable */ diff --git a/crates/cli/tests/reference/anyref-import-catch.d.ts b/crates/cli/tests/reference/anyref-import-catch.d.ts new file mode 100644 index 00000000000..3e2ffc07207 --- /dev/null +++ b/crates/cli/tests/reference/anyref-import-catch.d.ts @@ -0,0 +1,5 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +*/ +export function exported(): void; diff --git a/crates/cli/tests/reference/anyref-nop.d.ts b/crates/cli/tests/reference/anyref-nop.d.ts new file mode 100644 index 00000000000..b9f9648536e --- /dev/null +++ b/crates/cli/tests/reference/anyref-nop.d.ts @@ -0,0 +1,5 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +*/ +export function foo(): void; diff --git a/crates/cli/tests/reference/async-number.d.ts b/crates/cli/tests/reference/async-number.d.ts new file mode 100644 index 00000000000..d7204543623 --- /dev/null +++ b/crates/cli/tests/reference/async-number.d.ts @@ -0,0 +1,6 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +* @returns {Promise} +*/ +export function foo(): Promise; diff --git a/crates/cli/tests/reference/async-number.rs b/crates/cli/tests/reference/async-number.rs new file mode 100644 index 00000000000..2948c43667d --- /dev/null +++ b/crates/cli/tests/reference/async-number.rs @@ -0,0 +1,6 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub async fn foo() -> u32 { + 1 +} diff --git a/crates/cli/tests/reference/async-void.d.ts b/crates/cli/tests/reference/async-void.d.ts new file mode 100644 index 00000000000..83335802b7e --- /dev/null +++ b/crates/cli/tests/reference/async-void.d.ts @@ -0,0 +1,6 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +* @returns {Promise} +*/ +export function foo(): Promise; diff --git a/crates/cli/tests/reference/async-void.rs b/crates/cli/tests/reference/async-void.rs new file mode 100644 index 00000000000..73f4a0ff586 --- /dev/null +++ b/crates/cli/tests/reference/async-void.rs @@ -0,0 +1,4 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub async fn foo() {} diff --git a/crates/cli/tests/reference/empty.d.ts b/crates/cli/tests/reference/empty.d.ts new file mode 100644 index 00000000000..5abcaf33bb3 --- /dev/null +++ b/crates/cli/tests/reference/empty.d.ts @@ -0,0 +1,2 @@ +/* tslint:disable */ +/* eslint-disable */ diff --git a/crates/cli/tests/reference/import-catch.d.ts b/crates/cli/tests/reference/import-catch.d.ts new file mode 100644 index 00000000000..3e2ffc07207 --- /dev/null +++ b/crates/cli/tests/reference/import-catch.d.ts @@ -0,0 +1,5 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +*/ +export function exported(): void; diff --git a/crates/cli/tests/reference/nop.d.ts b/crates/cli/tests/reference/nop.d.ts new file mode 100644 index 00000000000..c285bc0f2f6 --- /dev/null +++ b/crates/cli/tests/reference/nop.d.ts @@ -0,0 +1,5 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +*/ +export function nop(): void; diff --git a/crates/cli/tests/reference/string-arg.d.ts b/crates/cli/tests/reference/string-arg.d.ts new file mode 100644 index 00000000000..701afc6b2d4 --- /dev/null +++ b/crates/cli/tests/reference/string-arg.d.ts @@ -0,0 +1,6 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +* @param {string} a +*/ +export function foo(a: string): void; diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 090dc2a155d..2c2eecd33a8 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -115,6 +115,7 @@ macro_rules! shared_api { struct Function<'a> { arg_names: Vec, + asyncness: bool, name: &'a str, generate_typescript: bool, } diff --git a/crates/typescript-tests/Cargo.toml b/crates/typescript-tests/Cargo.toml index 61efd4c1c98..e3afb5a7fca 100644 --- a/crates/typescript-tests/Cargo.toml +++ b/crates/typescript-tests/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] wasm-bindgen = { path = '../..' } +wasm-bindgen-futures = { path = '../futures' } web-sys = { path = '../web-sys', features = [ 'HtmlElement', 'Node', 'Document' ] } js-sys = { path = '../js-sys' } diff --git a/crates/typescript-tests/src/lib.rs b/crates/typescript-tests/src/lib.rs index 6c6db10e2f2..ad8a1c3fbf8 100644 --- a/crates/typescript-tests/src/lib.rs +++ b/crates/typescript-tests/src/lib.rs @@ -3,6 +3,7 @@ pub mod getters_setters; pub mod omit_definition; pub mod opt_args_and_ret; pub mod optional_fields; +pub mod simple_async_fn; pub mod simple_fn; pub mod simple_struct; pub mod typescript_type; diff --git a/crates/typescript-tests/src/simple_async_fn.rs b/crates/typescript-tests/src/simple_async_fn.rs new file mode 100644 index 00000000000..34f64879ac8 --- /dev/null +++ b/crates/typescript-tests/src/simple_async_fn.rs @@ -0,0 +1,9 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub async fn async_greet(_: String) {} + +#[wasm_bindgen] +pub async fn async_take_and_return_bool(_: bool) -> bool { + true +} diff --git a/crates/typescript-tests/src/simple_async_fn.ts b/crates/typescript-tests/src/simple_async_fn.ts new file mode 100644 index 00000000000..51fdb4d7d03 --- /dev/null +++ b/crates/typescript-tests/src/simple_async_fn.ts @@ -0,0 +1,6 @@ +import * as wbg from '../pkg/typescript_tests'; +import * as wasm from '../pkg/typescript_tests_bg.wasm'; + +const wbg_async_greet: (a: string) => Promise = wbg.async_greet; +const wasm_async_greet: (a: number, b: number) => number = wasm.async_greet; +const async_take_and_return_bool: (a: boolean) => Promise = wbg.async_take_and_return_bool; diff --git a/src/convert/closures.rs b/src/convert/closures.rs index 3887e46100a..97755b8ee46 100644 --- a/src/convert/closures.rs +++ b/src/convert/closures.rs @@ -53,6 +53,7 @@ macro_rules! stack_closures { inform($cnt); $(<$var as WasmDescribe>::describe();)* ::describe(); + ::describe(); } } @@ -101,6 +102,7 @@ macro_rules! stack_closures { inform($cnt); $(<$var as WasmDescribe>::describe();)* ::describe(); + ::describe(); } } )*) @@ -166,6 +168,7 @@ where inform(1); <&A as WasmDescribe>::describe(); ::describe(); + ::describe(); } } @@ -217,5 +220,6 @@ where inform(1); <&A as WasmDescribe>::describe(); ::describe(); + ::describe(); } } diff --git a/tests/wasm/futures.js b/tests/wasm/futures.js index 487a98a259f..9da0aace80d 100644 --- a/tests/wasm/futures.js +++ b/tests/wasm/futures.js @@ -10,9 +10,9 @@ exports.call_exports = async function() { 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/); + await assert.rejects(wasm.async_throw_7(), /7/); + await assert.rejects(wasm.async_throw_custom(), /\[object Object\]/); + await assert.rejects(wasm.async_throw_message(), /async message/); }; exports.call_promise = async function() { diff --git a/tests/wasm/futures.rs b/tests/wasm/futures.rs index 47c32f69277..32a9edbfb5e 100644 --- a/tests/wasm/futures.rs +++ b/tests/wasm/futures.rs @@ -70,18 +70,18 @@ pub async fn async_return_6() -> Result { } #[wasm_bindgen] -pub async fn async_return_7() -> Result { - Ok(AsyncCustomReturn { val: 7 }) +pub async fn async_throw_7() -> Result { + Err(7.into()) } #[wasm_bindgen] -pub async fn async_return_8() -> Result { - Ok(AsyncCustomReturn { val: 8 }) +pub async fn async_throw_custom() -> Result { + Err(AsyncCustomReturn { val: 8 }.into()) } #[wasm_bindgen] -pub async fn async_throw() -> Result<(), js_sys::Error> { - Err(js_sys::Error::new("async message")) +pub async fn async_throw_message() -> Result<(), JsValue> { + Err(js_sys::Error::new("async message").into()) } #[wasm_bindgen_test]