Summary
Follow-up to #765 (compiled class-expression generator methods). With #765, generator / async-generator methods in a class expression (const C = class { *gen() {…} }) now compile and run. But an arrow/callback inside such a generator that writes a variable captured from the generator scope still fail-fasts:
const C = class { *gen(arr: number[]) { let sum = 0; arr.forEach(n => sum += n); yield sum; } };
console.log([...new C().gen([1,2,3])].join(",")); // interp: 6
// compiled: Compile Error: Compiled mode does not yet support an arrow/callback inside a
// generator (function*) body that writes to a variable captured from the generator
// scope (sum). … (#674)
This is the safe fail-fast guard (no silent miscompile), identical to where class declarations were before #724/#725.
Fix path
Class declarations wire this via RegisterGeneratorMethodFunctionDisplayClasses(classStmt, qualifiedClassName), called from DefineClass (Phase 4) so the function display class is registered before Phase 5's PropagateFunctionDCRequirements. Class expressions are defined later (DefineClassExpressionTypes/DefineClassExpressionMethods, Phase 5), so the analogous registration needs to be sequenced carefully relative to the propagation pass (and keyed for the class-expression's generated name). The registry is keyed by the method AST node (_generatorMethodFunctionDCKeys / _asyncGeneratorMethodFunctionDCKeys), which EmitGeneratorMethodBody / EmitAsyncGeneratorMethodBody already consult — so once registered at the right phase, emission picks it up.
Scope
Compiled-only; interpreter handles it. Low priority — the guard prevents incorrect output. Discovered while implementing #765.
Summary
Follow-up to #765 (compiled class-expression generator methods). With #765, generator / async-generator methods in a class expression (
const C = class { *gen() {…} }) now compile and run. But an arrow/callback inside such a generator that writes a variable captured from the generator scope still fail-fasts:This is the safe fail-fast guard (no silent miscompile), identical to where class declarations were before #724/#725.
Fix path
Class declarations wire this via
RegisterGeneratorMethodFunctionDisplayClasses(classStmt, qualifiedClassName), called fromDefineClass(Phase 4) so the function display class is registered before Phase 5'sPropagateFunctionDCRequirements. Class expressions are defined later (DefineClassExpressionTypes/DefineClassExpressionMethods, Phase 5), so the analogous registration needs to be sequenced carefully relative to the propagation pass (and keyed for the class-expression's generated name). The registry is keyed by the method AST node (_generatorMethodFunctionDCKeys/_asyncGeneratorMethodFunctionDCKeys), whichEmitGeneratorMethodBody/EmitAsyncGeneratorMethodBodyalready consult — so once registered at the right phase, emission picks it up.Scope
Compiled-only; interpreter handles it. Low priority — the guard prevents incorrect output. Discovered while implementing #765.