forked from WebKit/WebKit
-
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.
[JSC] Disallow yield/await expressions in class field initializers
https://bugs.webkit.org/show_bug.cgi?id=276438 rdar://119044881 Reviewed by Yusuke Suzuki. The language spec doesn't explictly disallow yield and await expressions in class field initializers, however it implicitly does given that the expression is effectively evaluated as if it's inside a method. Additionally, the consensus seems to be that these expressions should not be allowed, see: tc39/ecma262#3333 The yield and await expressions are now handled differently, but similar to how they are each handled in other contexts. This also seems to be the least disruptive way to handle existing scripts, as well as consistent with other engines: yield: raise syntax error await: parse as an identifier Also adding a new test that generates and verifies scripts containing a class with a field initializer containing yield and await, where the class is either not nested or nested inside generator or async functions to verify the behavior of various combinations. * Source/JavaScriptCore/parser/Parser.cpp: (JSC::Parser<LexerType>::parseYieldExpression): (JSC::Parser<LexerType>::parseAwaitExpression): (JSC::Parser<LexerType>::parsePrimaryExpression): (JSC::Parser<LexerType>::parseUnaryExpression): Canonical link: https://commits.webkit.org/280837@main
- Loading branch information
Showing
2 changed files
with
95 additions
and
2 deletions.
There are no files selected for viewing
89 changes: 89 additions & 0 deletions
89
JSTests/stress/yield-await-class-field-initializer-expr.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,89 @@ | ||
// Tests for 'yield' and 'await' inside class field initializers, where the class is declared inside | ||
// async and generator functions. | ||
const verbose = false; | ||
|
||
const wrappers = ['none', 'generator', 'async']; | ||
const fieldModifiers = ['', 'static']; | ||
const fieldInitExprs = ['yield', 'yield 42', 'await', 'await 3']; | ||
|
||
function genTestCases() { | ||
let cases = []; | ||
for (const wrapper of wrappers) { | ||
for (const fieldModifier of fieldModifiers) { | ||
for (const fieldInitExpr of fieldInitExprs) { | ||
cases.push({ wrapper, fieldModifier, fieldInitExpr }); | ||
} | ||
} | ||
} | ||
return cases; | ||
} | ||
|
||
function genTestScript(c) { | ||
let tabs = 0; | ||
let script = ""; | ||
|
||
function append(line) { | ||
for (t = 0; t < tabs; t++) | ||
script += ' '; | ||
script += line + '\n'; | ||
} | ||
|
||
switch (c.wrapper) { | ||
case 'generator': | ||
append('function * g() {'); | ||
break; | ||
case 'async': | ||
append('async function f() {'); | ||
break; | ||
case 'none': | ||
break; | ||
} | ||
tabs++; | ||
append('class C {'); | ||
tabs++; | ||
append(`${c.fieldModifier} f = ${c.fieldInitExpr};`); | ||
tabs--; | ||
append('}'); | ||
tabs--; | ||
if (c.wrapper !== 'none') append('}'); | ||
return script; | ||
} | ||
|
||
function expected(c, result, error) { | ||
if (c.fieldInitExpr === 'await') { | ||
// 'await' will parse as an identifier. | ||
if (c.wrapper === 'none' && c.fieldModifier === 'static') { | ||
// In this case, 'await' as identifier produces a ReferenceError. | ||
return result === null && error instanceof ReferenceError; | ||
} | ||
// In these cases, 'await' as identifier has value 'undefined'). | ||
return result === undefined && error === null; | ||
} | ||
// All other cases should result in a SyntaxError. | ||
return result === null && error instanceof SyntaxError; | ||
} | ||
|
||
cases = genTestCases(); | ||
|
||
for (const c of cases) { | ||
let script = genTestScript(c); | ||
let result = null; | ||
let error = null; | ||
try { | ||
result = eval(script); | ||
} catch (e) { | ||
error = e; | ||
} | ||
|
||
if (verbose || !expected(c, result, error)) { | ||
print(`Case: ${c.wrapper}:${c.fieldModifier}:${c.fieldInitExpr}`); | ||
print(`Script:\n${script}`); | ||
if (result != null) { | ||
print("Result: " + result); | ||
} else if (error != null) { | ||
print("Error: " + error); | ||
} else { | ||
print("Expecting either result or error!") | ||
} | ||
} | ||
} |
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