v8/test/mjsunit/harmony/block-eval-var-over-let.js
littledan d515e5138d Test for var declarations in eval which conflict with let
Previously, name conflicts between var and let declarations were only
made into exceptions if they were visible at parse-time. This patch adds
runtime checks so that sloppy-mode direct eval can't introduce conflicting
var declarations. The change is implemented by traversing the scope chain
when a direct eval introduces a var declaration to look for conflicting
let declarations, up to the function boundary.

BUG=v8:4454
R=adamk
LOG=Y

Review URL: https://codereview.chromium.org/1382513003

Cr-Commit-Position: refs/heads/master@{#31211}
2015-10-12 14:31:01 +00:00

192 lines
3.1 KiB
JavaScript

// 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.
// Flags: --harmony-sloppy --harmony-sloppy-let --harmony-sloppy-function --no-legacy-const
// Var-let conflict in a function throws, even if the var is in an eval
let caught = false;
// Throws at the top level of a function
try {
(function() {
let x = 1;
eval('var x = 2');
})()
} catch (e) {
caught = true;
}
assertTrue(caught);
// If the eval is in its own block scope, throws
caught = false;
try {
(function() {
let y = 1;
{ eval('var y = 2'); }
})()
} catch (e) {
caught = true;
}
assertTrue(caught);
// If the let is in its own block scope, with the eval, throws
caught = false
try {
(function() {
{
let x = 1;
eval('var x = 2');
}
})();
} catch (e) {
caught = true;
}
assertTrue(caught);
// Legal if the let is no longer visible
caught = false
try {
(function() {
{
let x = 1;
}
eval('var x = 2');
})();
} catch (e) {
caught = true;
}
assertFalse(caught);
// All the same works for const:
// Throws at the top level of a function
try {
(function() {
const x = 1;
eval('var x = 2');
})();
} catch (e) {
caught = true;
}
assertTrue(caught);
// If the eval is in its own block scope, throws
caught = false;
try {
(function() {
const y = 1;
{ eval('var y = 2'); }
})();
} catch (e) {
caught = true;
}
assertTrue(caught);
// If the const is in its own block scope, with the eval, throws
caught = false
try {
(function() {
{
const x = 1;
eval('var x = 2');
}
})();
} catch (e) {
caught = true;
}
assertTrue(caught);
// Legal if the const is no longer visible
caught = false
try {
(function() {
{
const x = 1;
}
eval('var x = 2');
})();
} catch (e) {
caught = true;
}
assertFalse(caught);
// In global scope
caught = false;
try {
let z = 1;
eval('var z = 2');
} 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 = 2;");
}
})();
} 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 = 2;");
}
})();
} 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);
// TODO(littledan): Hoisting x out of the block should be
// prevented in this case BUG(v8:4479)
caught = false
try {
(function() {
{
let x = 1;
eval('{ function x() {} }');
}
})();
} catch (e) {
caught = true;
}
// TODO(littledan): switch to assertTrue when bug is fixed
assertTrue(caught);