__ 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());
__ 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.
}
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.
}
}
__ 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());
__ 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.
}
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.
}
}
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())) {
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);
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())) {
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());
// 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,
__ 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());
__ 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.
}
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.
}
}
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 &&
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"],
HandleScope scope(isolate);
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
- NewTypeError("harmony_const_assign", HandleVector<Object>(NULL, 0)));
+ NewTypeError("const_assign", HandleVector<Object>(NULL, 0)));
}
__ 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());
__ 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.
}
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.
}
}
// (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
"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]);
+ }
+ }
}
}