Stream: jco

Topic: reject/resolve import name collision w instantiation helper


view this post on Zulip Mike M (Sep 17 2026 at 17:16):

Hi — looking for a sanity check before filing a GitHub issue.

Summary

With jco transpile --instantiation async, importing a WIT function named
reject (also resolve, and likely promise / gen / runNext /
maybeSyncReturn) produces JS that fails to load:

SyntaxError: Identifier 'reject' has already been declared

reject / resolve are legal WIT identifiers (not WIT keywords, not JS
keywords). The collision is with locals that the instantiation helper emits
in the same function scope.

WIT shape

package demo:jco;

interface respondent {
    reject: func(id: u32);
}

world demo {
    import respondent;
    export run: func(id: u32);
}

Observed

Generated instantiate() contains, in one scope:

const { reject } = imports['demo:jco/respondent'];
// ...
let promise, resolve, reject;   // instantiation helper

Expected

Either the import or the helper locals are deconflicted (e.g. reject$1), same as other name clashes — module loads cleanly.

Root cause (best guess)

Imports go through LocalNames in render_imports, but the helper is a raw string in transpile_bindgen.rs (let promise, resolve, reject; plus gen / runNext / maybeSyncReturn) and those names are never registered via exclude_globals / create_once. So the deconflicter never sees them.

Specific to --instantiation mode (default ESM puts the helper in a $init IIFE, so this is shadowing rather than redeclaration). Still present on bindgen from main last we checked, and on @bytecodealliance/jco@1.10.2.

Related precedent: #1898 / #1899 (exported eval not sanitized) — same “bindings must produce valid JS for any legal WIT name” principle.

Minimal repro

No wasm toolchain needed:

npm i @bytecodealliance/jco@1.10.2   # also fails on newer in our checks up to 1.34.0
# demo.wit as above
jco transpile demo.wit --stub --instantiation async --no-typescript -o out
node -e "import('./out/demo.js').then(() => console.log('OK'), e => console.log('FAIL:', e.message))"
# FAIL: Identifier 'reject' has already been declared

Control: rename reject → anything else → OK.

view this post on Zulip Victor Adossi (Sep 17 2026 at 17:28):

Hey @Mike M thanks for the report -- yeah that is definitely worth filing an issue for! I think basically the list that needs to be updated is here, but definitely this is worth filing an issue for and having the repro will be great to add to Jco.

view this post on Zulip Mike M (Sep 17 2026 at 18:01):

https://github.com/bytecodealliance/jco/issues/2134

view this post on Zulip Victor Adossi (Sep 18 2026 at 00:43):

Hey @Mike M Thanks for filing the issue! Do you want to take a stab at it? If not I'm happy to get to it (hopefully today/by monday!)

view this post on Zulip Mike M (Sep 18 2026 at 17:38):

yeah, sure! I wouldn't have presumed, but I'm happy to. Gimme a few.

view this post on Zulip Mike M (Sep 18 2026 at 17:58):

One thought I'd like your input on: since this isn't a forbidden JS keyword, it's bindgen’s own helper locals that weren’t reserved. So what do you think about either:

1) Extend global_names (or I could create a sibling call when instantiation/$init is emitted) with the helper locals:
promise, resolve, reject, gen, runNext, maybeSyncReturn, normalizeInstantiationError

Then an imported reject becomes reject$1 only when it actually collides — which is how LocalNames seem to work?

or...

2) perhaps even better (for a future where this chunk of helper code is modified again), leverage LocalNames directly and wrap those keyword in local_names.create_once(...), which seems to be the precedent for preventing collisions in the bindings, e.g.,

let promise = local_names.create_once("promise");
let resolve = local_names.create_once("resolve");
let reject  = local_names.create_once("reject");
let run_next = local_names.create_once("runNext");
// ...
uwrite!(output, "
  let {promise}, {resolve}, {reject};
  function {run_next} (value) {{ ... }}
  ...
", ...);

This has the benefit of not adding the name to global_names once, only to have another name pop up later that also needs to be added to global_names and leads to this same bug.

Thoughts?

view this post on Zulip Mike M (Sep 19 2026 at 02:29):

Here's the PR if you want to look at the impl I suggest above. Happy to tweak/pivot as needed. Pls advise when you have a moment.
https://github.com/bytecodealliance/jco/pull/2135

view this post on Zulip Victor Adossi (Sep 21 2026 at 09:18):

Thanks for the PR! IMO I'm OK with the approach -- these local names are just slightly different from that initial global names list, and I think what you worked out there is pretty reasonable.

It's a bit of a different paradigm to deal with, but I think the separation is pretty easy to reason about for anyone stumbling upon it -- as soon as someone sees instantiation_helper_names it would be pretty obvious what is happening!

Thanks again for putting a PR up for this -- it looks like there was a slight regression, addin ga PR to fix that now

view this post on Zulip Mike M (Sep 21 2026 at 15:58):

Thank you!
something was still wrong. I just pushed an adjusted commit. I'll watch it.

view this post on Zulip Mike M (Sep 21 2026 at 16:20):

looks like my commit message was making commitinit unhappy.
The other CI fail looks unrelated.

view this post on Zulip Victor Adossi (Sep 21 2026 at 16:54):

Hey also, yes, apologies one of the CI failures is actually has nothing to do with your PR! I've approved the CI run and we should be able to get this merged in soon

view this post on Zulip Mike M (Sep 21 2026 at 20:28):

That was fast! :) Thanks for your help, @Victor Adossi !

view this post on Zulip Victor Adossi (Sep 22 2026 at 02:05):

no worries! Still need to get this out so hopefully today or tomorrow we'll have new versions across the ecosystem (jco-transpile & jco) so that this can be usable from a proper release!

view this post on Zulip Victor Adossi (Sep 24 2026 at 16:00):

Hey @Mike M so Jco 1.35.0 has the released code!

https://www.npmjs.com/package/@bytecodealliance/jco/v/1.35.0

Would love if you could confirm things are fixed!

view this post on Zulip Mike M (Sep 24 2026 at 17:28):

Everything looks good from here @Victor Adossi ! Thanks so much for your support and speedy integration. Much appreciated! Y'all are killin' it! :)


Last updated: Oct 11 2026 at 02:20 UTC