Skip to content

emit-tsd: add TSD_SKIP_EXPORTS for toolchain-owned exports; warn on unhandled multi-value returns#26966

Closed
guybedford wants to merge 1 commit into
emscripten-core:mainfrom
guybedford:tsd-skip-exports
Closed

emit-tsd: add TSD_SKIP_EXPORTS for toolchain-owned exports; warn on unhandled multi-value returns#26966
guybedford wants to merge 1 commit into
emscripten-core:mainfrom
guybedford:tsd-skip-exports

Conversation

@guybedford
Copy link
Copy Markdown
Collaborator

Today --emit-tsd asserts when it sees a wasm function with multiple return values:

assert len(functype.returns) <= 1, 'One return type only supported'

This fails for any wasm produced by a higher-level toolchain that lowers compound types to wasm-level (ptr, len)-style tuples. wasm-bindgen is the canonical case — Rust exports returning String, Vec<u8>, Result<T, E> etc. all show up as (i32, i32) in the wasm. The user-facing JS surface for those exports isn't the wasm export at all; it's a JS wrapper installed via --js-library, and the wrapping toolchain declares the real type in its own .d.ts. emcc has no way to recover that type from the wasm signature, so guessing (e.g. a tuple) is wrong and silently skipping is opaque.

Give the toolchain a way to tell emcc which exports it owns: a new TSD_SKIP_EXPORTS setting listing wasm export names to omit from --emit-tsd. Exports on the list are skipped silently. Multi-value-return exports not on the list are skipped with an actionable warning rather than asserting, so the toolchain hears about anything it forgot to declare without the build crashing. Single- and void-return exports are typed as before.

This composes naturally with downstream .d.ts mergers (e.g. wasm-pack's emscripten flow) which layer the toolchain's .d.ts on top of emcc's to supply the real types for the skipped exports.

Tests cover the four scenarios: skipped export omitted with no warning, unhandled multi-value export omitted with a warning, unknown skip-list entries silently ignored, and the existing single-return path unchanged.

…nhandled multi-value returns

When a higher-level toolchain (e.g. wasm-bindgen) lowers compound types
to wasm-level (ptr, len) tuples and installs its own JS wrapper via
--js-library, emcc has no way to recover the user-facing JS type from
the raw wasm signature.  Today --emit-tsd asserts on those exports.

Add TSD_SKIP_EXPORTS so the toolchain can list the exports it owns.
Multi-value-return exports not on the list are skipped with a warning
instead of crashing the build.
@sbc100 sbc100 requested a review from brendandahl May 16, 2026 00:33
@sbc100
Copy link
Copy Markdown
Collaborator

sbc100 commented May 16, 2026

Welcome @guybedford ! Thanks for the PR.

Assigning @brendandahl who has done most of the tsc compiler work.

My main concern here is the addition of a new setting in the compiler. Every time we add another entry to settings.js I cry a little inside and I'm always looking instead to remove entries. I wonder if there is some way to go with sensible hardcoded defaults, and see how that gets us? i.e. do we really need the flexibility of a user-facing setting here?

@guybedford
Copy link
Copy Markdown
Collaborator Author

Thanks @sbc100 and @brendandahl for taking a look. Actually on second thoughts I think we can avoid this approach entirely by just maintaining the typing entirely on the wasm bindgen side here. That is, wasm-pack calling to emcc can generate the typescript itself from wasm-bindgen directly instead of trying to do hybrid definitions and introducing a new setting, at least while C++ linking is not in play.

@walkingeyerobot's work on the other hand was based on having emcc drive the entire process with both C++ and Rust, and as the final emitter, which makes sense why it needed to be more directly integrated instead.

Closing for now, but if this comes up again I'll let you know.

@guybedford guybedford closed this May 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants