// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Var-let conflict in a function throws, even if the var is in an eval // Throws at the top level of a function assertThrows(function() { let x = 1; eval('var x'); }, SyntaxError); // If the eval is in its own block scope, throws assertThrows(function() { let y = 1; { eval('var y'); } }, SyntaxError); // If the let is in its own block scope, with the eval, throws assertThrows(function() { { let x = 1; eval('var x'); } }, SyntaxError); // Legal if the let is no longer visible assertDoesNotThrow(function() { { let x = 1; } eval('var x'); }); // All the same works for const: // Throws at the top level of a function assertThrows(function() { const x = 1; eval('var x'); }, SyntaxError); // If the eval is in its own block scope, throws assertThrows(function() { const y = 1; { eval('var y'); } }, SyntaxError); // If the const is in its own block scope, with the eval, throws assertThrows(function() { { const x = 1; eval('var x'); } }, SyntaxError); // Legal if the const is no longer visible assertDoesNotThrow(function() { { const x = 1; } eval('var x'); }); // The same should work for lexical function declarations: // If the const is in its own block scope, with the eval, throws assertThrows(function() { { function x() {} eval('var x'); } }, SyntaxError); // If the eval is in its own block scope, throws assertThrows(function() { { function y() {} { eval('var y'); } } }, SyntaxError); // In global scope let caught = false; try { let z = 1; eval('var z'); } catch (e) { caught = true; } assertTrue(caught); // Let declarations beyond a function boundary don't conflict caught = false; try { let a = 1; (function() { eval('var a'); })(); } catch (e) { caught = true; } assertFalse(caught); // var across with doesn't conflict caught = false; try { (function() { with ({x: 1}) { eval("var x"); } })(); } catch (e) { caught = true; } assertFalse(caught); // var can still conflict with let across a with caught = false; try { (function() { let x; with ({x: 1}) { eval("var x"); } })(); } catch (e) { caught = true; } assertTrue(caught); // Functions declared in eval also conflict caught = false try { (function() { { let x = 1; eval('function x() {}'); } })(); } catch (e) { caught = true; } assertTrue(caught); // See ES#sec-web-compat-evaldeclarationinstantiation. Sloppy block functions // inside of blocks in eval behave similar to regular sloppy block function // hoisting: the var declaration on the function level is only created if // it would not cause a syntax error. A masking let would cause a conflicting // var declaration syntax error, and hence the var isn't introduced. (function() { { let x = 1; eval('{ function x() {} }'); assertEquals(1, x); } })();