Skip to content

Commit e521854

Browse files
committed
We incorrectly throw a syntax error when declaring a top level for-loop iteration variable the same as a parameter
https://bugs.webkit.org/show_bug.cgi?id=171041 <rdar://problem/32082516> Reviewed by Yusuke Suzuki. JSTests: * stress/lexical-scoping-for-loop.js: Added. (assert): (test1): (test2): (test3): (test4): (test5): (test6): (let.test7): (let.test8): (let.test9): (let.test10): (let.test11): (let.test12): Source/JavaScriptCore: We were treating a for-loop variable declaration potentially as a top level statement, e.g, in a program like this: ``` function foo() { for (let variable of expr) { } } ``` But we should not be. This had the consequence of making this type of program throw a syntax error: ``` function foo(arg) { for (let arg of expr) { } } ``` even though it should not. The fix is simple, we just need to increment the statement depth before parsing anything inside the for loop. * parser/Parser.cpp: (JSC::Parser<LexerType>::parseForStatement): LayoutTests: * js/parser-syntax-check-expected.txt: * js/script-tests/parser-syntax-check.js: Canonical link: https://commits.webkit.org/189327@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@217200 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 6e4aa4e commit e521854

File tree

7 files changed

+199
-0
lines changed

7 files changed

+199
-0
lines changed

JSTests/ChangeLog

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
2017-05-21 Saam Barati <[email protected]>
2+
3+
We incorrectly throw a syntax error when declaring a top level for-loop iteration variable the same as a parameter
4+
https://bugs.webkit.org/show_bug.cgi?id=171041
5+
<rdar://problem/32082516>
6+
7+
Reviewed by Yusuke Suzuki.
8+
9+
* stress/lexical-scoping-for-loop.js: Added.
10+
(assert):
11+
(test1):
12+
(test2):
13+
(test3):
14+
(test4):
15+
(test5):
16+
(test6):
17+
(let.test7):
18+
(let.test8):
19+
(let.test9):
20+
(let.test10):
21+
(let.test11):
22+
(let.test12):
23+
124
2017-05-19 Yusuke Suzuki <[email protected]>
225

326
[JSC] Make get_by_val & string "499" to number 499
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
3+
function assert(b) {
4+
if (!b)
5+
throw new Error("Bad");
6+
}
7+
8+
function test1(x) {
9+
for (let x = 20; x < 30; ++x) { }
10+
return x;
11+
}
12+
function test2(x) {
13+
for (let x of [1,2,3]) { }
14+
return x;
15+
}
16+
function test3(x) {
17+
for (let x in {}) { }
18+
return x;
19+
}
20+
function test4(x) {
21+
let i = 0;
22+
for (const x = 20; i < 1; ++i) { }
23+
return x;
24+
}
25+
function test5(x) {
26+
for (const x of [1, 2, 3]) { }
27+
return x;
28+
}
29+
function test6(x) {
30+
for (const x in {}) { }
31+
return x;
32+
}
33+
34+
let test7 = (x) => {
35+
for (let x = 20; x < 30; ++x) { }
36+
return x;
37+
}
38+
let test8 = (x) => {
39+
for (let x of [1,2,3]) { }
40+
return x;
41+
}
42+
let test9 = (x) => {
43+
for (let x in {}) { }
44+
return x;
45+
}
46+
let test10 = (x) => {
47+
let i = 0;
48+
for (const x = 20; i < 1; ++i) { }
49+
return x;
50+
}
51+
let test11 = (x) => {
52+
for (const x of [1, 2, 3]) { }
53+
return x;
54+
}
55+
let test12 = (x) => {
56+
for (const x in {}) { }
57+
return x;
58+
}
59+
60+
for (let test of [test1, test2, test3, test4, test5, test7, test8, test9, test10, test11, test12])
61+
assert(test("foo") === "foo");

LayoutTests/ChangeLog

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
2017-05-21 Saam Barati <[email protected]>
2+
3+
We incorrectly throw a syntax error when declaring a top level for-loop iteration variable the same as a parameter
4+
https://bugs.webkit.org/show_bug.cgi?id=171041
5+
<rdar://problem/32082516>
6+
7+
Reviewed by Yusuke Suzuki.
8+
9+
* js/parser-syntax-check-expected.txt:
10+
* js/script-tests/parser-syntax-check.js:
11+
112
2017-05-21 Antti Koivisto <[email protected]>
213

314
matchMedia('print').addListener() fires in WK1 but never in WK2 when printing (breaks printing Google maps, QuickLooks)

LayoutTests/js/parser-syntax-check-expected.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,54 @@ PASS Invalid: "for (const {i} = 20 in b) { }". Produced the following syntax err
556556
PASS Invalid: "function f() { for (const {i} = 20 in b) { } }". Produced the following syntax error: "SyntaxError: Cannot assign to the loop variable inside a for-in loop header."
557557
PASS Invalid: "for (let {i} = 20 in b) { }". Produced the following syntax error: "SyntaxError: Cannot assign to the loop variable inside a for-in loop header."
558558
PASS Invalid: "function f() { for (let {i} = 20 in b) { } }". Produced the following syntax error: "SyntaxError: Cannot assign to the loop variable inside a for-in loop header."
559+
PASS Valid: "function x(i) { for (let i in {}) { } }"
560+
PASS Valid: "function f() { function x(i) { for (let i in {}) { } } }"
561+
PASS Valid: "function x(i) { for (let i of []) { } }"
562+
PASS Valid: "function f() { function x(i) { for (let i of []) { } } }"
563+
PASS Valid: "function x(i) { for (let i of []) { } }"
564+
PASS Valid: "function f() { function x(i) { for (let i of []) { } } }"
565+
PASS Valid: "function x(i) { for (let i; false; ) { } }"
566+
PASS Valid: "function f() { function x(i) { for (let i; false; ) { } } }"
567+
PASS Valid: "let f = (i) => { for (let i in {}) { } }"
568+
PASS Valid: "function f() { let f = (i) => { for (let i in {}) { } } }"
569+
PASS Valid: "let f = (i) => { for (let i of []) { } }"
570+
PASS Valid: "function f() { let f = (i) => { for (let i of []) { } } }"
571+
PASS Valid: "let f = (i) => { for (let i of []) { } }"
572+
PASS Valid: "function f() { let f = (i) => { for (let i of []) { } } }"
573+
PASS Valid: "let f = (i) => { for (let i; false; ) { } }"
574+
PASS Valid: "function f() { let f = (i) => { for (let i; false; ) { } } }"
575+
PASS Valid: "function* x(i) { for (let i in {}) { } }"
576+
PASS Valid: "function f() { function* x(i) { for (let i in {}) { } } }"
577+
PASS Valid: "function* x(i) { for (let i of []) { } }"
578+
PASS Valid: "function f() { function* x(i) { for (let i of []) { } } }"
579+
PASS Valid: "function* x(i) { for (let i of []) { } }"
580+
PASS Valid: "function f() { function* x(i) { for (let i of []) { } } }"
581+
PASS Valid: "function* x(i) { for (let i; false; ) { } }"
582+
PASS Valid: "function f() { function* x(i) { for (let i; false; ) { } } }"
583+
PASS Valid: "function x(i) { for (const i in {}) { } }"
584+
PASS Valid: "function f() { function x(i) { for (const i in {}) { } } }"
585+
PASS Valid: "function x(i) { for (const i of []) { } }"
586+
PASS Valid: "function f() { function x(i) { for (const i of []) { } } }"
587+
PASS Valid: "function x(i) { for (const i of []) { } }"
588+
PASS Valid: "function f() { function x(i) { for (const i of []) { } } }"
589+
PASS Valid: "function x(i) { for (const i = 20; false; ) { } }"
590+
PASS Valid: "function f() { function x(i) { for (const i = 20; false; ) { } } }"
591+
PASS Valid: "let f = (i) => { for (const i in {}) { } }"
592+
PASS Valid: "function f() { let f = (i) => { for (const i in {}) { } } }"
593+
PASS Valid: "let f = (i) => { for (const i of []) { } }"
594+
PASS Valid: "function f() { let f = (i) => { for (const i of []) { } } }"
595+
PASS Valid: "let f = (i) => { for (const i of []) { } }"
596+
PASS Valid: "function f() { let f = (i) => { for (const i of []) { } } }"
597+
PASS Valid: "let f = (i) => { for (const i = 20; false; ) { } }"
598+
PASS Valid: "function f() { let f = (i) => { for (const i = 20; false; ) { } } }"
599+
PASS Valid: "function* x(i) { for (const i in {}) { } }"
600+
PASS Valid: "function f() { function* x(i) { for (const i in {}) { } } }"
601+
PASS Valid: "function* x(i) { for (const i of []) { } }"
602+
PASS Valid: "function f() { function* x(i) { for (const i of []) { } } }"
603+
PASS Valid: "function* x(i) { for (const i of []) { } }"
604+
PASS Valid: "function f() { function* x(i) { for (const i of []) { } } }"
605+
PASS Valid: "function* x(i) { for (const i = 20; false; ) { } }"
606+
PASS Valid: "function f() { function* x(i) { for (const i = 20; false; ) { } } }"
559607
try statement
560608
PASS Invalid: "try { break } catch(e) {}". Produced the following syntax error: "SyntaxError: 'break' is only valid inside a switch or loop statement."
561609
PASS Invalid: "function f() { try { break } catch(e) {} }". Produced the following syntax error: "SyntaxError: 'break' is only valid inside a switch or loop statement."

LayoutTests/js/script-tests/parser-syntax-check.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,30 @@ invalid("for (let i = 20 in b) { }");
371371
invalid("for (const i = 20 in b) { }");
372372
invalid("for (const {i} = 20 in b) { }");
373373
invalid("for (let {i} = 20 in b) { }");
374+
valid("function x(i) { for (let i in {}) { } }");
375+
valid("function x(i) { for (let i of []) { } }");
376+
valid("function x(i) { for (let i of []) { } }");
377+
valid("function x(i) { for (let i; false; ) { } }");
378+
valid("let f = (i) => { for (let i in {}) { } }");
379+
valid("let f = (i) => { for (let i of []) { } }");
380+
valid("let f = (i) => { for (let i of []) { } }");
381+
valid("let f = (i) => { for (let i; false; ) { } }");
382+
valid("function* x(i) { for (let i in {}) { } }");
383+
valid("function* x(i) { for (let i of []) { } }");
384+
valid("function* x(i) { for (let i of []) { } }");
385+
valid("function* x(i) { for (let i; false; ) { } }");
386+
valid("function x(i) { for (const i in {}) { } }");
387+
valid("function x(i) { for (const i of []) { } }");
388+
valid("function x(i) { for (const i of []) { } }");
389+
valid("function x(i) { for (const i = 20; false; ) { } }");
390+
valid("let f = (i) => { for (const i in {}) { } }");
391+
valid("let f = (i) => { for (const i of []) { } }");
392+
valid("let f = (i) => { for (const i of []) { } }");
393+
valid("let f = (i) => { for (const i = 20; false; ) { } }");
394+
valid("function* x(i) { for (const i in {}) { } }");
395+
valid("function* x(i) { for (const i of []) { } }");
396+
valid("function* x(i) { for (const i of []) { } }");
397+
valid("function* x(i) { for (const i = 20; false; ) { } }");
374398

375399
debug ("try statement");
376400

Source/JavaScriptCore/ChangeLog

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
2017-05-21 Saam Barati <[email protected]>
2+
3+
We incorrectly throw a syntax error when declaring a top level for-loop iteration variable the same as a parameter
4+
https://bugs.webkit.org/show_bug.cgi?id=171041
5+
<rdar://problem/32082516>
6+
7+
Reviewed by Yusuke Suzuki.
8+
9+
We were treating a for-loop variable declaration potentially as a top
10+
level statement, e.g, in a program like this:
11+
```
12+
function foo() {
13+
for (let variable of expr) { }
14+
}
15+
```
16+
But we should not be. This had the consequence of making this type of program
17+
throw a syntax error:
18+
```
19+
function foo(arg) {
20+
for (let arg of expr) { }
21+
}
22+
```
23+
even though it should not. The fix is simple, we just need to increment the
24+
statement depth before parsing anything inside the for loop.
25+
26+
* parser/Parser.cpp:
27+
(JSC::Parser<LexerType>::parseForStatement):
28+
129
2017-05-19 Yusuke Suzuki <[email protected]>
230

331
[JSC] Make get_by_val & string "499" to number 499

Source/JavaScriptCore/parser/Parser.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,10 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
11331133
JSTokenLocation location(tokenLocation());
11341134
int startLine = tokenLine();
11351135
next();
1136+
1137+
DepthManager statementDepth(&m_statementDepth);
1138+
m_statementDepth++;
1139+
11361140
handleProductionOrFail(OPENPAREN, "(", "start", "for-loop header");
11371141
int nonLHSCount = m_parserState.nonLHSCount;
11381142
int declarations = 0;

0 commit comments

Comments
 (0)