Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions test/other/test_emit_tsd_multivalue.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <emscripten.h>

struct Pair { int a; int b; };

// Returning a small struct by value with the experimental multi-value ABI
// causes clang to emit a wasm function with two return values (i32, i32).
// This mirrors the shape wasm-bindgen produces for e.g. `pub fn foo() -> String`
// (a ptr+len pair) on the wasm32-unknown-emscripten target.
EMSCRIPTEN_KEEPALIVE struct Pair make_pair(int a, int b) {
struct Pair p = {a, b};
return p;
}

int main() {}
15 changes: 15 additions & 0 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -3803,6 +3803,21 @@ def test_emit_tsd_wasm_only(self):
expected = 'Wasm only output is not compatible with --emit-tsd'
self.assert_fail([EMCC, test_file('other/test_emit_tsd.c'), '--emit-tsd', 'test_emit_tsd_wasm_only.d.ts', '-o', 'out.wasm'], expected)

def test_emit_tsd_multivalue(self):
# A wasm export that returns multiple values (e.g. wasm-bindgen's
# ptr+len pair for `pub fn foo() -> String`) used to crash --emit-tsd
# with `AssertionError: One return type only supported`. It should
# now surface as a TypeScript tuple return type.
self.run_process([EMCC, test_file('other/test_emit_tsd_multivalue.c'),
'-mmultivalue', '-Xclang', '-target-abi', '-Xclang', 'experimental-mv',
'--emit-tsd', 'test_emit_tsd_multivalue.d.ts',
'-sMODULARIZE', '-sEXPORT_ES6',
'-sEXPORT_KEEPALIVE',
'-o', 'test_emit_tsd_multivalue.mjs'] +
self.get_cflags())
actual = read_file('test_emit_tsd_multivalue.d.ts')
self.assertContained('_make_pair(_0: number, _1: number): [number, number];', actual)

@requires_dev_dependency('typescript')
def test_emit_tsd_heap(self):
self.run_process([EMCC, test_file('other/test_emit_tsd.c'),
Expand Down
10 changes: 7 additions & 3 deletions tools/emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,11 +695,15 @@ def create_tsd(metadata, embind_tsd):
for index, type in enumerate(functype.params):
arguments.append(f"_{index}: {type_to_ts_type(type)}")
out += f' {mangled}({", ".join(arguments)}): '
assert len(functype.returns) <= 1, 'One return type only supported'
if functype.returns:
if len(functype.returns) == 0:
ret_ts_type = 'void'
elif len(functype.returns) == 1:
ret_ts_type = type_to_ts_type(functype.returns[0])
else:
ret_ts_type = 'void'
# Multi-value returns are valid wasm (e.g. wasm-bindgen emits them
# for `pub fn foo() -> String` as a (ptr, len) pair). Surface them
# as a TS tuple type; downstream glue (or .d.ts mergers) can refine.
ret_ts_type = '[' + ', '.join(type_to_ts_type(t) for t in functype.returns) + ']'
if settings.ASYNCIFY == 2 and any(fnmatch.fnmatch(name, pat) for pat in settings.ASYNCIFY_EXPORTS):
ret_ts_type = f'Promise<{ret_ts_type}>'
out += f'{ret_ts_type};\n'
Expand Down