ReviewOS

zig-utils/zig-js

Compiler: lower member logical assignment references

#705
Closed chris opened this 9 days ago ·
9 days ago

Parents: #465, #498 Depends on: #706 for top-level program expressions Related: #704, #491

Problem

Member logical assignments are represented explicitly so the base and computed property key resolve exactly once, but the bytecode compiler rejects every such node. obj.x &&= rhs, obj[key] ||= rhs, and obj[key] ??= rhs therefore fall back even though function activations already provide the state and VM predicates/property operations needed to preserve one-time reference resolution.

Program-mode bytecode has no activation-local scratch today. #706 owns that independent stack/runtime prerequisite; #705 must keep direct top-level member logical assignment causally rejected until it lands rather than storing compiler state in shared/global bindings.

Scope

  • Lower ordinary named and computed member targets for all three logical-assignment operators in plain, generator, and async function activations.
  • Evaluate the base once, the computed key expression once, and observable ToPropertyKey once before GetValue; retain the resolved reference across recursion and RHS suspension.
  • Preserve RequireObjectCoercible, getter/setter, proxy, abrupt-completion, short-circuit, and assignment-result ordering.
  • Keep top-level program and super-property logical assignment explicitly unsupported until #706 and a receiver-aware super write opcode exist.

No-workaround rules

  • No repeated base/key/coercion evaluation, eager RHS, truthiness substitution for ??=, skipped accessors/proxies, AST rewriting, tree-walker callback from bytecode, or syntax-specific fast path.
  • No global/environment scratch shared across program executions. Compiler-owned function reference state must remain activation-local and GC-rooted across recursion and generator/async suspension.

Acceptance

  • Named/computed &&=, ||=, and ??= compile across plain-function, generator, and async admission; program mode retains a causal #706 rejection.
  • Exact witnesses cover base/key/get/RHS/set ordering, every short-circuit class, throwing coercion/getter/RHS/setter, proxies, Symbol keys, recursion, and computed-key one-shot behavior.
  • Generator resume and async settlement preserve the resolved reference when the RHS suspends.
  • Forced tree-walker and required-bytecode function differentials match; direct program and super targets retain causal unsupported admission reasons.
  • Focused compiler/frontend, full units, applicable TSan, and exact relevant Test262 before → after accounting pass with no regressions.
  • Parent/dependency issues and the landing commit are cross-linked with quantified evidence.
9 days ago

Implemented and landed on main in feat(compiler): lower member logical assignments (#705).

Plain frames and generator/async activation environments now retain one resolved ordinary member Reference across &&=, ||=, and ??=. The implementation preserves base/key expression order, one observable ToPropertyKey, getter/proxy reads, exact short-circuit predicates, RHS suspension, setter/proxy writes, Symbol keys, abrupt completion, recursive re-entry, and property-base errors. Direct program expressions remain explicitly rejected behind #706; super remains behind its receiver-aware write boundary.

Evidence:

  • focused Debug matrix: 12/12 relevant compiler/admission/runtime checks passed, 0 failed/leaked;
  • focused TSan: 12/12 passed, 0 failed/leaked;
  • complete focused frontend: 12/12 passed;
  • full Debug units: 1,802 passed / 1 platform skip / 0 failed / 0 leaked across 6 shards;
  • exact parent/candidate test/language/expressions/logical-assignment: 0 fail / 78 pass → 0 / 78, byte-identical diagnostics and nonzero denominators;
  • parent/candidate Test262 SHA-256: cef821d2… / d69877c5….

No Promise, microtask, Worker, job, queue, shared Map/Set iterator-cursor, or program-stack implementation was changed.

9 days ago

Follow-up #707 reused the activation-safe member-reference contract from #705 and landed in feat(compiler): lower member compound assignments (#707). The shared compiler helpers now keep logical and compound assignment aligned on one base/key/coercion/GetValue/PutValue sequence.

Sign in to comment on this issue.