[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}
This commit is contained in:
parent
7fc183af06
commit
3b1aabc960
@ -1387,7 +1387,7 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
|
|||||||
case Token::VAR:
|
case Token::VAR:
|
||||||
return ParseVariableStatement(kStatementListItem, NULL, ok);
|
return ParseVariableStatement(kStatementListItem, NULL, ok);
|
||||||
case Token::LET:
|
case Token::LET:
|
||||||
if (is_strict(language_mode())) {
|
if (allow_let()) {
|
||||||
return ParseVariableStatement(kStatementListItem, NULL, ok);
|
return ParseVariableStatement(kStatementListItem, NULL, ok);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2049,7 +2049,7 @@ Variable* Parser::Declare(Declaration* declaration,
|
|||||||
// because the var declaration is hoisted to the function scope where 'x'
|
// because the var declaration is hoisted to the function scope where 'x'
|
||||||
// is already bound.
|
// is already bound.
|
||||||
DCHECK(IsDeclaredVariableMode(var->mode()));
|
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
|
// In harmony we treat re-declarations as early errors. See
|
||||||
// ES5 16 for a definition of early errors.
|
// ES5 16 for a definition of early errors.
|
||||||
if (declaration_kind == DeclarationDescriptor::NORMAL) {
|
if (declaration_kind == DeclarationDescriptor::NORMAL) {
|
||||||
@ -2207,7 +2207,7 @@ Statement* Parser::ParseFunctionDeclaration(
|
|||||||
VariableMode mode =
|
VariableMode mode =
|
||||||
is_strong(language_mode())
|
is_strong(language_mode())
|
||||||
? CONST
|
? CONST
|
||||||
: is_strict(language_mode()) &&
|
: (is_strict(language_mode()) || allow_harmony_sloppy()) &&
|
||||||
!(scope_->is_script_scope() || scope_->is_eval_scope() ||
|
!(scope_->is_script_scope() || scope_->is_eval_scope() ||
|
||||||
scope_->is_function_scope())
|
scope_->is_function_scope())
|
||||||
? LET
|
? LET
|
||||||
@ -2287,7 +2287,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
|||||||
|
|
||||||
|
|
||||||
Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
|
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);
|
return ParseScopedBlock(labels, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2439,14 +2439,14 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
|
|||||||
parsing_result->descriptor.init_op = Token::INIT_CONST_LEGACY;
|
parsing_result->descriptor.init_op = Token::INIT_CONST_LEGACY;
|
||||||
++use_counts_[v8::Isolate::kLegacyConst];
|
++use_counts_[v8::Isolate::kLegacyConst];
|
||||||
} else {
|
} else {
|
||||||
DCHECK(is_strict(language_mode()));
|
DCHECK(is_strict(language_mode()) || allow_harmony_sloppy());
|
||||||
DCHECK(var_context != kStatement);
|
DCHECK(var_context != kStatement);
|
||||||
parsing_result->descriptor.mode = CONST;
|
parsing_result->descriptor.mode = CONST;
|
||||||
parsing_result->descriptor.init_op = Token::INIT_CONST;
|
parsing_result->descriptor.init_op = Token::INIT_CONST;
|
||||||
}
|
}
|
||||||
parsing_result->descriptor.is_const = true;
|
parsing_result->descriptor.is_const = true;
|
||||||
parsing_result->descriptor.needs_init = 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);
|
Consume(Token::LET);
|
||||||
DCHECK(var_context != kStatement);
|
DCHECK(var_context != kStatement);
|
||||||
parsing_result->descriptor.mode = LET;
|
parsing_result->descriptor.mode = LET;
|
||||||
@ -3498,7 +3498,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
|||||||
DeclarationParsingResult parsing_result;
|
DeclarationParsingResult parsing_result;
|
||||||
if (peek() != Token::SEMICOLON) {
|
if (peek() != Token::SEMICOLON) {
|
||||||
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
|
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);
|
ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
|
||||||
is_const = parsing_result.descriptor.mode == CONST;
|
is_const = parsing_result.descriptor.mode == CONST;
|
||||||
|
|
||||||
@ -3973,6 +3973,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
Scope* original_declaration_scope = original_scope_->DeclarationScope();
|
Scope* original_declaration_scope = original_scope_->DeclarationScope();
|
||||||
Scope* scope = function_type == FunctionLiteral::DECLARATION &&
|
Scope* scope = function_type == FunctionLiteral::DECLARATION &&
|
||||||
is_sloppy(language_mode()) &&
|
is_sloppy(language_mode()) &&
|
||||||
|
!allow_harmony_sloppy() &&
|
||||||
(original_scope_ == original_declaration_scope ||
|
(original_scope_ == original_declaration_scope ||
|
||||||
declaration_scope != original_declaration_scope)
|
declaration_scope != original_declaration_scope)
|
||||||
? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
|
? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
|
||||||
@ -4030,11 +4031,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
Variable* fvar = NULL;
|
Variable* fvar = NULL;
|
||||||
Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
|
Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
|
||||||
if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
|
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;
|
fvar_init_op = Token::INIT_CONST;
|
||||||
}
|
}
|
||||||
VariableMode fvar_mode =
|
VariableMode fvar_mode = use_strict_const ? CONST : CONST_LEGACY;
|
||||||
is_strict(language_mode()) ? CONST : CONST_LEGACY;
|
|
||||||
DCHECK(function_name != NULL);
|
DCHECK(function_name != NULL);
|
||||||
fvar = new (zone())
|
fvar = new (zone())
|
||||||
Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
|
Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
|
||||||
|
@ -197,7 +197,7 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Token::LET:
|
case Token::LET:
|
||||||
if (is_strict(language_mode())) {
|
if (allow_let()) {
|
||||||
return ParseVariableStatement(kStatementListItem, ok);
|
return ParseVariableStatement(kStatementListItem, ok);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -456,7 +456,7 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
|
|||||||
Expect(Token::LBRACE, CHECK_OK);
|
Expect(Token::LBRACE, CHECK_OK);
|
||||||
Statement final = Statement::Default();
|
Statement final = Statement::Default();
|
||||||
while (peek() != Token::RBRACE) {
|
while (peek() != Token::RBRACE) {
|
||||||
if (is_strict(language_mode())) {
|
if (is_strict(language_mode()) || allow_harmony_sloppy()) {
|
||||||
final = ParseStatementListItem(CHECK_OK);
|
final = ParseStatementListItem(CHECK_OK);
|
||||||
} else {
|
} else {
|
||||||
final = ParseStatement(CHECK_OK);
|
final = ParseStatement(CHECK_OK);
|
||||||
@ -524,12 +524,13 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
|||||||
// existing pages. Therefore we keep allowing const with the old
|
// existing pages. Therefore we keep allowing const with the old
|
||||||
// non-harmony semantics in sloppy mode.
|
// non-harmony semantics in sloppy mode.
|
||||||
Consume(Token::CONST);
|
Consume(Token::CONST);
|
||||||
if (is_strict(language_mode())) {
|
if (is_strict(language_mode()) ||
|
||||||
|
(allow_harmony_sloppy() && !allow_legacy_const())) {
|
||||||
DCHECK(var_context != kStatement);
|
DCHECK(var_context != kStatement);
|
||||||
is_strict_const = true;
|
is_strict_const = true;
|
||||||
require_initializer = var_context != kForStatement;
|
require_initializer = var_context != kForStatement;
|
||||||
}
|
}
|
||||||
} else if (peek() == Token::LET && is_strict(language_mode())) {
|
} else if (peek() == Token::LET && allow_let()) {
|
||||||
Consume(Token::LET);
|
Consume(Token::LET);
|
||||||
DCHECK(var_context != kStatement);
|
DCHECK(var_context != kStatement);
|
||||||
} else {
|
} else {
|
||||||
@ -869,7 +870,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
|||||||
if (peek() != Token::SEMICOLON) {
|
if (peek() != Token::SEMICOLON) {
|
||||||
ForEachStatement::VisitMode mode;
|
ForEachStatement::VisitMode mode;
|
||||||
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
|
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
|
||||||
(peek() == Token::LET && is_strict(language_mode()))) {
|
(peek() == Token::LET && allow_let())) {
|
||||||
int decl_count;
|
int decl_count;
|
||||||
Scanner::Location first_initializer_loc = Scanner::Location::invalid();
|
Scanner::Location first_initializer_loc = Scanner::Location::invalid();
|
||||||
Scanner::Location bindings_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 is_generator() const { return function_state_->is_generator(); }
|
||||||
|
|
||||||
bool allow_const() {
|
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.
|
// Report syntax errors.
|
||||||
|
@ -6766,7 +6766,7 @@ TEST(NewTarget) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(LegacyConst) {
|
TEST(ConstLegacy) {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const char* context_data[][2] = {
|
const char* context_data[][2] = {
|
||||||
{"", ""},
|
{"", ""},
|
||||||
@ -6784,9 +6784,57 @@ TEST(LegacyConst) {
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
static const ParserFlag always_flags[] = {kNoLegacyConst};
|
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {kNoLegacyConst};
|
||||||
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
|
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
|
||||||
arraysize(always_flags));
|
arraysize(always_flags));
|
||||||
RunParserSyncTest(context_data, data, kSuccess);
|
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
|
// Verify that the context is correctly set in the stack frame after exiting
|
||||||
// from with.
|
// from eval.
|
||||||
function f() {}
|
function f() {}
|
||||||
|
|
||||||
(function(x) {
|
(function(x) {
|
||||||
|
159
test/mjsunit/harmony/block-const-assign-sloppy.js
Normal file
159
test/mjsunit/harmony/block-const-assign-sloppy.js
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
199
test/mjsunit/harmony/block-for-sloppy.js
Normal file
199
test/mjsunit/harmony/block-for-sloppy.js
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// 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; }"));
|
224
test/mjsunit/harmony/block-leave-sloppy.js
Normal file
224
test/mjsunit/harmony/block-leave-sloppy.js
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
483
test/mjsunit/harmony/block-let-crankshaft-sloppy.js
Normal file
483
test/mjsunit/harmony/block-let-crankshaft-sloppy.js
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
// 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);
|
157
test/mjsunit/harmony/block-let-declaration-sloppy.js
Normal file
157
test/mjsunit/harmony/block-let-declaration-sloppy.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
// 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() {} } }");
|
188
test/mjsunit/harmony/block-let-semantics-sloppy.js
Normal file
188
test/mjsunit/harmony/block-let-semantics-sloppy.js
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// 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());
|
269
test/mjsunit/harmony/block-scoping-sloppy.js
Normal file
269
test/mjsunit/harmony/block-scoping-sloppy.js
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
// 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();
|
34
test/mjsunit/harmony/block-scoping-top-level-sloppy.js
Normal file
34
test/mjsunit/harmony/block-scoping-top-level-sloppy.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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());
|
Loading…
Reference in New Issue
Block a user