Skip to content

Compiled generator body: arrow functions are miscompiled (map/forEach callback not callable; captured closures crash) #669

@nickna

Description

@nickna

Summary

In compiled mode, arrow functions written inside a generator (function*) body are miscompiled. Two symptoms, both pre-existing (reproduce on origin/main / 0952d442), interpreter is correct:

1. Arrow passed as an array-method callback → TypeError: ... callback is not callable

function* g() { yield [1, 2, 3].map(x => x * 2).join(","); }
console.log(g().next().value);
// interp:   2,4,6
// compiled: Unhandled exception. TypeError: Array.prototype.map callback is not callable
//             at $Runtime.ArrayMap(...)  at <gen>d__0.MoveNext()

2. A closure created and invoked inside a generator body → Non-static method requires a target

function* gen() {
  const fns: any[] = [];
  for (let k = 0; k < 3; k++) { fns.push(() => k); }
  let out = "";
  for (let i = 0; i < fns.length; i++) { out += fns[i](); }
  yield out;
}
console.log(gen().next().value);
// interp:   012
// compiled: Unhandled exception. System.Reflection.TargetException: Non-static method requires a target.

A non-capturing arrow stored in a local and called directly does work (const f = () => 42; yield f(); yields 42), so the breakage is specific to arrows emitted as callback arguments / capturing closures within the generator MoveNext state machine.

Likely area

GeneratorMoveNextEmitter arrow-function emission (Compilation/GeneratorMoveNextEmitter.*). The $TSFunction wrapping the arrow appears to be produced without a valid target/method binding inside the generator state machine (mirrors the kind of state-machine arrow-emission parity gaps tracked for async emitters).

Notes

Found while adding cross-mode regression tests for #649 (closures capturing a for (let …) loop variable). The per-iteration binding itself is correct in generators; this is an orthogonal generator-body arrow-emission bug. Top-level function* declared in a loop capturing the loop var (the #622 repro) is unaffected because its .map runs at top level, not inside a generator body.

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