feat: accept a destructuring pattern as the for-of loop variable - #58
Merged
Merged
Conversation
for-of and destructuring shipped separately and their combination did not parse,
including the shape the two are most often used together in:
for (const [key, value] of pairs) { ... } Expected = but found of
isForOf() required an IDENT where the loop variable goes, so a pattern was never
recognised as a for-of head at all and the "of" fell through to the last switch.
It now also accepts a bracket or a brace and scans to the bracket that closes it,
the way isDestructuringAssignment does. That scan goes through lookahead(), so it
leaves the token stream alone and a regular expression in the source is still
readable afterwards.
forOf() then parses the loop variable as a pattern and, per iteration, binds the
element to a temporary and takes the pattern apart from there - so the element
expression is evaluated once, as it is for a plain loop variable. The two
existing emitters do the work: declareBindings for var, let and const,
assignBindings for the form with no declaration, where the leaves are assignment
targets rather than names to declare.
Covered: array and object patterns, renaming, rest, nesting, defaults, the
pairs idiom, member expressions as targets, per-iteration let capture, and
break/continue.
Not in this change: the same pattern in a for-in head. for-in yields keys, which
are strings, so destructuring one is legal ES6 but of no practical use;
for (var [a, b] in obj) stays a syntax error.
Also unchanged, and pre-existing rather than introduced here: a const pattern
element whose default is actually taken fails with "Assignment to constant".
const [a = 7] = [] fails the same way outside a loop.
./gradlew build testOptimistic testPessimistic:
suite before after
test 666, 0 fail 666, 0 fail
testOptimistic 1718, 0 fail 1718, 0 fail
testPessimistic 1718, 0 fail 1718, 0 fail
marevol
force-pushed
the
es6/for-of-destructuring
branch
from
August 28, 2026 05:11
b74ffe0 to
7cefe8c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #57.
for-of (#39) and destructuring (#38) shipped separately and their combination did not parse, including the shape the two are most often used together in:
Cause
isForOf()required anIDENTwhere the loop variable goes, so a pattern was never recognised as a for-of head at all and theoffell through to the last switch.Fix
It now also accepts a bracket or a brace and scans to the bracket that closes it, the way
isDestructuringAssignmentdoes. That scan goes throughlookahead()(#51), so it leaves the token stream alone and a regular expression in the source is still readable afterwards.forOf()then parses the loop variable as a pattern and, per iteration, binds the element to a temporary and takes the pattern apart from there — so the element expression is evaluated once, as it is for a plain loop variable. The two existing emitters do the work:declareBindingsforvar,letandconst,assignBindingsfor the form with no declaration, where the leaves are assignment targets rather than names to declare.Covered: array and object patterns, renaming, rest, nesting, defaults, the pairs idiom, member expressions as targets, per-iteration
letcapture, andbreak/continue.Not in this change
The same pattern in a for-in head. for-in yields keys, which are strings, so destructuring one is legal ES6 but of no practical use;
for (var [a, b] in obj)stays a syntax error.Verification
./gradlew build testOptimistic testPessimistic