Commit 3b1aabc9 authored by arv's avatar arv Committed by Commit bot

[es6] Initial support for let/const bindings in sloppy mode

Allow let in sloppy mode with --harmony-sloppy

Allow ES'15 const in sloppy mode with --harmony-sloppy --no-legacy-const

Functions in block are not done yet. They are only let bound in the block
at this point.

BUG=v8:3305, v8:2198
LOG=N
R=littledan@chromium.org, rossberg@chromium.org, adamk@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#29536}
parent 7fc183af
......@@ -1387,7 +1387,7 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
case Token::VAR:
return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::LET:
if (is_strict(language_mode())) {
if (allow_let()) {
return ParseVariableStatement(kStatementListItem, NULL, ok);
}
break;
......@@ -2049,7 +2049,7 @@ Variable* Parser::Declare(Declaration* declaration,
// because the var declaration is hoisted to the function scope where 'x'
// is already bound.
DCHECK(IsDeclaredVariableMode(var->mode()));
if (is_strict(language_mode())) {
if (is_strict(language_mode()) || allow_harmony_sloppy()) {
// In harmony we treat re-declarations as early errors. See
// ES5 16 for a definition of early errors.
if (declaration_kind == DeclarationDescriptor::NORMAL) {
......@@ -2207,7 +2207,7 @@ Statement* Parser::ParseFunctionDeclaration(
VariableMode mode =
is_strong(language_mode())
? CONST
: is_strict(language_mode()) &&
: (is_strict(language_mode()) || allow_harmony_sloppy()) &&
!(scope_->is_script_scope() || scope_->is_eval_scope() ||
scope_->is_function_scope())
? LET
......@@ -2287,7 +2287,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
if (is_strict(language_mode())) {
if (is_strict(language_mode()) || allow_harmony_sloppy()) {
return ParseScopedBlock(labels, ok);
}
......@@ -2439,14 +2439,14 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
parsing_result->descriptor.init_op = Token::INIT_CONST_LEGACY;
++use_counts_[v8::Isolate::kLegacyConst];
} else {
DCHECK(is_strict(language_mode()));
DCHECK(is_strict(language_mode()) || allow_harmony_sloppy());
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = CONST;
parsing_result->descriptor.init_op = Token::INIT_CONST;
}
parsing_result->descriptor.is_const = true;
parsing_result->descriptor.needs_init = true;
} else if (peek() == Token::LET && is_strict(language_mode())) {
} else if (peek() == Token::LET && allow_let()) {
Consume(Token::LET);
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = LET;
......@@ -3498,7 +3498,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
DeclarationParsingResult parsing_result;
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && is_strict(language_mode()))) {
(peek() == Token::LET && allow_let())) {
ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
is_const = parsing_result.descriptor.mode == CONST;
......@@ -3973,6 +3973,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Scope* original_declaration_scope = original_scope_->DeclarationScope();
Scope* scope = function_type == FunctionLiteral::DECLARATION &&
is_sloppy(language_mode()) &&
!allow_harmony_sloppy() &&
(original_scope_ == original_declaration_scope ||
declaration_scope != original_declaration_scope)
? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
......@@ -4030,11 +4031,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Variable* fvar = NULL;
Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
if (is_strict(language_mode())) {
bool use_strict_const = is_strict(language_mode()) ||
(!allow_legacy_const() && allow_harmony_sloppy());
if (use_strict_const) {
fvar_init_op = Token::INIT_CONST;
}
VariableMode fvar_mode =
is_strict(language_mode()) ? CONST : CONST_LEGACY;
VariableMode fvar_mode = use_strict_const ? CONST : CONST_LEGACY;
DCHECK(function_name != NULL);
fvar = new (zone())
Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
......
......@@ -197,7 +197,7 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
}
break;
case Token::LET:
if (is_strict(language_mode())) {
if (allow_let()) {
return ParseVariableStatement(kStatementListItem, ok);
}
break;
......@@ -456,7 +456,7 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
Expect(Token::LBRACE, CHECK_OK);
Statement final = Statement::Default();
while (peek() != Token::RBRACE) {
if (is_strict(language_mode())) {
if (is_strict(language_mode()) || allow_harmony_sloppy()) {
final = ParseStatementListItem(CHECK_OK);
} else {
final = ParseStatement(CHECK_OK);
......@@ -524,12 +524,13 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
// existing pages. Therefore we keep allowing const with the old
// non-harmony semantics in sloppy mode.
Consume(Token::CONST);
if (is_strict(language_mode())) {
if (is_strict(language_mode()) ||
(allow_harmony_sloppy() && !allow_legacy_const())) {
DCHECK(var_context != kStatement);
is_strict_const = true;
require_initializer = var_context != kForStatement;
}
} else if (peek() == Token::LET && is_strict(language_mode())) {
} else if (peek() == Token::LET && allow_let()) {
Consume(Token::LET);
DCHECK(var_context != kStatement);
} else {
......@@ -869,7 +870,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
if (peek() != Token::SEMICOLON) {
ForEachStatement::VisitMode mode;
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && is_strict(language_mode()))) {
(peek() == Token::LET && allow_let())) {
int decl_count;
Scanner::Location first_initializer_loc = Scanner::Location::invalid();
Scanner::Location bindings_loc = Scanner::Location::invalid();
......
......@@ -494,7 +494,12 @@ class ParserBase : public Traits {
bool is_generator() const { return function_state_->is_generator(); }
bool allow_const() {
return is_strict(language_mode()) || allow_legacy_const();
return is_strict(language_mode()) || allow_harmony_sloppy() ||
allow_legacy_const();
}
bool allow_let() {
return is_strict(language_mode()) || allow_harmony_sloppy();
}
// Report syntax errors.
......
......@@ -6766,7 +6766,7 @@ TEST(NewTarget) {
}
TEST(LegacyConst) {
TEST(ConstLegacy) {
// clang-format off
const char* context_data[][2] = {
{"", ""},
......@@ -6784,9 +6784,57 @@ TEST(LegacyConst) {
};
// clang-format on
static const ParserFlag always_flags[] = {kNoLegacyConst};
static const ParserFlag always_flags[] = {kNoLegacyConst};
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
RunParserSyncTest(context_data, data, kSuccess);
}
TEST(ConstSloppy) {
// clang-format off
const char* context_data[][2] = {
{"", ""},
{"{", "}"},
{NULL, NULL}
};
const char* data[] = {
"const x = 1",
"for (const x = 1; x < 1; x++) {}",
"for (const x in {}) {}",
"for (const x of []) {}",
NULL
};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonySloppy,
kNoLegacyConst};
RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(LetSloppy) {
// clang-format off
const char* context_data[][2] = {
{"", ""},
{"'use strict';", ""},
{"{", "}"},
{NULL, NULL}
};
const char* data[] = {
"let x",
"let x = 1",
"for (let x = 1; x < 1; x++) {}",
"for (let x in {}) {}",
"for (let x of []) {}",
NULL
};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonySloppy};
RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
}
......@@ -175,7 +175,7 @@ try {
// Verify that the context is correctly set in the stack frame after exiting
// from with.
// from eval.
function f() {}
(function(x) {
......
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --harmony-computed-property-names
// Flags: --no-legacy-const --harmony-sloppy
// Test that we throw early syntax errors in harmony mode
// when using an immutable binding in an assigment or with
// prefix/postfix decrement/increment operators.
const decls = [
// Const declaration.
function(use) { return "const c = 1; " + use + ";" }, TypeError,
function(use) { return "const x = 0, c = 1; " + use + ";" }, TypeError,
function(use) { return "const c = 1, x = (" + use + ");" }, TypeError,
function(use) { return use + "; const c = 1;" }, ReferenceError,
function(use) { return use + "; const x = 0, c = 1;" }, ReferenceError,
function(use) { return "const x = (" + use + "), c = 1;" }, ReferenceError,
function(use) { return "const c = (" + use + ");" }, ReferenceError,
// Function expression.
function(use) { return "(function c() { " + use + "; })();"; }, TypeError,
// TODO(rossberg): Once we have default parameters, test using 'c' there.
// Class expression.
function(use) {
return "new class c { constructor() { " + use + " } };";
}, TypeError,
function(use) {
return "(new class c { m() { " + use + " } }).m();";
}, TypeError,
function(use) {
return "(new class c { get a() { " + use + " } }).a;";
}, TypeError,
function(use) {
return "(new class c { set a(x) { " + use + " } }).a = 0;";
}, TypeError,
function(use) {
return "(class c { static m() { " + use + " } }).s();";
}, TypeError,
function(use) {
return "(class c extends (" + use + ") {});";
}, ReferenceError,
function(use) {
return "(class c { [" + use + "]() {} });";
}, ReferenceError,
function(use) {
return "(class c { get [" + use + "]() {} });";
}, ReferenceError,
function(use) {
return "(class c { set [" + use + "](x) {} });";
}, ReferenceError,
function(use) {
return "(class c { static [" + use + "]() {} });";
}, ReferenceError,
// For loop.
function(use) {
return "for (const c = 0; " + use + ";) {}"
}, TypeError,
function(use) {
return "for (const x = 0, c = 0; " + use + ";) {}"
}, TypeError,
function(use) {
return "for (const c = 0; ; " + use + ") {}"
}, TypeError,
function(use) {
return "for (const x = 0, c = 0; ; " + use + ") {}"
}, TypeError,
function(use) {
return "for (const c = 0; ;) { " + use + "; }"
}, TypeError,
function(use) {
return "for (const x = 0, c = 0; ;) { " + use + "; }"
}, TypeError,
function(use) {
return "for (const c in {a: 1}) { " + use + "; }"
}, TypeError,
function(use) {
return "for (const c of [1]) { " + use + "; }"
}, TypeError,
function(use) {
return "for (const x = (" + use + "), c = 0; ;) {}"
}, ReferenceError,
function(use) {
return "for (const c = (" + use + "); ;) {}"
}, ReferenceError,
]
let uses = [
'c = 1',
'c += 1',
'++c',
'c--',
];
let declcontexts = [
function(decl) { return decl; },
function(decl) { return "eval(\'" + decl + "\')"; },
function(decl) { return "{ " + decl + " }"; },
function(decl) { return "(function() { " + decl + " })()"; },
];
let usecontexts = [
function(use) { return use; },
function(use) { return "eval(\"" + use + "\")"; },
function(use) { return "(function() { " + use + " })()"; },
function(use) { return "(function() { eval(\"" + use + "\"); })()"; },
function(use) { return "eval(\"(function() { " + use + "; })\")()"; },
];
function Test(program, error) {
program = "'use strict'; " + program;
try {
print(program, " // throw " + error.name);
eval(program);
} catch (e) {
assertInstanceof(e, error);
if (e === TypeError) {
assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0);
}
return;
}
assertUnreachable();
}
for (var d = 0; d < decls.length; d += 2) {
for (var u = 0; u < uses.length; ++u) {
for (var o = 0; o < declcontexts.length; ++o) {
for (var i = 0; i < usecontexts.length; ++i) {
Test(declcontexts[o](decls[d](usecontexts[i](uses[u]))), decls[d + 1]);
}
}
}
}
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --no-legacy-const --harmony-sloppy
function props(x) {
var array = [];
for (let p in x) array.push(p);
return array.sort();
}
assertEquals(0, props({}).length);
assertEquals(1, props({x:1}).length);
assertEquals(2, props({x:1, y:2}).length);
assertArrayEquals(["x"], props({x:1}));
assertArrayEquals(["x", "y"], props({x:1, y:2}));
assertArrayEquals(["x", "y", "zoom"], props({x:1, y:2, zoom:3}));
assertEquals(0, props([]).length);
assertEquals(1, props([1]).length);
assertEquals(2, props([1,2]).length);
assertArrayEquals(["0"], props([1]));
assertArrayEquals(["0", "1"], props([1,2]));
assertArrayEquals(["0", "1", "2"], props([1,2,3]));
var o = {};
var a = [];
let i = "outer_i";
let s = "outer_s";
for (let i = 0x0020; i < 0x01ff; i+=2) {
let s = 'char:' + String.fromCharCode(i);
a.push(s);
o[s] = i;
}
assertArrayEquals(a, props(o));
assertEquals(i, "outer_i");
assertEquals(s, "outer_s");
var a = [];
assertEquals(0, props(a).length);
a[Math.pow(2,30)-1] = 0;
assertEquals(1, props(a).length);
a[Math.pow(2,31)-1] = 0;
assertEquals(2, props(a).length);
a[1] = 0;
assertEquals(3, props(a).length);
var result = '';
for (let p in {a : [0], b : 1}) { result += p; }
assertEquals('ab', result);
var result = '';
for (let p in {a : {v:1}, b : 1}) { result += p; }
assertEquals('ab', result);
var result = '';
for (let p in { get a() {}, b : 1}) { result += p; }
assertEquals('ab', result);
var result = '';
for (let p in { get a() {}, set a(x) {}, b : 1}) { result += p; }
assertEquals('ab', result);
// Check that there is exactly one variable without initializer
// in a for-in statement with let variables.
assertThrows("function foo() { 'use strict'; for (let in {}) { } }", SyntaxError);
assertThrows("function foo() { 'use strict'; for (let x = 3 in {}) { } }", SyntaxError);
assertThrows("function foo() { 'use strict'; for (let x, y in {}) { } }", SyntaxError);
assertThrows("function foo() { 'use strict'; for (let x = 3, y in {}) { } }", SyntaxError);
assertThrows("function foo() { 'use strict'; for (let x, y = 4 in {}) { } }", SyntaxError);
assertThrows("function foo() { 'use strict'; for (let x = 3, y = 4 in {}) { } }", SyntaxError);
// In a normal for statement the iteration variable is
// freshly allocated for each iteration.
function closures1() {
let a = [];
for (let i = 0; i < 5; ++i) {
a.push(function () { return i; });
}
for (let j = 0; j < 5; ++j) {
assertEquals(j, a[j]());
}
}
closures1();
function closures2() {
let a = [], b = [];
for (let i = 0, j = 10; i < 5; ++i, ++j) {
a.push(function () { return i; });
b.push(function () { return j; });
}
for (let k = 0; k < 5; ++k) {
assertEquals(k, a[k]());
assertEquals(k + 10, b[k]());
}
}
closures2();
function closure_in_for_init() {
let a = [];
for (let i = 0, f = function() { return i }; i < 5; ++i) {
a.push(f);
}
for (let k = 0; k < 5; ++k) {
assertEquals(0, a[k]());
}
}
closure_in_for_init();
function closure_in_for_cond() {
let a = [];
for (let i = 0; a.push(function () { return i; }), i < 5; ++i) { }
for (let k = 0; k < 5; ++k) {
assertEquals(k, a[k]());
}
}
closure_in_for_cond();
function closure_in_for_next() {
let a = [];
for (let i = 0; i < 5; a.push(function () { return i; }), ++i) { }
for (let k = 0; k < 5; ++k) {
assertEquals(k + 1, a[k]());
}
}
closure_in_for_next();
// In a for-in statement the iteration variable is fresh
// for each iteration.
function closures3(x) {
let a = [];
for (let p in x) {
a.push(function () { return p; });
}
let k = 0;
for (let q in x) {
assertEquals(q, a[k]());
++k;
}
}
closures3({a : [0], b : 1, c : {v : 1}, get d() {}, set e(x) {}});
// Check normal for statement completion values.
assertEquals(1, eval("for (let i = 0; i < 10; i++) { 1; }"));
assertEquals(9, eval("for (let i = 0; i < 10; i++) { i; }"));
assertEquals(undefined, eval("for (let i = 0; false;) { }"));
assertEquals(undefined, eval("for (const i = 0; false;) { }"));
assertEquals(undefined, eval("for (let i = 0; i < 10; i++) { }"));
assertEquals(undefined, eval("for (let i = 0; false;) { i; }"));
assertEquals(undefined, eval("for (const i = 0; false;) { i; }"));
assertEquals(undefined, eval("for (let i = 0; true;) { break; }"));
assertEquals(undefined, eval("for (const i = 0; true;) { break; }"));
assertEquals(undefined, eval("for (let i = 0; i < 10; i++) { continue; }"));
assertEquals(undefined, eval("for (let i = 0; true;) { break; i; }"));
assertEquals(undefined, eval("for (const i = 0; true;) { break; i; }"));
assertEquals(undefined, eval("for (let i = 0; i < 10; i++) { continue; i; }"));
assertEquals(0, eval("for (let i = 0; true;) { i; break; }"));
assertEquals(0, eval("for (const i = 0; true;) { i; break; }"));
assertEquals(9, eval("for (let i = 0; i < 10; i++) { i; continue; }"));
assertEquals(3, eval("for (let i = 0; true; i++) { i; if (i >= 3) break; }"));
assertEquals(2, eval("for (let i = 0; true; i++) { if (i >= 3) break; i; }"));
assertEquals(
2, eval("for (let i = 0; i < 10; i++) { if (i >= 3) continue; i; }"));
assertEquals(undefined, eval("foo: for (let i = 0; true;) { break foo; }"));
assertEquals(undefined, eval("foo: for (const i = 0; true;) { break foo; }"));
assertEquals(3, eval("foo: for (let i = 3; true;) { i; break foo; }"));
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --no-legacy-const --harmony-sloppy
// We want to test the context chain shape. In each of the tests cases
// below, the outer with is to force a runtime lookup of the identifier 'x'
// to actually verify that the inner context has been discarded. A static
// lookup of 'x' might accidentally succeed.
{
let x = 2;
L: {
let x = 3;
assertEquals(3, x);
break L;
assertTrue(false);
}
assertEquals(2, x);
}
do {
let x = 4;
assertEquals(4,x);
{
let x = 5;
assertEquals(5, x);
continue;
assertTrue(false);
}
} while (false);
var caught = false;
try {
{
let xx = 18;
throw 25;
assertTrue(false);
}
} catch (e) {
caught = true;
assertEquals(25, e);
(function () {
try {
// NOTE: This checks that the block scope containing xx has been
// removed from the context chain.
eval('xx');
assertTrue(false); // should not reach here
} catch (e2) {
assertTrue(e2 instanceof ReferenceError);
}
})();
}
assertTrue(caught);
(function(x) {
label: {
let x = 'inner';
break label;
}
assertEquals('outer', eval('x'));
})('outer');
(function(x) {
label: {
let x = 'middle';
{
let x = 'inner';
break label;
}
}
assertEquals('outer', eval('x'));
})('outer');
(function(x) {
for (var i = 0; i < 10; ++i) {
let x = 'inner' + i;
continue;
}
assertEquals('outer', eval('x'));
})('outer');
(function(x) {
label: for (var i = 0; i < 10; ++i) {
let x = 'middle' + i;
for (var j = 0; j < 10; ++j) {
let x = 'inner' + j;
continue label;
}
}
assertEquals('outer', eval('x'));
})('outer');
(function(x) {
try {
let x = 'inner';
throw 0;
} catch (e) {
assertEquals('outer', eval('x'));
}
})('outer');
(function(x) {
try {
let x = 'middle';
{
let x = 'inner';
throw 0;
}
} catch (e) {
assertEquals('outer', eval('x'));
}
})('outer');
try {
(function(x) {
try {
let x = 'inner';
throw 0;
} finally {
assertEquals('outer', eval('x'));
}
})('outer');
} catch (e) {
if (e instanceof MjsUnitAssertionError) throw e;
}
try {
(function(x) {
try {
let x = 'middle';
{
let x = 'inner';
throw 0;
}
} finally {
assertEquals('outer', eval('x'));
}
})('outer');
} catch (e) {
if (e instanceof MjsUnitAssertionError) throw e;
}
// Verify that the context is correctly set in the stack frame after exiting
// from eval.
function f() {}
(function(x) {
label: {
let x = 'inner';
break label;
}
f(); // The context could be restored from the stack after the call.
assertEquals('outer', eval('x'));
})('outer');
(function(x) {
for (var i = 0; i < 10; ++i) {
let x = 'inner';
continue;
}
f();
assertEquals('outer', eval('x'));
})('outer');
(function(x) {
try {
let x = 'inner';
throw 0;
} catch (e) {
f();
assertEquals('outer', eval('x'));
}
})('outer');
try {
(function(x) {
try {
let x = 'inner';
throw 0;
} finally {
f();
assertEquals('outer', eval('x'));
}
})('outer');
} catch (e) {
if (e instanceof MjsUnitAssertionError) throw e;
}
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
// Flags: --no-legacy-const --harmony-sloppy
// Check that the following functions are optimizable.
var functions = [ f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14,
f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26,
f27, f28, f29, f30, f31, f32, f33];
for (var i = 0; i < functions.length; ++i) {
var func = functions[i];
print("Testing:");
print(func);
for (var j = 0; j < 10; ++j) {
func(12);
}
%OptimizeFunctionOnNextCall(func);
func(12);
assertOptimized(func);
}
function f1() { }
function f2(x) { }
function f3() {
let x;
}
function f4() {
function foo() {
}
}
function f5() {
let x = 1;
}
function f6() {
const x = 1;
}
function f7(x) {
return x;
}
function f8() {
let x;
return x;
}
function f9() {
function x() {
}
return x;
}
function f10(x) {
x = 1;
}
function f11() {
let x;
x = 1;
}
function f12() {
function x() {};
x = 1;
}
function f13(x) {
(function() { x; });
}
function f14() {
let x;
(function() { x; });
}
function f15() {
function x() {
}
(function() { x; });
}
function f16() {
let x = 1;
(function() { x; });
}
function f17() {
const x = 1;
(function() { x; });
}
function f18(x) {
return x;
(function() { x; });
}
function f19() {
let x;
return x;
(function() { x; });
}
function f20() {
function x() {
}
return x;
(function() { x; });
}
function f21(x) {
x = 1;
(function() { x; });
}
function f22() {
let x;
x = 1;
(function() { x; });
}
function f23() {
function x() { }
x = 1;
(function() { x; });
}
function f24() {
let x = 1;
{
let x = 2;
{
let x = 3;
assertEquals(3, x);
}
assertEquals(2, x);
}
assertEquals(1, x);
}
function f25() {
{
let x = 2;
L: {
let x = 3;
assertEquals(3, x);
break L;
assertTrue(false);
}
assertEquals(2, x);
}
assertTrue(true);
}
function f26() {
{
let x = 1;
L: {
let x = 2;
{
let x = 3;
assertEquals(3, x);
break L;
assertTrue(false);
}
assertTrue(false);
}
assertEquals(1, x);
}
}
function f27() {
do {
let x = 4;
assertEquals(4,x);
{
let x = 5;
assertEquals(5, x);
continue;
assertTrue(false);
}
} while (false);
}
function f28() {
label: for (var i = 0; i < 10; ++i) {
let x = 'middle' + i;
for (var j = 0; j < 10; ++j) {
let x = 'inner' + j;
continue label;
}
}
}
function f29() {
// Verify that the context is correctly set in the stack frame after exiting
// from with.
let x = 'outer';
label: {
let x = 'inner';
break label;
}
f(); // The context could be restored from the stack after the call.
assertEquals('outer', x);
function f() {
assertEquals('outer', x);
};
}
function f30() {
let x = 'outer';
for (var i = 0; i < 10; ++i) {
let x = 'inner';
continue;
}
f();
assertEquals('outer', x);
function f() {
assertEquals('outer', x);
};
}
function f31() {
{
let x = 'outer';
label: for (var i = 0; assertEquals('outer', x), i < 10; ++i) {
let x = 'middle' + i;
{
let x = 'inner' + j;
continue label;
}
}
assertEquals('outer', x);
}
}
var c = true;
function f32() {
{
let x = 'outer';
L: {
{
let x = 'inner';
if (c) {
break L;
}
}
foo();
}
}
function foo() {
return 'bar';
}
}
function f33() {
{
let x = 'outer';
L: {
{
let x = 'inner';
if (c) {
break L;
}
foo();
}
}
}
function foo() {
return 'bar';
}
}
function TestThrow() {
function f() {
let x = 'outer';
{
let x = 'inner';
throw x;
}
}
for (var i = 0; i < 5; i++) {
try {
f();
} catch (e) {
assertEquals('inner', e);
}
}
%OptimizeFunctionOnNextCall(f);
try {
f();
} catch (e) {
assertEquals('inner', e);
}
assertOptimized(f);
}
TestThrow();
// Test that temporal dead zone semantics for function and block scoped
// let bindings are handled by the optimizing compiler.
function TestFunctionLocal(s) {
'use strict';
var func = eval("(function baz(){" + s + "; })");
print("Testing:");
print(func);
for (var i = 0; i < 5; ++i) {
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
%OptimizeFunctionOnNextCall(func);
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
function TestFunctionContext(s) {
'use strict';
var func = eval("(function baz(){ " + s + "; (function() { x; }); })");
print("Testing:");
print(func);
for (var i = 0; i < 5; ++i) {
print(i);
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
print("optimize");
%OptimizeFunctionOnNextCall(func);
try {
print("call");
func();
assertUnreachable();
} catch (e) {
print("catch");
assertInstanceof(e, ReferenceError);
}
}
function TestBlockLocal(s) {
'use strict';
var func = eval("(function baz(){ { " + s + "; } })");
print("Testing:");
print(func);
for (var i = 0; i < 5; ++i) {
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
%OptimizeFunctionOnNextCall(func);
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
function TestBlockContext(s) {
'use strict';
var func = eval("(function baz(){ { " + s + "; (function() { x; }); } })");
print("Testing:");
print(func);
for (var i = 0; i < 5; ++i) {
print(i);
try {
func();
assertUnreachable();
} catch (e) {
assertInstanceof(e, ReferenceError);
}
}
print("optimize");
%OptimizeFunctionOnNextCall(func);
try {
print("call");
func();
assertUnreachable();
} catch (e) {
print("catch");
assertInstanceof(e, ReferenceError);
}
}
function TestAll(s) {
TestFunctionLocal(s);
TestFunctionContext(s);
TestBlockLocal(s);
TestBlockContext(s);
}
// Use before initialization in declaration statement.
TestAll('let x = x + 1');
TestAll('let x = x += 1');
TestAll('let x = x++');
TestAll('let x = ++x');
TestAll('const x = x + 1');
// Use before initialization in prior statement.
TestAll('x + 1; let x;');
TestAll('x = 1; let x;');
TestAll('x += 1; let x;');
TestAll('++x; let x;');
TestAll('x++; let x;');
TestAll('let y = x; const x = 1;');
function f(x) {
let y = x + 42;
return y;
}
function g(x) {
{
let y = x + 42;
return y;
}
}
for (var i=0; i<10; i++) {
f(i);
g(i);
}
%OptimizeFunctionOnNextCall(f);
%OptimizeFunctionOnNextCall(g);
f(12);
g(12);
assertTrue(%GetOptimizationStatus(f) != 2);
assertTrue(%GetOptimizationStatus(g) != 2);
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test let declarations in various settings.
// Flags: --no-legacy-const --harmony-sloppy
// Global
let x;
let y = 2;
const z = 4;
// Block local
{
let y;
let x = 3;
const z = 5;
}
assertEquals(undefined, x);
assertEquals(2,y);
assertEquals(4,z);
if (true) {
let y;
assertEquals(undefined, y);
}
// Invalid declarations are early errors in harmony mode and thus should trigger
// an exception in eval code during parsing, before even compiling or executing
// the code. Thus the generated function is not called here.
function TestLocalThrows(str, expect) {
assertThrows("(function(arg){ 'use strict'; " + str + "})", expect);
}
function TestLocalDoesNotThrow(str) {
assertDoesNotThrow("(function(arg){ 'use strict'; " + str + "})()");
}
// Test let declarations in statement positions.
TestLocalThrows("if (true) let x;", SyntaxError);
TestLocalThrows("if (true) {} else let x;", SyntaxError);
TestLocalThrows("do let x; while (false)", SyntaxError);
TestLocalThrows("while (false) let x;", SyntaxError);
TestLocalThrows("label: let x;", SyntaxError);
TestLocalThrows("for (;false;) let x;", SyntaxError);
TestLocalDoesNotThrow("switch (true) { case true: let x; }");
TestLocalDoesNotThrow("switch (true) { default: let x; }");
// Test const declarations with initialisers in statement positions.
TestLocalThrows("if (true) const x = 1;", SyntaxError);
TestLocalThrows("if (true) {} else const x = 1;", SyntaxError);
TestLocalThrows("do const x = 1; while (false)", SyntaxError);
TestLocalThrows("while (false) const x = 1;", SyntaxError);
TestLocalThrows("label: const x = 1;", SyntaxError);
TestLocalThrows("for (;false;) const x = 1;", SyntaxError);
TestLocalDoesNotThrow("switch (true) { case true: const x = 1; }");
TestLocalDoesNotThrow("switch (true) { default: const x = 1; }");
// Test const declarations without initialisers.
TestLocalThrows("const x;", SyntaxError);
TestLocalThrows("const x = 1, y;", SyntaxError);
TestLocalThrows("const x, y = 1;", SyntaxError);
// Test const declarations without initialisers in statement positions.
TestLocalThrows("if (true) const x;", SyntaxError);
TestLocalThrows("if (true) {} else const x;", SyntaxError);
TestLocalThrows("do const x; while (false)", SyntaxError);
TestLocalThrows("while (false) const x;", SyntaxError);
TestLocalThrows("label: const x;", SyntaxError);
TestLocalThrows("for (;false;) const x;", SyntaxError);
TestLocalThrows("switch (true) { case true: const x; }", SyntaxError);
TestLocalThrows("switch (true) { default: const x; }", SyntaxError);
// Test var declarations in statement positions.
TestLocalDoesNotThrow("if (true) var x;");
TestLocalDoesNotThrow("if (true) {} else var x;");
TestLocalDoesNotThrow("do var x; while (false)");
TestLocalDoesNotThrow("while (false) var x;");
TestLocalDoesNotThrow("label: var x;");
TestLocalDoesNotThrow("for (;false;) var x;");
TestLocalDoesNotThrow("switch (true) { case true: var x; }");
TestLocalDoesNotThrow("switch (true) { default: var x; }");
// Test that redeclarations of functions are only allowed in outermost scope.
TestLocalThrows("{ let f; var f; }");
TestLocalThrows("{ var f; let f; }");
TestLocalThrows("{ function f() {} let f; }");
TestLocalThrows("{ let f; function f() {} }");
TestLocalThrows("{ function f() {} var f; }");
TestLocalThrows("{ var f; function f() {} }");
TestLocalThrows("{ function f() {} function f() {} }");
TestLocalThrows("function f() {} let f;");
TestLocalThrows("let f; function f() {}");
TestLocalDoesNotThrow("function arg() {}");
TestLocalDoesNotThrow("function f() {} var f;");
TestLocalDoesNotThrow("var f; function f() {}");
TestLocalDoesNotThrow("function f() {} function f() {}");
function g(f) {
function f() { return 1 }
return f()
}
assertEquals(1, g(function() { return 2 }))
// Test function declarations in source element and
// sloppy statement positions.
function f() {
// Sloppy source element positions.
function g0() {
"use strict";
// Strict source element positions.
function h() { }
{
function h1() { }
}
}
{
function g1() { }
}
}
f();
// Test function declarations in statement position in strict mode.
TestLocalThrows("function f() { if (true) function g() {} }", SyntaxError);
TestLocalThrows("function f() { if (true) {} else function g() {} }", SyntaxError);
TestLocalThrows("function f() { do function g() {} while (false) }", SyntaxError);
TestLocalThrows("function f() { while (false) function g() {} }", SyntaxError);
TestLocalThrows("function f() { label: function g() {} }", SyntaxError);
TestLocalThrows("function f() { for (;false;) function g() {} }", SyntaxError);
TestLocalDoesNotThrow("function f() { switch (true) { case true: function g() {} } }");
TestLocalDoesNotThrow("function f() { switch (true) { default: function g() {} } }");
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --harmony-sloppy --no-legacy-const
// Test temporal dead zone semantics of let bound variables in
// function and block scopes.
function TestFunctionLocal(s) {
try {
eval("(function(){" + s + "; })")();
} catch (e) {
assertInstanceof(e, ReferenceError);
return;
}
assertUnreachable();
}
function TestBlockLocal(s,e) {
try {
eval("(function(){ {" + s + ";} })")();
} catch (e) {
assertInstanceof(e, ReferenceError);
return;
}
assertUnreachable();
}
function TestAll(s) {
TestBlockLocal(s);
TestFunctionLocal(s);
}
// Use before initialization in declaration statement.
TestAll('let x = x + 1');
TestAll('let x = x += 1');
TestAll('let x = x++');
TestAll('let x = ++x');
TestAll('const x = x + 1');
// Use before initialization in prior statement.
TestAll('x + 1; let x;');
TestAll('x = 1; let x;');
TestAll('x += 1; let x;');
TestAll('++x; let x;');
TestAll('x++; let x;');
TestAll('let y = x; const x = 1;');
TestAll('f(); let x; function f() { return x + 1; }');
TestAll('f(); let x; function f() { x = 1; }');
TestAll('f(); let x; function f() { x += 1; }');
TestAll('f(); let x; function f() { ++x; }');
TestAll('f(); let x; function f() { x++; }');
TestAll('f(); const x = 1; function f() { return x; }');
TestAll('f()(); let x; function f() { return function() { return x + 1; } }');
TestAll('f()(); let x; function f() { return function() { x = 1; } }');
TestAll('f()(); let x; function f() { return function() { x += 1; } }');
TestAll('f()(); let x; function f() { return function() { ++x; } }');
TestAll('f()(); let x; function f() { return function() { x++; } }');
TestAll('f()(); const x = 1; function f() { return function() { return x; } }');
// Use before initialization with a dynamic lookup.
TestAll('eval("x + 1;"); let x;');
TestAll('eval("x = 1;"); let x;');
TestAll('eval("x += 1;"); let x;');
TestAll('eval("++x;"); let x;');
TestAll('eval("x++;"); let x;');
TestAll('eval("x"); const x = 1;');
// Use before initialization with check for eval-shadowed bindings.
TestAll('function f() { eval("var y = 2;"); x + 1; }; f(); let x;');
// TODO(arv): https://code.google.com/p/v8/issues/detail?id=4284
// TestAll('function f() { eval("var y = 2;"); x = 1; }; f(); let x;');
TestAll('function f() { eval("var y = 2;"); x += 1; }; f(); let x;');
TestAll('function f() { eval("var y = 2;"); ++x; }; f(); let x;');
TestAll('function f() { eval("var y = 2;"); x++; }; f(); let x;');
// Test that variables introduced by function declarations are created and
// initialized upon entering a function / block scope.
function f() {
{
assertEquals(2, g1());
assertEquals(2, eval("g1()"));
// block scoped function declaration
function g1() {
return 2;
}
}
assertEquals(3, g2());
assertEquals(3, eval("g2()"));
// function scoped function declaration
function g2() {
return 3;
}
}
f();
// Test that a function declaration introduces a block scoped variable.
TestAll('{ function k() { return 0; } }; k(); ');
// Test that a function declaration sees the scope it resides in.
function f2() {
let m, n, o, p;
{
m = g;
function g() {
return a;
}
let a = 1;
}
assertEquals(1, m());
try {
throw 2;
} catch(b) {
n = h;
function h() {
return b + c;
}
let c = 3;
}
assertEquals(5, n());
{
o = i;
function i() {
return d;
}
let d = 4;
}
assertEquals(4, o());
try {
throw 5;
} catch(e) {
p = j;
function j() {
return e + f;
}
let f = 6;
}
assertEquals(11, p());
}
f2();
// Test that resolution of let bound variables works with scopes that call eval.
function outer() {
function middle() {
function inner() {
return x;
}
eval("1 + 1");
return x + inner();
}
let x = 1;
return middle();
}
assertEquals(2, outer());
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --harmony-sloppy --no-legacy-const
// Test functionality of block scopes.
// Hoisting of var declarations.
function f1() {
{
var x = 1;
var y;
}
assertEquals(1, x)
assertEquals(undefined, y)
}
for (var j = 0; j < 5; ++j) f1();
%OptimizeFunctionOnNextCall(f1);
f1();
assertTrue(%GetOptimizationStatus(f1) != 2);
// Dynamic lookup in and through block contexts.
function f2(one) {
var x = one + 1;
let y = one + 2;
const u = one + 4;
{
let z = one + 3;
const v = one + 5;
assertEquals(1, eval('one'));
assertEquals(2, eval('x'));
assertEquals(3, eval('y'));
assertEquals(4, eval('z'));
assertEquals(5, eval('u'));
assertEquals(6, eval('v'));
}
}
f2(1);
// Lookup in and through block contexts.
function f3(one) {
var x = one + 1;
let y = one + 2;
const u = one + 4;
{
let z = one + 3;
const v = one + 5;
assertEquals(1, one);
assertEquals(2, x);
assertEquals(3, y);
assertEquals(4, z);
assertEquals(5, u);
assertEquals(6, v);
}
}
for (var j = 0; j < 5; ++j) f3(1);
%OptimizeFunctionOnNextCall(f3);
f3(1);
assertTrue(%GetOptimizationStatus(f3) != 2);
// Dynamic lookup from closure.
function f4(one) {
var x = one + 1;
let y = one + 2;
const u = one + 4;
{
let z = one + 3;
const v = one + 5;
function f() {
assertEquals(1, eval('one'));
assertEquals(2, eval('x'));
assertEquals(3, eval('y'));
assertEquals(4, eval('z'));
assertEquals(5, eval('u'));
assertEquals(6, eval('v'));
}
f();
}
}
f4(1);
// Lookup from closure.
function f5(one) {
var x = one + 1;
let y = one + 2;
const u = one + 4;
{
let z = one + 3;
const v = one + 5;
function f() {
assertEquals(1, one);
assertEquals(2, x);
assertEquals(3, y);
assertEquals(4, z);
assertEquals(5, u);
assertEquals(6, v);
}
f();
}
}
f5(1);
// Return from block.
function f6() {
let x = 1;
const u = 3;
{
let y = 2;
const v = 4;
return x + y;
}
}
assertEquals(3, f6(6));
// Variable shadowing and lookup.
function f7(a) {
let b = 1;
var c = 1;
var d = 1;
const e = 1;
{ // let variables shadowing argument, let, const and var variables
let a = 2;
let b = 2;
let c = 2;
let e = 2;
assertEquals(2,a);
assertEquals(2,b);
assertEquals(2,c);
assertEquals(2,e);
}
{ // const variables shadowing argument, let, const and var variables
const a = 2;
const b = 2;
const c = 2;
const e = 2;
assertEquals(2,a);
assertEquals(2,b);
assertEquals(2,c);
assertEquals(2,e);
}
try {
throw 'stuff1';
} catch (a) {
assertEquals('stuff1',a);
// catch variable shadowing argument
a = 2;
assertEquals(2,a);
{
// let variable shadowing catch variable
let a = 3;
assertEquals(3,a);
try {
throw 'stuff2';
} catch (a) {
assertEquals('stuff2',a);
// catch variable shadowing let variable
a = 4;
assertEquals(4,a);
}
assertEquals(3,a);
}
assertEquals(2,a);
}
try {
throw 'stuff3';
} catch (c) {
// catch variable shadowing var variable
assertEquals('stuff3',c);
{
// const variable shadowing catch variable
const c = 3;
assertEquals(3,c);
}
assertEquals('stuff3',c);
try {
throw 'stuff4';
} catch(c) {
assertEquals('stuff4',c);
// catch variable shadowing catch variable
c = 3;
assertEquals(3,c);
}
(function(c) {
// argument shadowing catch variable
c = 3;
assertEquals(3,c);
})();
assertEquals('stuff3', c);
(function() {
// var variable shadowing catch variable
var c = 3;
})();
assertEquals('stuff3', c);
c = 2;
}
assertEquals(1,c);
(function(a,b,c,e) {
// arguments shadowing argument, let, const and var variable
a = 2;
b = 2;
c = 2;
e = 2;
assertEquals(2,a);
assertEquals(2,b);
assertEquals(2,c);
assertEquals(2,e);
// var variable shadowing var variable
var d = 2;
})(1,1);
assertEquals(1,a);
assertEquals(1,b);
assertEquals(1,c);
assertEquals(1,d);
assertEquals(1,e);
}
f7(1);
// Ensure let and const variables are block local
// and var variables function local.
function f8() {
var let_accessors = [];
var var_accessors = [];
var const_accessors = [];
for (var i = 0; i < 10; i++) {
let x = i;
var y = i;
const z = i;
let_accessors[i] = function() { return x; }
var_accessors[i] = function() { return y; }
const_accessors[i] = function() { return z; }
}
for (var j = 0; j < 10; j++) {
y = j + 10;
assertEquals(j, let_accessors[j]());
assertEquals(y, var_accessors[j]());
assertEquals(j, const_accessors[j]());
}
}
f8();
// 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: --min-preparse-length=0
// Flags: --no-legacy-const --harmony-sloppy
let xxx = 1;
let f = undefined;
{
let inner_x = xxx;
f = function() { return inner_x; };
}
assertSame(1, f());
xxx = 42;
{
f = function() { return inner_x1; };
let inner_x1 = xxx;
}
assertSame(42, f());
xxx = 31;
{
let inner_x1 = xxx;
try {
throw new Error();
} catch (e) {
f = function() { return inner_x1; };
}
}
assertSame(31, f());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment