Skip to content

Commit

Permalink
Properly handle 'async of' in await loops
Browse files Browse the repository at this point in the history
FIX: Fix spec conformity in corner case 'for await (async of ...)'.

Closes #1031
  • Loading branch information
marijnh committed May 4, 2021
1 parent b0b1030 commit 134ede4
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 2 deletions.
7 changes: 5 additions & 2 deletions acorn/src/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,10 @@ pp.parseMaybeAssign = function(forInit, refDestructuringErrors, afterLeftParse)
}

let startPos = this.start, startLoc = this.startLoc
if (this.type === tt.parenL || this.type === tt.name)
if (this.type === tt.parenL || this.type === tt.name) {
this.potentialArrowAt = this.start
this.potentialArrowInForAwait = forInit === "await"
}
let left = this.parseMaybeConditional(forInit, refDestructuringErrors)
if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc)
if (this.type.isAssign) {
Expand Down Expand Up @@ -414,7 +416,8 @@ pp.parseExprAtom = function(refDestructuringErrors) {
if (canBeArrow && !this.canInsertSemicolon()) {
if (this.eat(tt.arrow))
return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false)
if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name && !containsEsc) {
if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name && !containsEsc &&
(!this.potentialArrowInForAwait || this.value !== "of" || this.containsEsc)) {
id = this.parseIdent(false)
if (this.canInsertSemicolon() || !this.eat(tt.arrow))
this.unexpected()
Expand Down
1 change: 1 addition & 0 deletions acorn/src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class Parser {

// Used to signify the start of a potential arrow function
this.potentialArrowAt = -1
this.potentialArrowInForAwait = false

// Positions to delayed-check that yield/await does not exist in default parameters.
this.yieldPos = this.awaitPos = this.awaitIdentPos = 0
Expand Down
6 changes: 6 additions & 0 deletions test/tests-async-iteration.js
Original file line number Diff line number Diff line change
Expand Up @@ -1992,3 +1992,9 @@ test("({async})", {}, { "ecmaVersion": 9 })
test("({async: true})", {}, { "ecmaVersion": 9 })

testFail("({async\n foo() { }})", "Unexpected token (2:4)", { "ecmaVersion": 9 })

// #1031
test("async () => { for await (async of []); }", {}, {ecmaVersion: 9})
test("for (async of => {}; i < 10; ++i) {}", {}, {ecmaVersion: 9})
testFail("for (async of [1]) {}", "Unexpected token (1:14)", {ecmaVersion: 9})

0 comments on commit 134ede4

Please sign in to comment.