Commit 2ecdf736 authored by rossberg's avatar rossberg Committed by Commit bot

Fix exception for assignment to uninitialised const

R=dslomov@chromium.org, mstarzinger@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#27014}
parent 95c1f5dd
......@@ -2726,25 +2726,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
__ ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ push(r0);
__ mov(r0, Operand(var->name()));
__ Push(cp, r0); // Context and name.
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, r1);
__ ldr(r2, location);
__ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
__ b(ne, &skip);
EmitStoreToStackLocalOrContextSlot(var, location);
__ bind(&skip);
}
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
......@@ -2761,6 +2742,21 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
__ bind(&assign);
EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->mode() == CONST && op != Token::INIT_CONST) {
// Assignment to const variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label const_error;
MemOperand location = VarOperand(var, r1);
__ ldr(r3, location);
__ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
__ b(ne, &const_error);
__ mov(r3, Operand(var->name()));
__ push(r3);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&const_error);
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
if (var->IsLookupSlot()) {
// Assignment to var.
......@@ -2782,8 +2778,33 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
}
EmitStoreToStackLocalOrContextSlot(var, location);
}
} else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(var->mode() == CONST_LEGACY);
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ push(r0);
__ mov(r0, Operand(var->name()));
__ Push(cp, r0); // Context and name.
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, r1);
__ ldr(r2, location);
__ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
__ b(ne, &skip);
EmitStoreToStackLocalOrContextSlot(var, location);
__ bind(&skip);
}
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
}
// Silently ignore store in sloppy mode.
}
}
......
......@@ -2415,23 +2415,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ Mov(x1, Operand(var->name()));
__ Push(x0, cp, x1);
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackLocal() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, x1);
__ Ldr(x10, location);
__ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &skip);
EmitStoreToStackLocalOrContextSlot(var, location);
__ Bind(&skip);
}
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
......@@ -2447,6 +2430,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Bind(&assign);
EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->mode() == CONST && op != Token::INIT_CONST) {
// Assignment to const variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label const_error;
MemOperand location = VarOperand(var, x1);
__ Ldr(x10, location);
__ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &const_error);
__ Mov(x10, Operand(var->name()));
__ Push(x10);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ Bind(&const_error);
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
if (var->IsLookupSlot()) {
// Assignment to var.
......@@ -2470,8 +2467,31 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
}
EmitStoreToStackLocalOrContextSlot(var, location);
}
} else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(var->mode() == CONST_LEGACY);
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ Mov(x1, Operand(var->name()));
__ Push(x0, cp, x1);
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackLocal() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, x1);
__ Ldr(x10, location);
__ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &skip);
EmitStoreToStackLocalOrContextSlot(var, location);
__ Bind(&skip);
}
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
}
// Silently ignore store in sloppy mode.
}
}
......
......@@ -2701,7 +2701,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
value = BuildHoleCheckSilent(current, value, current);
}
} else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
// Non-initializing assignments to legacy const is
// Non-initializing assignment to legacy const is
// - exception in strict mode.
// - ignored in sloppy mode.
if (is_strict(language_mode())) {
......@@ -2720,7 +2720,13 @@ Node* AstGraphBuilder::BuildVariableAssignment(
value = BuildHoleCheckThrow(current, variable, value, bailout_id);
}
} else if (mode == CONST && op != Token::INIT_CONST) {
// Non-initializing assignments to const is exception in all modes.
// Assignment to const is exception in all modes.
Node* current = environment()->Lookup(variable);
if (current->op() == the_hole->op()) {
return BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) {
BuildHoleCheckThrow(current, variable, value, bailout_id);
}
return BuildThrowConstAssignError(bailout_id);
}
environment()->Bind(variable, value);
......@@ -2735,7 +2741,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
Node* current = NewNode(op, current_context());
value = BuildHoleCheckSilent(current, value, current);
} else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
// Non-initializing assignments to legacy const is
// Non-initializing assignment to legacy const is
// - exception in strict mode.
// - ignored in sloppy mode.
if (is_strict(language_mode())) {
......@@ -2749,7 +2755,11 @@ Node* AstGraphBuilder::BuildVariableAssignment(
Node* current = NewNode(op, current_context());
value = BuildHoleCheckThrow(current, variable, value, bailout_id);
} else if (mode == CONST && op != Token::INIT_CONST) {
// Non-initializing assignments to const is exception in all modes.
// Assignment to const is exception in all modes.
const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
BuildHoleCheckThrow(current, variable, value, bailout_id);
return BuildThrowConstAssignError(bailout_id);
}
const Operator* op = javascript()->StoreContext(depth, variable->index());
......
......@@ -589,19 +589,6 @@ class FullCodeGenerator: public AstVisitor {
// is expected in the accumulator.
void EmitAssignment(Expression* expr);
// Shall an error be thrown if assignment with 'op' operation is perfomed
// on this variable in given language mode?
static bool IsSignallingAssignmentToConst(Variable* var, Token::Value op,
LanguageMode language_mode) {
if (var->mode() == CONST) return op != Token::INIT_CONST;
if (var->mode() == CONST_LEGACY) {
return is_strict(language_mode) && op != Token::INIT_CONST_LEGACY;
}
return false;
}
// Complete a variable assignment. The right-hand-side value is expected
// in the accumulator.
void EmitVariableAssignment(Variable* var,
......
......@@ -2632,25 +2632,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ push(eax);
__ push(esi);
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackLocal() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, ecx);
__ mov(edx, location);
__ cmp(edx, isolate()->factory()->the_hole_value());
__ j(not_equal, &skip, Label::kNear);
EmitStoreToStackLocalOrContextSlot(var, location);
__ bind(&skip);
}
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
......@@ -2664,6 +2645,21 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&assign);
EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->mode() == CONST && op != Token::INIT_CONST) {
// Assignment to const variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label const_error;
MemOperand location = VarOperand(var, ecx);
__ mov(edx, location);
__ cmp(edx, isolate()->factory()->the_hole_value());
__ j(not_equal, &const_error, Label::kNear);
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&const_error);
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
if (var->IsLookupSlot()) {
// Assignment to var.
......@@ -2685,8 +2681,33 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
}
EmitStoreToStackLocalOrContextSlot(var, location);
}
} else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(var->mode() == CONST_LEGACY);
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ push(eax);
__ push(esi);
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackLocal() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, ecx);
__ mov(edx, location);
__ cmp(edx, isolate()->factory()->the_hole_value());
__ j(not_equal, &skip, Label::kNear);
EmitStoreToStackLocalOrContextSlot(var, location);
__ bind(&skip);
}
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
}
// Silently ignore store in sloppy mode.
}
}
......
......@@ -1551,7 +1551,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
Handle<Context> script_context = ScriptContextTable::GetContext(
script_contexts, lookup_result.context_index);
if (lookup_result.mode == CONST) {
return TypeError("harmony_const_assign", object, name);
return TypeError("const_assign", object, name);
}
if (FLAG_use_ic &&
......
......@@ -174,7 +174,7 @@ var kMessages = {
generator_poison_pill: ["'caller' and 'arguments' properties may not be accessed on generator functions."],
cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
harmony_const_assign: ["Assignment to constant variable."],
const_assign: ["Assignment to constant variable."],
symbol_to_string: ["Cannot convert a Symbol value to a string"],
symbol_to_primitive: ["Cannot convert a Symbol wrapper object to a primitive value"],
symbol_to_number: ["Cannot convert a Symbol value to a number"],
......
......@@ -26,7 +26,7 @@ RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
HandleScope scope(isolate);
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError("harmony_const_assign", HandleVector<Object>(NULL, 0)));
NewTypeError("const_assign", HandleVector<Object>(NULL, 0)));
}
......
......@@ -2635,25 +2635,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ movp(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
CallStoreIC();
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ Push(rax);
__ Push(rsi);
__ Push(var->name());
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackLocal() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, rcx);
__ movp(rdx, location);
__ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &skip);
EmitStoreToStackLocalOrContextSlot(var, location);
__ bind(&skip);
}
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
......@@ -2668,6 +2649,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ bind(&assign);
EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->mode() == CONST && op != Token::INIT_CONST) {
// Assignment to const variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label const_error;
MemOperand location = VarOperand(var, rcx);
__ movp(rdx, location);
__ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &const_error, Label::kNear);
__ Push(var->name());
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&const_error);
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
if (var->IsLookupSlot()) {
// Assignment to var.
......@@ -2689,8 +2684,33 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
}
EmitStoreToStackLocalOrContextSlot(var, location);
}
} else if (IsSignallingAssignmentToConst(var, op, language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
} else if (op == Token::INIT_CONST_LEGACY) {
// Const initializers need a write barrier.
DCHECK(var->mode() == CONST_LEGACY);
DCHECK(!var->IsParameter()); // No const parameters.
if (var->IsLookupSlot()) {
__ Push(rax);
__ Push(rsi);
__ Push(var->name());
__ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
DCHECK(var->IsStackLocal() || var->IsContextSlot());
Label skip;
MemOperand location = VarOperand(var, rcx);
__ movp(rdx, location);
__ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &skip);
EmitStoreToStackLocalOrContextSlot(var, location);
__ bind(&skip);
}
} else {
DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT_CONST_LEGACY);
if (is_strict(language_mode())) {
__ CallRuntime(Runtime::kThrowConstAssignError, 0);
}
// Silently ignore store in sloppy mode.
}
}
......
......@@ -25,7 +25,7 @@
// (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-scoping
// Flags: --harmony-scoping --harmony-computed-property-names
// Test that we throw early syntax errors in harmony mode
// when using an immutable binding in an assigment or with
......@@ -33,124 +33,128 @@
"use strict";
// Function local const.
function constDecl0(use) {
return "(function() { const constvar = 1; " + use + "; })();";
}
function constDecl1(use) {
return "(function() { " + use + "; const constvar = 1; })();";
}
// Function local const, assign from eval.
function constDecl2(use) {
use = "eval('(function() { " + use + " })')()";
return "(function() { const constvar = 1; " + use + "; })();";
}
function constDecl3(use) {
use = "eval('(function() { " + use + " })')()";
return "(function() { " + use + "; const constvar = 1; })();";
}
// Block local const.
function constDecl4(use) {
return "(function() { { const constvar = 1; " + use + "; } })();";
}
function constDecl5(use) {
return "(function() { { " + use + "; const constvar = 1; } })();";
}
// Block local const, assign from eval.
function constDecl6(use) {
use = "eval('(function() {" + use + "})')()";
return "(function() { { const constvar = 1; " + use + "; } })();";
}
function constDecl7(use) {
use = "eval('(function() {" + use + "})')()";
return "(function() { { " + use + "; const constvar = 1; } })();";
}
// Function expression name.
function constDecl8(use) {
return "(function constvar() { " + use + "; })();";
}
// Function expression name, assign from eval.
function constDecl9(use) {
use = "eval('(function(){" + use + "})')()";
return "(function constvar() { " + use + "; })();";
}
// For loop variable.
function constDecl10(use) {
return "(function() { for (const constvar = 0; ;) { " + use + "; } })();";
}
// For-in loop variable.
function constDecl11(use) {
return "(function() { for (const constvar in {a: 1}) { " + use + "; } })();";
}
// For-of loop variable.
function constDecl12(use) {
return "(function() { for (const constvar of [1]) { " + use + "; } })();";
}
let decls = [ constDecl0,
constDecl1,
constDecl2,
constDecl3,
constDecl4,
constDecl5,
constDecl6,
constDecl7,
constDecl8,
constDecl9,
constDecl10,
constDecl11,
constDecl12
];
let declsForTDZ = new Set([constDecl1, constDecl3, constDecl5, constDecl7]);
let uses = [ 'constvar = 1;',
'constvar += 1;',
'++constvar;',
'constvar++;'
];
function Test(d,u) {
'use strict';
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(d(u));
eval(d(u));
print(program, " // throw " + error.name);
eval(program);
} catch (e) {
if (declsForTDZ.has(d) && u !== uses[0]) {
// In these cases, read of a const variable occurs
// before a write to it, so TDZ kicks in before const check.
assertInstanceof(e, ReferenceError);
return;
assertInstanceof(e, error);
if (e === TypeError) {
assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0);
}
assertInstanceof(e, TypeError);
assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0);
return;
}
assertUnreachable();
}
for (var d = 0; d < decls.length; ++d) {
for (var d = 0; d < decls.length; d += 2) {
for (var u = 0; u < uses.length; ++u) {
Test(decls[d], uses[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]);
}
}
}
}
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