ReviewOS

zig-utils/zig-js

Parser: early-error queries skip class heritage and computed names

#923
Closed glennmichael123 opened this 9 days ago ·
9 days ago

Parent: #904. Related: #899, #920, #921, #922.

Reproduced on 1adf483

Compile-only Function-constructor probes match 6/16 specified outcomes in both tree-walker and required-VM modes; independent Node/V8 matches 16/16. All ten invalid programs are accepted. All six valid controls already pass. These are focused probes, not test262 totals.

Examples that must throw SyntaxError during compilation, even if the function or method is never called:

Function('class C extends super() {}');
Function('class C { [super.key]() {} }');
Function('function f() { return class extends super.Object {}; }');
Function('class C extends Object { m() { return class extends super() {}; } }');
Function('async function f(x = class extends (await Object) {}) {}');
Function('async function f(x = class { [await 0]() {} }) {}');
Function('function* f(x = class extends (yield Object) {}) {}');
Function('function* f(x = class { [yield 0]() {} }) {}');

The remaining two failing shapes put a SuperProperty in global class heritage and a SuperCall in a global computed method name.

Root cause and specification boundary

The shared parser early-error visitor wraps its entire class-expression case in scan_descend_class_expr. Ordinary-function, method, global/eval, and parameter suspension queries leave that flag false, skipping not only class bodies but also heritage and computed names.

ECMA-262 2026 8.5.1 Contains and 8.5.2 ComputedPropertyContains require these outer-context expressions to be visited. Method bodies, field initializers, and static blocks are separate boundaries for these Contains queries. 15.7.9 ContainsArguments has a distinct traversal rule and must not be weakened while correcting the class boundary.

Fix and verification requirements

  • Visit heritage and computed keys for every active query, without letting the class-body policy disable them.
  • Preserve the separate initializer/static-block policy for ContainsArguments; do not impose outer SuperProperty or suspension bans on a nested class's own method/initializer context.
  • Preserve legal derived-constructor super use in heritage, method-owned super properties in computed keys, await/yield in permitted function bodies, and nested constructors' own super calls.
  • Add script/module parser fixtures and Function/eval checks in both modes, including rejection before earlier side effects.
  • Run serial bounded focused units and exact-before/after relevant class, arrow, async, generator and eval corpus checks. Retain raw failure lists and denominators.

No fix or new corpus improvement is claimed yet. The separately verified arrow-boundary fix in #922 is already pushed and remains a distinct change.

9 days ago

Landed in 877f25b on origin/main under the configured user identity, with no trailers. Related: #904, #899, #922.

The parser now always visits class heritage and computed names for the enclosing early-error queries. ContainsArguments separately visits initializers/static blocks with outer super/await/yield restrictions disabled; method and constructor bodies retain their own boundaries. There is no runtime workaround and no execution-tier-specific patch: the shared parse rejects before either tier executes.

Verification against exact parent 1adf4837:

  • Focused Debug units: 76 passed, 0 skipped, 0 failed, 0 leaked. New parser fixtures cover 14 invalid and 12 valid programs in script/module modes; Node/V8 independently confirms all 26 compile outcomes.
  • Frozen compile-only probe: 6/16 → 16/16 in both tree and required-VM modes, ten distinct incorrect acceptances fixed. Eval/Function units also require rejection before preceding side effects. Valid own-class super, arguments, await/yield, and nested constructor controls pass.
  • test262 at 4249661388e5d3f92a85186213da140a6481490f: 10,224 passed / 0 failed before and after, zero flips and no regressions in the ten measured scopes below. This is not a full corpus or native-JIT claim.
ScopeBefore pass/failAfter pass/fail
statements/class4367/04367/0
expressions/class4059/04059/0
expressions/arrow-function343/0343/0
expressions/async-arrow-function60/060/0
statements/async-function74/074/0
expressions/async-function93/093/0
statements/generators, dstr filter186/0186/0
expressions/generators, dstr filter186/0186/0
language/eval-code347/0347/0
built-ins/Function509/0509/0

Serial verification used real clean dependencies (zig-gc 0285ef8; zig-regex c60344d), not the local noncollecting GC stub. Production source files match the tested checkout exactly. Temporary compile-time unit selectors were isolated and removed after verification. The guard recorded 2813 MB peak process-tree footprint and 31% host memory low-water under a 3072 MB limit.

Local raw evidence retained in /private/tmp/zig-js-class-query-landed-evidence.Tv2S62/: both source files, complete gate script/log, independent reference, frozen probe, per-scope logs and empty regression lists. Runner SHA-256: parent 25721ef6d3aebd6840ddd6d293e84317fb3300f84a19c9af33e9ef8af4b89cc7; candidate 26ab0e991077cd646f02c7d1bc8a88a35edd283c7ac10084bf658520236783a0.

README/global conformance totals remain unchanged because this was targeted verification, not a new full-corpus publication.

Sign in to comment on this issue.