Skip to content

test262: Iterator conformance fixes (wave 13) - #75

Merged
hiett merged 2 commits into
experiment/js-frontendfrom
js262/wave13-Iterator
Jul 15, 2026
Merged

test262: Iterator conformance fixes (wave 13)#75
hiett merged 2 commits into
experiment/js-frontendfrom
js262/wave13-Iterator

Conversation

@hiett

@hiett hiett commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Raises Iterator/IteratorHelperPrototype test262 conformance from 42 → 60 passing (+18; RAN 74 → 92) via two generator-runtime fixes.

1. Transform generator function expressions (not just declarations)

is_generator was only honoured for function DECLARATIONS, so (function*(){ … })() — the immediately-invoked form test262 uses to build a throwaway iterator — lowered as a plain function, returning undefined (or raising "yield in an unsupported generator shape"). The lambda pre-pass now rewrites a generator expression body to the same resumable state machine, falling back to the untransformed body on an unsupported shape. Fixes the "iterator-already-exhausted" cases (some/every/find/reduce/toArray). (+10)

2. Generator.prototype.return (§27.5.1.4)

iterator.return() was undefined → {badfun,undefined}. Added gen_return across the FFI (grouped export next to gen_next), emit_core allow-list, and rt_js external, routed in the generator dispatch cluster. Closes the generator and returns {value: v, done: true}; a non-generator receiver delegates to a user return method. Closing swaps in a permanently-done step while keeping the {js_gen,_} tag, so the lazy helpers (map/filter/take/drop) see the closed source as empty. Fixes the "underlying-iterator-closed" cluster. (+8)

Spec-driven tests appended at EOF under // ==== Iterator (wave 13) ====. js_compiler_test fully green (only the 3 pre-existing WASM .wat fixture failures remain); erlc/gleam build/format clean.

hiett added 2 commits July 15, 2026 06:24
A generator used in expression position — most commonly the immediately-invoked
form `(function*(){ … })()` that test262 uses to build a throwaway iterator —
was lowered as an ordinary function: its `is_generator` flag was only honoured
for function DECLARATIONS (in as_function_decl), so the expression body was never
rewritten to the resumable state machine. The call therefore returned `undefined`
(empty body) or raised "yield in an unsupported generator shape", and any later
`.next()`/iterator-helper call on the result threw a TypeError.

Rewrite a generator function expression in the lambda pre-pass exactly as a
declaration is rewritten, falling back to the untransformed body on an unsupported
shape so the surviving `yield` still reports a clean Unsupported error. This makes
`(function*(){…})()` produce a real generator, fixing the Iterator-helper
"already exhausted" cases (some/every/find/reduce/toArray) and letting the lazy
helpers compose over generator-expression sources.
Iterator-helper tests routinely close a source with `iterator.return()` before
building a helper over it; `.return` was undefined, so the call raised
{badfun,undefined}. Add gen_return across the three runtime layers (FFI impl +
grouped export, emit_core resolve_js allow-list, rt_js @external) and route
`x.return(v)` in the generator dispatch cluster.

Per §27.5.1.4 it closes the generator and returns {value: v, done: true} (v
defaults to undefined); a non-generator receiver delegates to a user `return`
method. Closing swaps the step for a permanently-done step while keeping the
{js_gen,_} tag, so the iterator helpers (map/filter/take/drop/…), which dispatch
on that tag, correctly see the closed source as an empty iterator.
@hiett
hiett merged commit 84a62e7 into experiment/js-frontend Jul 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant