Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[JSC] let [ sequence cannot appear in ExpressionStatement context
https://bugs.webkit.org/show_bug.cgi?id=215977

Reviewed by Ross Kirsling.

JSTests:

* stress/let-and-open-bracket.js: Added.
(testSyntax):
(testSyntaxError):
* test262/expectations.yaml:

Source/JavaScriptCore:

Because of ambiguity between destructuring assignment and member access (let IDENTIFIER), ECMA262 does not allow `let [` sequence in ExpressionStatement context[1].
We should throw SyntaxError when we see something like this.

    if (false)
        let [ok] = [42];

[1]: https://tc39.es/ecma262/#sec-expression-statement

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseStatement):

Canonical link: https://commits.webkit.org/228763@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@266327 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Constellation committed Aug 29, 2020
1 parent 41c992a commit d116fc7
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 16 deletions.
12 changes: 12 additions & 0 deletions JSTests/ChangeLog
@@ -1,3 +1,15 @@
2020-08-29 Yusuke Suzuki <ysuzuki@apple.com>

[JSC] `let [` sequence cannot appear in ExpressionStatement context
https://bugs.webkit.org/show_bug.cgi?id=215977

Reviewed by Ross Kirsling.

* stress/let-and-open-bracket.js: Added.
(testSyntax):
(testSyntaxError):
* test262/expectations.yaml:

2020-08-29 Yusuke Suzuki <ysuzuki@apple.com>

[JSC] for-of uses AssignmentExpression while for-in uses Expression
Expand Down
37 changes: 37 additions & 0 deletions JSTests/stress/let-and-open-bracket.js
@@ -0,0 +1,37 @@
function testSyntax(script) {
try {
eval(script);
} catch (error) {
if (error instanceof SyntaxError)
throw new Error("Bad error: " + String(error));
}
}

function testSyntaxError(script, message) {
var error = null;
try {
eval(script);
} catch (e) {
error = e;
}
if (!error)
throw new Error("Expected syntax error not thrown");

if (String(error) !== message)
throw new Error("Bad error: " + String(error));
}

testSyntaxError(`
if (false) let [ok] = 40;
`, `SyntaxError: Unexpected token '['. Cannot use lexical declaration in single-statement context.`);

testSyntaxError(`
if (false) let
[ok] = 40;
`, `SyntaxError: Unexpected token '['. Cannot use lexical declaration in single-statement context.`);

testSyntax(`
if (false) {
let [ok] = 40;
}
`);
16 changes: 0 additions & 16 deletions JSTests/test262/expectations.yaml
Expand Up @@ -3053,13 +3053,9 @@ test/language/statements/const/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js
test/language/statements/const/dstr/ary-ptrn-rest-id-direct.js:
default: 'Test262Error: Expected true but got false'
strict mode: 'Test262Error: Expected true but got false'
test/language/statements/do-while/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/for-await-of/async-from-sync-iterator-continuation-abrupt-completion-get-constructor.js:
default: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Expected [start, tick 1, tick 2] and [start, tick 1, tick 2, catch] to have the same contents. '
strict mode: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Expected [start, tick 1, tick 2] and [start, tick 1, tick 2, catch] to have the same contents. '
test/language/statements/for-await-of/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/for-await-of/ticks-with-async-iter-resolved-promise-and-constructor-lookup-two.js:
default: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Expected [pre, tick 1, tick 2, loop] and [pre, constructor, tick 1, loop, constructor, tick 2, post] to have the same contents. Ticks and constructor lookups'
strict mode: 'Test262:AsyncTestFailure:Test262Error: Test262Error: Expected [pre, tick 1, tick 2, loop] and [pre, constructor, tick 1, loop, constructor, tick 2, post] to have the same contents. Ticks and constructor lookups'
Expand All @@ -3073,8 +3069,6 @@ test/language/statements/for-in/head-lhs-let.js:
default: "SyntaxError: Cannot use the keyword 'in' as a lexical variable name."
test/language/statements/for-in/identifier-let-allowed-as-lefthandside-expression-not-strict.js:
default: "SyntaxError: Cannot use the keyword 'in' as a lexical variable name."
test/language/statements/for-in/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/for-in/order-enumerable-shadowed.js:
default: 'Test262Error: Expected [p1, p2] and [p1] to have the same contents. '
strict mode: 'Test262Error: Expected [p1, p2] and [p1] to have the same contents. '
Expand Down Expand Up @@ -3156,8 +3150,6 @@ test/language/statements/for-of/dstr/obj-id-put-const.js:
test/language/statements/for-of/dstr/obj-id-put-let.js:
default: 'Test262Error: Expected a ReferenceError to be thrown but no exception was thrown at all'
strict mode: 'Test262Error: Expected a ReferenceError to be thrown but no exception was thrown at all'
test/language/statements/for-of/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/for/dstr/const-ary-init-iter-get-err-array-prototype.js:
default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
Expand Down Expand Up @@ -3187,8 +3179,6 @@ test/language/statements/for/dstr/var-ary-ptrn-rest-id-direct.js:
strict mode: 'Test262Error: Expected true but got false'
test/language/statements/for/head-lhs-let.js:
default: "SyntaxError: Unexpected token ';'. Expected a parameter pattern or a ')' in parameter list."
test/language/statements/for/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/for/scope-body-lex-open.js:
default: 'Test262Error: Expected SameValue(«inside», «outside») to be true'
strict mode: 'Test262Error: Expected SameValue(«inside», «outside») to be true'
Expand Down Expand Up @@ -3231,8 +3221,6 @@ test/language/statements/if/if-stmt-else-async-gen.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/if/if-stmt-else-gen.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/if/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/labeled/decl-async-function.js:
default: 'Test262: This statement should not be evaluated.'
strict mode: 'Test262: This statement should not be evaluated.'
Expand Down Expand Up @@ -3368,10 +3356,6 @@ test/language/statements/variable/dstr/ary-ptrn-elem-id-iter-val-array-prototype
test/language/statements/variable/dstr/ary-ptrn-rest-id-direct.js:
default: 'Test262Error: Expected true but got false'
strict mode: 'Test262Error: Expected true but got false'
test/language/statements/while/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/with/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/types/reference/put-value-prop-base-primitive-realm.js:
default: 'Test262Error: number Expected SameValue(«0», «1») to be true'
strict mode: 'Test262Error: number Expected SameValue(«0», «1») to be true'
Expand Down
18 changes: 18 additions & 0 deletions Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,21 @@
2020-08-29 Yusuke Suzuki <ysuzuki@apple.com>

[JSC] `let [` sequence cannot appear in ExpressionStatement context
https://bugs.webkit.org/show_bug.cgi?id=215977

Reviewed by Ross Kirsling.

Because of ambiguity between destructuring assignment and member access (let IDENTIFIER), ECMA262 does not allow `let [` sequence in ExpressionStatement context[1].
We should throw SyntaxError when we see something like this.

if (false)
let [ok] = [42];

[1]: https://tc39.es/ecma262/#sec-expression-statement

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseStatement):

2020-08-29 Yusuke Suzuki <ysuzuki@apple.com>

[JSC] for-of uses AssignmentExpression while for-in uses Expression
Expand Down
6 changes: 6 additions & 0 deletions Source/JavaScriptCore/parser/Parser.cpp
Expand Up @@ -1970,6 +1970,12 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(Tre
// These tokens imply the end of a set of source elements
return 0;
case LET: {
// https://tc39.es/ecma262/#sec-expression-statement
// ExpressionStatement's lookahead includes `let [` sequence.
SavePoint savePoint = createSavePoint(context);
next();
failIfTrue(match(OPENBRACKET), "Cannot use lexical declaration in single-statement context");
restoreSavePoint(context, savePoint);
if (!strictMode())
goto identcase;
goto defaultCase;
Expand Down

0 comments on commit d116fc7

Please sign in to comment.