8073707: const re-assignment should not reported as a early error
Reviewed-by: sundar, attila
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Fri Feb 27 18:03:18 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Fri Feb 27 14:33:47 2015 +0100
@@ -712,19 +712,8 @@
return definingFn == function;
}
- private void checkConstAssignment(final IdentNode ident) {
- // Check for reassignment of constant
- final Symbol symbol = ident.getSymbol();
- if (symbol.isConst()) {
- throwParserException(ECMAErrors.getMessage("syntax.error.assign.constant", symbol.getName()), ident);
- }
- }
-
@Override
public Node leaveBinaryNode(final BinaryNode binaryNode) {
- if (binaryNode.isAssignment() && binaryNode.lhs() instanceof IdentNode) {
- checkConstAssignment((IdentNode) binaryNode.lhs());
- }
switch (binaryNode.tokenType()) {
case ASSIGN:
return leaveASSIGN(binaryNode);
@@ -751,9 +740,6 @@
@Override
public Node leaveUnaryNode(final UnaryNode unaryNode) {
- if (unaryNode.isAssignment() && unaryNode.getExpression() instanceof IdentNode) {
- checkConstAssignment((IdentNode) unaryNode.getExpression());
- }
switch (unaryNode.tokenType()) {
case DELETE:
return leaveDELETE(unaryNode);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Feb 27 18:03:18 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Feb 27 14:33:47 2015 +0100
@@ -343,8 +343,14 @@
// This is called the temporal dead zone (TDZ). See https://gist.github.com/rwaldron/f0807a758aa03bcdd58a
private void checkTemporalDeadZone(final IdentNode identNode) {
if (identNode.isDead()) {
- method.load(identNode.getSymbol().getName());
- method.invoke(ScriptRuntime.THROW_REFERENCE_ERROR);
+ method.load(identNode.getSymbol().getName()).invoke(ScriptRuntime.THROW_REFERENCE_ERROR);
+ }
+ }
+
+ // Runtime check for assignment to ES6 const
+ private void checkAssignTarget(final Expression expression) {
+ if (expression instanceof IdentNode && ((IdentNode)expression).getSymbol().isConst()) {
+ method.load(((IdentNode)expression).getSymbol().getName()).invoke(ScriptRuntime.THROW_CONST_TYPE_ERROR);
}
}
@@ -787,72 +793,84 @@
@Override
public boolean enterASSIGN(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_ADD(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_ADD(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_BIT_AND(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_BIT_OR(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_BIT_XOR(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_DIV(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_DIV(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_MOD(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_MOD(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_MUL(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_MUL(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_SAR(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_SAR(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_SHL(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_SHL(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_SHR(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_SHR(binaryNode);
return false;
}
@Override
public boolean enterASSIGN_SUB(final BinaryNode binaryNode) {
+ checkAssignTarget(binaryNode.lhs());
loadASSIGN_SUB(binaryNode);
return false;
}
@@ -1062,6 +1080,7 @@
@Override
public boolean enterDECINC(final UnaryNode unaryNode) {
+ checkAssignTarget(unaryNode.getExpression());
loadDECINC(unaryNode);
return false;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Fri Feb 27 18:03:18 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Fri Feb 27 14:33:47 2015 +0100
@@ -115,6 +115,11 @@
public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
/**
+ * Throws a reference error for an undefined variable.
+ */
+ public static final Call THROW_CONST_TYPE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwConstTypeError", void.class, String.class);
+
+ /**
* Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself.
*/
public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName", void.class, String.class);
@@ -403,6 +408,15 @@
}
/**
+ * Throws a type error for an assignment to a const.
+ *
+ * @param name the const name
+ */
+ public static void throwConstTypeError(final String name) {
+ throw typeError("assign.constant", name);
+ }
+
+ /**
* Call a script function as a constructor with given args.
*
* @param target ScriptFunction object.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Fri Feb 27 18:03:18 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Fri Feb 27 14:33:47 2015 +0100
@@ -167,7 +167,6 @@
syntax.error.invalid.json=Invalid JSON: {0}
syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
syntax.error.redeclare.variable=Variable "{0}" has already been declared
-syntax.error.assign.constant=Assignment to constant "{0}"
syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
io.error.cant.write=cannot write "{0}"
--- a/nashorn/test/script/basic/es6/const-reassign.js Fri Feb 27 18:03:18 2015 +0530
+++ b/nashorn/test/script/basic/es6/const-reassign.js Fri Feb 27 14:33:47 2015 +0100
@@ -31,144 +31,147 @@
"use strict";
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x = 1;\n');
+ const x = 2;
+ x = 1;
+ fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x++;\n');
+ const x = 2;
+ x++;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x--;\n');
+ const x = 2;
+ x--;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
+}
+
+try {
+ const x = 2;
+ ++x;
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- '++x;\n');
+ const x = 2;
+ --x;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- '--x;\n');
+ const x = 2;
+ x += 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x += 1;\n');
+ const x = 2;
+ x *= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x *= 1;\n');
+ const x = 2;
+ x /= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x /= 1;\n');
+ const x = 2;
+ x %= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x %= 1;\n');
+ const x = 2;
+ x |= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x |= 1;\n');
+ const x = 2;
+ x &= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x &= 1;\n');
+ const x = 2;
+ x ^= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
+}
+
+try {
+ const x = 2;
+ x <<= 1;
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x ^= 1;\n');
+ const x = 2;
+ x >>= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x <<= 1;\n');
+ const x = 2;
+ x >>>= 1;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x >>= 1;\n');
+ const x = 2;
+ delete x;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
+const c = 1;
+
try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'x >>>= 1;\n');
+ c = 2;
fail("const assignment didn't throw");
} catch (e) {
- print(e.name);
+ print(e);
}
-try {
- eval('"use strict";\n' +
- 'const x = 2;\n' +
- 'delete x;\n');
- fail("const assignment didn't throw");
-} catch (e) {
- print(e.name);
-}
+(function() {
+ try {
+ c = 2;
+ fail("const assignment didn't throw");
+ } catch (e) {
+ print(e);
+ }
+})();
--- a/nashorn/test/script/basic/es6/const-reassign.js.EXPECTED Fri Feb 27 18:03:18 2015 +0530
+++ b/nashorn/test/script/basic/es6/const-reassign.js.EXPECTED Fri Feb 27 14:33:47 2015 +0100
@@ -1,16 +1,18 @@
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
-SyntaxError
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+TypeError: Assignment to constant "x"
+SyntaxError: cannot delete "x" in strict mode
+TypeError: Assignment to constant "c"
+TypeError: Assignment to constant "c"
--- a/nashorn/test/script/basic/es6/let_const_reuse.js.EXPECTED Fri Feb 27 18:03:18 2015 +0530
+++ b/nashorn/test/script/basic/es6/let_const_reuse.js.EXPECTED Fri Feb 27 14:33:47 2015 +0100
@@ -1,8 +1,4 @@
ReferenceError: "a" is not defined
-SyntaxError: test/script/basic/es6/let_const_reuse.js#35:9<eval>:3:8 Assignment to constant "a"
- a--
- ^
-SyntaxError: test/script/basic/es6/let_const_reuse.js#35:9<eval>:3:8 Assignment to constant "a"
- a--
- ^
+TypeError: Assignment to constant "a"
+TypeError: Assignment to constant "a"
ReferenceError: "a" is not defined