ReviewOS

zig-utils/zig-js

Parser: await scans suppress lexical early errors in static-block arrows

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

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

Reproduced behavior

On main 41104a44, compile-only probes match 9/16 expected outcomes in both tree-walker and required-VM modes; independent Node/V8 matches 16/16. Seven invalid programs are accepted, while all eight valid controls and one direct parameter rejection already behave correctly. These are focused probe results, not a test262 denominator.

Minimal examples (compilation must throw SyntaxError even without invoking the arrows):

Function('class C { static { const f = () => arguments; } }');
Function('class C extends Object { static { const f = () => super(); } }');

Also reproduced with async arrows, nested arrows, destructuring defaults in an arrow body, and computed object keys in an arrow body.

Root cause

The static-block validation enables scan_forbid_await while asking the shared scanSuperAndArgs visitor to enforce three different early-error queries. Its arrow-function branch scans parameters and then returns whenever either await/yield flag is set. Skipping an arrow body is appropriate for the enclosing await/yield query, but it also drops the lexical arguments and SuperCall queries, which must continue through arrows. Ordinary functions must still stop those lexical queries.

ECMA-262 2026 sections 15.7.1 and 15.7.9 specify the distinct class-static-block and ContainsArguments rules: https://tc39.es/ecma262/2026/multipage/ecmascript-language-functions-and-classes.html#sec-class-definitions-static-semantics-early-errors

Required fix and gates

  • Model the separate query boundaries explicitly rather than letting one query's stop condition disable the others.
  • Preserve legal await inside nested async arrows and ordinary-function arguments bindings.
  • Preserve derived-constructor super bindings, including an async-arrow parameter whose default is an arrow containing a legal super call; a blanket descent could incorrectly reject this control.
  • Cover script/module parser entry points, Function construction, and eval rejection before prior side effects in tree-walker/required VM.
  • Run focused parser/context units and exact-before/after static-block, field, arrow, and async-parameter conformance checks serially with bounded resources.

No production fix or new corpus result is claimed yet.

9 days ago

Pushed 1adf483 to main under the configured Glenn identity, without trailers. The parser now separates lexical super/arguments queries from suspension queries at arrow boundaries. All 74 focused Debug tests pass with zero skips/failures/leaks; 20 invalid plus 18 valid parser fixtures are checked in script/module modes and agree with Node/V8. Runtime tests cover eval and Function rejection before side effects in both execution modes. The frozen focused differential improves 9/16 to 16/16 in each mode (7 distinct gains). Eight test262 scopes retain 9368/9368 passes before and after with zero failures: class statements 4367, class expressions 4059, arrows 343, async arrows 60, async declarations 74, async expressions 93, generator declaration/expression destructuring 186 each. This is 0 corpus flips, not a full-corpus claim. Guarded verification peaked at 1979 MB, host low-water 30%. Related class-heritage/computed-key omissions are a separate follow-up under #904.

Sign in to comment on this issue.