Repository navigation
Conversation
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.
Fixes #29197.
Fixes #27335.
Repro
Root cause
The
accessorclass field modifier (TC39 Stage 4 / TypeScript 4.9+) wasgated on Bun's internal
standard_decoratorsfeature flag in the parser.Under
experimentalDecorators: true,standard_decoratorsisfalse,so the parser never accepted the keyword and fell through to treat the
next token as a property name, choking on
x.The
accessorkeyword is a standalone proposal and is valid classsyntax regardless of decorator model.
Fix
All changes are in the Rust parser (
src/js_parser,src/ast):Parser (
parse_property.rs) — drop thestandard_decoratorsgateon the
p_accessorbranch. Add TC39's[no LineTerminator here]restriction so
class C { accessor\n y = 1 }parses as two fields viaASI (matching the existing
.p_asynccheck).Lowering routing (
parse/mod.rs) — JSC does not parseaccessor,so any class with an auto-accessor must go through the existing
standard-decorator lowering (WeakMap + getter/setter). Widen
should_lower_standard_decoratorstohas_auto_accessor || (standard && has_any_decorators).Mixed legacy + accessor → clear error (
parse/mod.rs) — if a classhas both legacy (
@dec) decorators AND anaccessorfield underexperimentalDecorators: true, silently rerouting the legacy decoratorsthrough the standard-proposal runtime would be wrong. Report a clear
compile-time error instead.
Hoist ordering (
g.rscan_be_moved) — include.AutoAccessorstatic initializers in the side-effect check so
static accessor x = sideEffect()isn't hoisted past preceding statements in the non-bundletree-shaking path.
Computed-key single evaluation (
lower_decorators.rs) — widen thecomputed-key hoist (previously gated on
ts_decorators.len > 0) toundecorated auto-accessors, so
accessor [k()] = 1evaluatesk()exactly once instead of twice.
Anonymous
export default class { accessor x = 1 }name injection isalready handled on main by the
has_decorators || should_lower_standard_decoratorscheck in
visit_stmt.rs.Verification
Regression test
test/regression/issue/29197.test.tscovers 10 scenarios:accessorwithpublic/private/protected/static/readonlymodifiersaccessorin a.tsfile with no tsconfig@dec accessorin standard-decorators modeaccessoremits the clear errorstatic accessor: direct access works, subclass access throws (TC39 spec)accessorin a class expressionaccessor(two fields, not one auto-accessor)static accessor x = sideEffect()evaluates in source orderexport default class { static accessor x = 1 }doesn't panicaccessor [k()]evaluates the key exactly onceRebase note
The Zig parser this PR originally targeted was fully removed from main
(migrated to Rust). All fixes were re-applied to the Rust parser; the
obsolete Zig-side changes were dropped. The final diff is Rust-only.
[review] gate passed · iteration 18 · 5 files touched
fails on main (without fix)
passes on PR (with fix)
diff hotspot
gate history · 1 passed · 0 rejected · iteration 18
evidence per changed file
root cause · written by the author bot
The parser only recognized the
accessorkeyword on class fields when the standard decorators feature was enabled, so under experimentalDecorators the token fell through to generic parsing and produced syntax errors. The fix removes that guard soaccessoris parsed as an auto-accessor property in any class context, and adds a lowering pass that rewrites each auto-accessor into a private backing field with synthesized get and set members for both class statements and class expressions. This preserves decorator and TypeScript metadata, evaluates computed keys once via hoisted temporaries, …