Repository navigation
fix(parser): keep decorated private assignment targets as references - #217
Merged
vincentkoc merged 1 commit intoOct 31, 2026
Merged
Conversation
A decorated private member is extracted from the class. Plain assignment already became __privateSet. Compound assignment, update operators, destructuring, and for-in/of heads were left as a call or as a private name outside the class, so the engine threw SyntaxError. Lower those forms to __privateWrapper(...)._, a property reference. A direct assignment stays __privateSet. A decorated private method still reads as the method and throws on write. Bump the runtime transpiler cache so cached output from before this lowering is not reused. The new helper is the last runtime.js export so existing bundle debugId hashes stay the same. Reported upstream as oven-sh/bun issue 47043. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
This was referenced Oct 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
A decorated private member is taken out of the class. A plain write,
this.#p = value, was already lowered to__privateSet. Compound assignment (+=,&&=,||=,??=),++and--, destructuring, andfor (this.#p of/in ...)were left as a call, or as a#pname outside the class. Loading the file then throwsSyntaxError: Left side of assignment is not a reference, orCannot reference undeclared private names.Those forms now lower to
__privateWrapper(object, member, setter, getter)._. That property is a real assignment target: the getter reads the member and the setter writes it. A directthis.#p = valuestays__privateSet. When=is a destructuring default ({ 0: this.#p = 1 }), the left side stays a reference, because a call cannot be a destructuring target. Only private names that the decorator lowering extracted are rewritten, so an undecorated#uin the same class still behaves as a private field.A decorated private method reads back the method after the brand check. Passing the method itself as the getter would call it. A write still throws, because the storage is a
WeakSetand has no setter.Field initializers still go through
__privateAdd, so an accessor decorator's setter does not run for the initializer. It runs for later assignments.The runtime transpiler cache version is now 45, so output cached before this lowering is not reused.
This is the bug reported in oven-sh#47043. oven-sh#42651 is an open change for the same bug that expands
this.#p += 1into a get plus a set, and uses the wrapper only for other receivers.How did you verify your code works?
USE_SYSTEM_BUN=1 bun test test/bundler/transpiler/private-decorator-assign.test.tson Bun 1.4.4 fails withSyntaxError: Left side of assignment is not a referenceatthis.#p += 1.bun run build:release test test/bundler/transpiler/private-decorator-assign.test.tspasses. The fixture is a.jsfile. The same source in a.tsfile does not hit this bug, which is why the existing decorator suite did not catch it. The run covers plain assignment, compound and logical assignment (including short-circuit), prefix and postfix update, object and array destructuring, rest, defaults,for-of,for-in, a wrapping accessor, an undecorated private next to a decorated one, and a decorated private method.bun run build:release test test/regression/issue/cyclic-imports-async-bundler.test.jspasses.__privateWrapperis the last export inruntime.js, so the part indexes of__esmand__promiseAlldo not move and that snapshot'sdebugIdstays the same.cargo check -p bun_ast -p bun_js_parser --offline --testspasses. The sorted runtime-import unit test does not link under a rawcargo testhere, because that link does not pull in mimalloc.bun bdcannot run on this machine.scripts/build/deps/webkit-artifacts.jsonhas no macOS arm64 debug or asan WebKit tarball, so the debug build stops before compile.