8073707: const re-assignment should not reported as a early error
Reviewed-by: sundar, attila
This commit is contained in:
parent
ffd434caa1
commit
74c88b0515
@ -712,19 +712,8 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
||||
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 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
||||
|
||||
@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);
|
||||
|
@ -343,8 +343,14 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
// 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 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
|
||||
@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 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
|
||||
@Override
|
||||
public boolean enterDECINC(final UnaryNode unaryNode) {
|
||||
checkAssignTarget(unaryNode.getExpression());
|
||||
loadDECINC(unaryNode);
|
||||
return false;
|
||||
}
|
||||
|
@ -114,6 +114,11 @@ public final class ScriptRuntime {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -402,6 +407,15 @@ public final class ScriptRuntime {
|
||||
throw referenceError("not.defined", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -167,7 +167,6 @@ reference.error.cant.be.used.as.lhs="{0}" can not be used as the left-hand side
|
||||
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}"
|
||||
|
@ -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 {
|
||||
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 {
|
||||
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 {
|
||||
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' +
|
||||
'delete x;\n');
|
||||
const x = 2;
|
||||
delete x;
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
print(e);
|
||||
}
|
||||
|
||||
const c = 1;
|
||||
|
||||
try {
|
||||
c = 2;
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
(function() {
|
||||
try {
|
||||
c = 2;
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
})();
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user