Skip to content

compiler: fused ++/-- on a spilled local targets R0 instead of the spill slot #27

Description

@mparrett

Summary

The fused ++/-- path reads a local's .Register without checking IsSpilled, so an increment/decrement on a spilled local targets R0 instead of the variable's spill slot. The variable never updates (and R0 is corrupted).

Where

pkg/compiler/compile_expression.go:705 and :719 set identInfo.targetReg = symbolRef.Register for a local without an !IsSpilled guard; that reg is later used by emitFusedUpdate (~line 883). A spilled symbol's Register defaults to 0 (!= nilRegister = 255), so it aliases R0.

Repro (270 locals force the counter to spill)

function f(): number {
  let v0 = 0; /* ... let v1 .. v269 ... */ let v269 = 269;
  let c = 100;
  c++;
  return c;   // returns 100 — the ++ hit R0, not c's spill slot
}

Actual: 100. Expected: 101. (c--, --c, ++c behave the same way.)

Relationship

Surfaced during the audit for #19. Same class of defect (code reusing a spilled symbol's zero-valued Register), but on the fused-update use path, not a binding-init path — so it was deliberately left out of #19's scope. Fix: check IsSpilled first and route the fused update through the spill slot (emitLoadSpill → update → emitStoreSpill), or fall back to the non-fused path for spilled locals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions