Skip to content

fix(runtime): bind this=iterable when calling [Symbol.iterator]() (yield* sync delegation)#4788

Merged
proggeramlug merged 1 commit into
mainfrom
yield-star-forwarding
Jun 8, 2026
Merged

fix(runtime): bind this=iterable when calling [Symbol.iterator]() (yield* sync delegation)#4788
proggeramlug merged 1 commit into
mainfrom
yield-star-forwarding

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Follow-up to #4777/#4783 yield* async-generator work. Fixes the this binding of the sync-iterator factory in GetIterator.

Root cause

js_get_iterator invoked the [Symbol.iterator]() factory via js_closure_call0 after clone_closure_rebind_this — which only rebinds a closure that captures this. A plain function(){ …this… } iterator factory reads this dynamically off IMPLICIT_THIS, which was left as the caller's this. So GetIterator(obj) ran the factory with the wrong this (spec: GetIteratorCall(method, obj) with this === obj).

Fix

Set IMPLICIT_THIS = iterable around the factory call (keeping the existing clone_closure_rebind_this for the captures-this effect-prototype case).

Impact

language/{expressions,statements}/async-generator: 93.8% → 94.7% (pass 833 → 841, compile-fail 0). Fixes the yield-star-sync-* thisValue ordering cluster and array-prototype destructuring iterator cases. General correctness fix for all for-of / destructuring / spread over an object whose [Symbol.iterator] factory reads this; verified no regression on for-of with a this-reading custom iterator.

Not included (return/throw delegation forwarding)

Attempted yield* .throw()/.return() forwarding to the delegated iterator (spec received.[[Type]] is throw/return). It requires the catch/return handler to re-enter the delegation loop, but Perry inlines async-generator catch bodies into the .throw() closure where there is no loop context (continue → "continue statement outside any loop"). Doing it properly is a deep state-machine rework with real regression risk to the shared yield* path (Effect / #321) — deferred.

js_get_iterator invoked the [Symbol.iterator]() factory via js_closure_call0
after clone_closure_rebind_this, which only rebinds a closure that *captures*
this. A plain function(){ ...this... } iterator factory reads this dynamically
off IMPLICIT_THIS, which was left as the caller's this — so GetIterator ran the
factory with the wrong this. Set IMPLICIT_THIS=iterable around the call (spec
GetIterator -> Call(method, obj)). Fixes test262 yield-star-sync-* (thisValue of
the [Symbol.iterator] call) and array-prototype destructuring iterator cases.
@proggeramlug proggeramlug merged commit cb1b1b4 into main Jun 8, 2026
13 checks passed
@proggeramlug proggeramlug deleted the yield-star-forwarding branch June 8, 2026 11:35
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