"use strict"; function truth() { return true; } noInline(truth); function assert(cond) { if (!cond) throw new Error("broke assertion"); } noInline(assert); const NUM_LOOPS = 1000; const SHORT_LOOPS = 100; function shouldThrowTDZ(func) { var hasThrown = false; try { func(); } catch(e) { if (e.name.indexOf("ReferenceError") !== -1) hasThrown = true; } assert(hasThrown); } noInline(shouldThrowTDZ); ;(function () { var arr = []; for (let i = 0; i < 10; i++) { arr.push(function () { return i; }) } for (let j = 0; j < arr.length; j++) { assert(arr[j]() === j); } let f = "fff"; let counter = 0; for (let f of arr) { assert(f() === counter++); } assert(f === "fff"); let numLoops = 0; for (let f of arr) { numLoops++; let f = function () { return "f"; } assert(f() === "f"); } assert(numLoops === arr.length); assert(f === "fff"); })(); ;(function() { function foo() { var obj = {hello:1, world:2}; obj["bar"] = 3; let p = 20; assert(p === 20); for (let p in obj) { assert(p === "hello" || p === "world" || p === "bar"); } assert(p === 20); } function bar() { var obj = {hello:1, world:2}; obj["bar"] = 3; let props = []; let p = 20; for (let p in obj) { props.push(function foo() { return p; }); let outerP = p; if (truth()) { let p = 100; assert(p === 100); assert(p !== outerP); assert(outerP === "hello" || outerP === "world" || outerP === "bar"); } assert(p === outerP); } assert(p === 20); let seenProps = {}; for (let f of props) { let p = f(); assert(p === "hello" || p === "world" || p === "bar"); seenProps[p] = true; } assert(seenProps["hello"] === true); assert(seenProps["world"] === true); assert(seenProps["bar"] === true); assert(p === 20); } for (var i = 0; i < NUM_LOOPS; i++) { foo(); bar(); } })(); ;(function() { function foo() { let counter = 0; for (let idx = 0; idx < 20; idx++) { assert(idx === counter++); continue; } shouldThrowTDZ(function() { return idx; }); } for (var i = 0; i < NUM_LOOPS; i++) { foo(); } })(); ;(function() { function foo() { for (let idx = 0; !truth(); idx++) { } shouldThrowTDZ(function() { return idx; }); // Just plain old reference error here. } function bar() { for (let j = 0; j < 20; j++) { if (j === 1) break; else continue; } shouldThrowTDZ(function() { return j; }); } for (var i = 0; i < NUM_LOOPS; i++) { foo(); bar(); } })(); ;(function() { function foo() { var obj = {hello:1, world:2}; let p = 20; var arr = [] for (let p in obj) { arr.push(function capP() { return p; }); assert(p === "hello" || p === "world"); } assert(arr[0]() === "hello" || arr[0]() === "world"); assert(arr[1]() === "hello" || arr[1]() === "world"); assert(arr[1]() !== arr[0]()); assert(p === 20); } function bar() { var obj = {a:1, b:2, c:3, d:4, e:4}; obj["f"] = 5; let funcs = []; for (let p in obj) { funcs.push(function capP() { return p; }); } let counter = 0; for (let p in obj) { assert(funcs[counter]() === p); counter++; } } for (var i = 0; i < NUM_LOOPS; i++) { foo(); bar(); } })(); ;(function() { function foo() { let arr = [0, 1, 2, 3, 4, 5]; let funcs = []; for (let x of arr) { funcs.push(function() { return x; }); } for (let i = 0; i < arr.length; ++i) { assert(funcs[i]() === i); } } for (var i = 0; i < NUM_LOOPS; i++) { foo(); } })(); ;(function() { function foo() { let thing = {}; for (let thing = thing; !thing; ) {} } for (var i = 0; i < NUM_LOOPS; i++) { shouldThrowTDZ(foo); } })(); ;(function() { function foo() { let thing = {}; for (let thing = eval("thing"); !truth(); ) {} } for (var i = 0; i < SHORT_LOOPS; i++) { shouldThrowTDZ(foo); } })(); ;(function() { function foo() { let thing = {}; for (let thing in thing) {} } function bar() { let thing = {hello: "world"} for (let thing in thing) {} } function baz() { let thing = {}; for (let thing in eval("thing")) {} } function bag() { let thing = {hello: "world"} for (let thing in eval("thing")) {} } for (var i = 0; i < SHORT_LOOPS; i++) { shouldThrowTDZ(foo); shouldThrowTDZ(bar); shouldThrowTDZ(baz); shouldThrowTDZ(bag); } })(); ;(function() { function foo() { let thing = ["hello"]; for (let thing in thing) {} } function bar() { let thing = []; for (let thing in thing) {} } function baz() { let thing = {hello: "world"}; for (let thing in thing) {} } function bag() { let empty = {}; for (let thing in empty) {} return thing; } function hat() { let notEmpty = {foo: "bar"}; for (let thing in notEmpty) { break; } return thing; } function cap() { let notEmpty = {foo: "bar"}; for (let thing in notEmpty) { continue; } return thing; } for (var i = 0; i < NUM_LOOPS; i++) { shouldThrowTDZ(foo); shouldThrowTDZ(bar); shouldThrowTDZ(baz); shouldThrowTDZ(bag); shouldThrowTDZ(hat); shouldThrowTDZ(cap); } })(); ;(function() { function foo() { let thing = ["hello"]; for (let thing of thing) {} } function bar() { let thing = []; for (let thing of thing) {} } function baz() { let thing = ["world"] for (let thing of thing) {} } function bag() { let empty = []; for (let thing of empty) {} return thing; } function hat() { let notEmpty = ["hello", "world"]; for (let thing of notEmpty) { break; } return thing; } function tap() { let notEmpty = [10, 20]; for (let thing of notEmpty) { } return thing; } function cap() { let notEmpty = [10, 20]; for (let thing of notEmpty) { continue; } return thing; } function pap() { let notEmpty = [10, 20]; for (let thing of notEmpty) { } return thing; } for (var i = 0; i < SHORT_LOOPS; i++) { shouldThrowTDZ(foo); shouldThrowTDZ(bar); shouldThrowTDZ(baz); shouldThrowTDZ(bag); shouldThrowTDZ(hat); shouldThrowTDZ(tap); shouldThrowTDZ(cap); shouldThrowTDZ(pap); } })(); ;(function() { function foo() { let x = 0; let arr = []; for (let x of (x=2, obj)) { x; } } function bar() { let x = 0; let obj = {}; for (let x in (x=2, obj)) { x; } } for (var i = 0; i < SHORT_LOOPS; i++) { shouldThrowTDZ(foo); shouldThrowTDZ(bar); } })(); ;(function() { let factorial = null; function test() { for (let factorial = function(x){ return x > 1 ? x * factorial(x - 1) : 1; }; true; ) { return factorial(5); } } assert(test() === 120); })(); ;(function() { function test() { for (let factorial = function(x){ return x > 1 ? x * factorial(x - 1) : 1; }; true; ) { return factorial(5); } } assert(test() === 120); })();