-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1685482 - Part 2: Disallow identifiers named "async" in for-of lo…
…ops. r=yulia `for-of` loops mustn't start with the token sequence `async of`, because that leads to a shift-reduce conflict when parsing `for (async of => {};;)` or `for (async of [])`. This restriction doesn't apply to `for-await-of` loops, because `async` in `for await (async of ...)` is always parsed as an identifier. Parsing `for (async of ...)` already results in a SyntaxError, but that happens because `assignExpr()` always tries to parse the sequence `async [no LineTerminator] of` as the start of an async arrow function. That means `forHeadStart()` still needs to handle the case when `async` and `of` are separated by a line terminator. Part 3 will update the parser to allow `for await (async of ...)`. Spec change: tc39/ecma262#2256 Depends on D100994 Differential Revision: https://phabricator.services.mozilla.com/D100995
- Loading branch information
Showing
4 changed files
with
150 additions
and
8 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
116 changes: 116 additions & 0 deletions
116
js/src/tests/non262/statements/for-of-async-of-starting-lhs.js
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
if (typeof getRealmConfiguration === "undefined") { | ||
var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration; | ||
} | ||
|
||
const IsTopLevelAwaitEnabled = getRealmConfiguration().topLevelAwait; | ||
|
||
const AsyncFunction = async function(){}.constructor; | ||
|
||
function assertNoError(f, msg) { | ||
try { | ||
f(); | ||
} catch (e) { | ||
assertEq(true, false, `${msg}: ${e}`); | ||
} | ||
} | ||
|
||
function assertSyntaxError(code) { | ||
assertThrowsInstanceOf(function () { Function(code); }, SyntaxError, "Function:" + code); | ||
assertThrowsInstanceOf(function () { AsyncFunction(code); }, SyntaxError, "AsyncFunction:" + code); | ||
|
||
if (typeof parseModule === "function") { | ||
assertThrowsInstanceOf(function () { parseModule(code); }, SyntaxError, "Module:" + code); | ||
} | ||
} | ||
|
||
function assertNoSyntaxError(code) { | ||
assertNoError(function () { Function(code); }, "Function:" + code); | ||
assertNoError(function () { AsyncFunction(code); }, "AsyncFunction:" + code); | ||
|
||
if (typeof parseModule === "function") { | ||
assertNoError(function () { parseModule(code); }, "Module:" + code); | ||
} | ||
} | ||
|
||
function assertNoSyntaxErrorAsyncContext(code) { | ||
assertNoError(function () { AsyncFunction(code); }, "AsyncFunction:" + code); | ||
|
||
if (typeof parseModule === "function" && IsTopLevelAwaitEnabled) { | ||
assertNoError(function () { parseModule(code); }, "Module:" + code); | ||
} | ||
} | ||
|
||
const invalidTestCases = [ | ||
// for-in loop: LHS can't start with an async arrow function. | ||
"for ( async of => {} in [] ) ;", | ||
"for ( async o\\u0066 => {} in [] ) ;", | ||
|
||
// for-of loop: LHS can't start with an async arrow function. | ||
"for ( async of => {} of [] ) ;", | ||
"for ( async o\\u0066 => {} of [] ) ;", | ||
|
||
// for-of loop: LHS can't start with an identifier named "async". | ||
"for ( async of [] ) ;", | ||
|
||
// for-await-of loop: LHS can't start with an async arrow function. | ||
"for await ( async of => {} of [] ) ;", | ||
"for await ( async o\\u0066 => {} of [] ) ;", | ||
]; | ||
|
||
for (let source of invalidTestCases) { | ||
assertSyntaxError(source); | ||
|
||
// Also test when the tokens are separated by newline characters. | ||
assertSyntaxError(source.split(" ").join("\n")); | ||
} | ||
|
||
// for-loop: async arrow functions are allowed in C-style for-loops. | ||
assertNoSyntaxError("for ( async of => {} ; ; ) ;") | ||
|
||
const validTestCases = [ | ||
// for-loop: LHS can start with an identifier named "async". | ||
"for ( async ; ; ) ;", | ||
"for ( \\u0061sync ; ; ) ;", | ||
|
||
// for-in loop: LHS can start with an identifier named "async". | ||
"for ( async in [] ) ;", | ||
"for ( \\u0061sync in [] ) ;", | ||
|
||
// for-in loop: LHS can start with an property assignment starting with "async". | ||
"for ( async . prop in [] ) ;", | ||
"for ( async [ 0 ] in [] ) ;", | ||
|
||
// for-of loop: LHS can start with an identifier named "async" when escape characters are used. | ||
"for ( \\u0061sync of [] ) ;", | ||
|
||
// for-of loop: LHS can start with an property assignment starting with "async". | ||
"for ( async . prop of [] ) ;", | ||
"for ( async [ 0 ] of [] ) ;", | ||
]; | ||
|
||
for (let source of validTestCases) { | ||
assertNoSyntaxError(source); | ||
|
||
// Also test when the tokens are separated by newline characters. | ||
assertNoSyntaxError(source.split(" ").join("\n")); | ||
} | ||
|
||
const validTestCasesAsync = [ | ||
// for-await-of loop: LHS can start with an identifier named "async". | ||
// "for await ( async of [] ) ;", | ||
"for await ( \\u0061sync of [] ) ;", | ||
|
||
// for-await-of loop: LHS can start with an property assignment starting with "async". | ||
"for await ( async . prop of [] ) ;", | ||
"for await ( async [ 0 ] of [] ) ;", | ||
]; | ||
|
||
for (let source of validTestCasesAsync) { | ||
assertNoSyntaxErrorAsyncContext(source); | ||
|
||
// Also test when the tokens are separated by newline characters. | ||
assertNoSyntaxErrorAsyncContext(source.split(" ").join("\n")); | ||
} | ||
|
||
if (typeof reportCompare === "function") | ||
reportCompare(true, true); |