Parents: #465. Discovered by the context-field audit in #795; related to #791's suspended/native root audit.
Reproduced defects
Both unmodified main e1afde2 and the #795 parameter-metadata patch fail these probes identically:
class C {
#x = 7;
*read(a = eval("this.#x")) { yield a; }
}
new C().read().next().value; // expected 7; SyntaxError: eval: UnexpectedToken at 1:8The corresponding async-generator method throws the same SyntaxError at its eager parameter initialization.
function* gen(a = eval("arguments.length")) { yield a; }
class C { field = gen().next().value; }
new C().field; // expected 0; SyntaxError: arguments not allowed in a field initializerMoving that eval into the generator body reproduces the same incorrect field-initializer restriction. An ordinary generator has its own function context even when invoked/resumed from a field initializer.
Root and scope
Ordinary function entry installs the function's private-name map and clears or lexically restores field-initializer context. The suspendable parameter makers and body-resume boundaries do not consistently establish those fields. #795 fixes formal-name/strictness/parameter-phase metadata, not this private/field context gap.
PerformEval derives field-initializer restrictions from the current this-environment's function and takes the direct eval's private environment from its running execution context.
Acceptance
- Install the callee's exact private environment for generator, async-function, and async-generator parameter evaluation and body execution.
- Preserve lexical field-initializer context for arrows while preventing ordinary suspendable functions from inheriting the caller's restriction.
- Restore caller context on normal completion, abrupt completion, suspension/resumption, reentrant eval, and allocation failure.
- Cover same-spelled private names in unrelated classes, nested classes/calls, genuinely forbidden field eval, and paired tree-walker/required-bytecode execution.
- Keep all retained managed edges and native borrowed caller state correctly rooted under moving GC and verify relevant no-GIL/TSan paths.
- Measure the pinned corpus impact, run integration gates, and land a linked conventional commit.
Reuse existing native suspend/resume, stack, queue, and job ownership; no lifecycle redesign or permissive eval fallback.
Local audit evidence: /tmp/zig-js-795-params.qYytM4/context-audit.log and its four audit-*.js probes. These are local diagnostics, not published conformance counts.
Landed implementation and evidence
8a1398ff — fix(eval): retain lexical private contexts across suspension (#797) is on origin/main, authored and committed by Chris, without trailers.
The fix captures lexical private environments for all functions and VM closures, preserves nested-class shadowing, installs/restores callee context at parameter and resume boundaries, validates exact private names before eval side effects, and isolates indirect eval and dynamic constructors. Maps are immutable Context-arena metadata, not new moving managed edges. Existing native resume, stack, queue, job, and root ownership is unchanged; #791 remains a separate native-borrow audit.
Local results against e0ed6eb and pinned Test262 4249661:
- 24 focused paired-mode witnesses: 5 -> 24 pass. Includes repeated suspension, async completion, private shadowing, escaped closures, forbidden field eval, and indirect/dynamic isolation.
- 13 language subtrees: 11,494 pass / 0 fail, unchanged. Five eval/dynamic-constructor subtrees: 581 pass / 2 existing fail, unchanged. All 18 diagnostic logs are byte-identical: 0 pinned test262 flips; no regressions in this measured scope.
- 9,643 eligible positive paired corpus files: 8,475 pass / 1,168 existing required-bytecode fail, with identical failing paths. These failures are retained, not excluded or claimed implemented.
- Full four-shard Debug suite: 2,017 pass, 1 platform skip, 0 fail/leak, 397.0 s.
- ReleaseSafe + TSan, no suppressions: 4 private-context, 47 parameter, 45 generator checks pass (overlapping filters). Includes no-GIL calls, actual receiver relocation, and metadata OOM restoration.
- Seed-1 threadfuzz: 400 default + 300 verify programs, zero failures. GC inventory and format checks pass.
Evidence index: /tmp/zig-js-797-context.2QwDxk/README.md; retained 24 fixtures under witnesses/. Temporary corpus files removed. The initial GC fixture's no_candidates failure is retained; final acceptance proves the receiver address actually changes.
- Pushed required integration passes: CI run 33113309062 completed successfully.
Completed integration
CI run 33113309062 completed successfully on main commit 8a1398ffc04e9e30987f968693667c7271ca3ce1, which contains this fix. All 53 executed jobs succeeded, including all four unit and TSan-unit shards, Linux no-GIL TSan, functional/no-GIL corpus gates, fuzz profiles, ABI, Wasm, Test262 parallel, and docs. The scheduled-only nightly job was skipped, not counted as a pass. The local evidence above plus this descendant integration run completes this issue's acceptance.