8057980: let & const: remaining issues with lexical scoping

Thu, 27 Nov 2014 18:02:28 +0100

author
hannesw
date
Thu, 27 Nov 2014 18:02:28 +0100
changeset 1109
f39081a16f71
parent 1108
d8bb6c470778
child 1110
a56051d3cdf5

8057980: let & const: remaining issues with lexical scoping
Reviewed-by: lagergren, attila

src/jdk/nashorn/internal/codegen/AssignSymbols.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Lower.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ForNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LexicalContext.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LoopNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/VarNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/WhileNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/Parser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/ArrayData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/resources/Messages.properties file | annotate | diff | comparison | revisions
test/script/basic/es6/for-let.js file | annotate | diff | comparison | revisions
test/script/basic/es6/for-let.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/es6/let-const-statement-context.js file | annotate | diff | comparison | revisions
test/script/basic/es6/let-const-statement-context.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/es6/let-const-switch.js file | annotate | diff | comparison | revisions
test/script/basic/es6/let-const-switch.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/es6/let-load.js file | annotate | diff | comparison | revisions
test/script/basic/es6/let-load.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/es6/let_const_closure.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/es6/lexical-toplevel.js.EXPECTED file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Nov 27 17:14:01 2014 +0400
     1.2 +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Nov 27 18:02:28 2014 +0100
     1.3 @@ -189,7 +189,7 @@
     1.4       * @param body the body of the FunctionNode we are entering
     1.5       */
     1.6      private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
     1.7 -        // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
     1.8 +        // This visitor will assign symbol to all declared variables.
     1.9          body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
    1.10              @Override
    1.11              protected boolean enterDefault(final Node node) {
    1.12 @@ -200,16 +200,17 @@
    1.13  
    1.14              @Override
    1.15              public Node leaveVarNode(final VarNode varNode) {
    1.16 -                if (varNode.isStatement()) {
    1.17 -                    final IdentNode ident  = varNode.getName();
    1.18 -                    final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body;
    1.19 -                    final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
    1.20 -                    if (varNode.isFunctionDeclaration()) {
    1.21 -                        symbol.setIsFunctionDeclaration();
    1.22 -                    }
    1.23 -                    return varNode.setName(ident.setSymbol(symbol));
    1.24 +                final IdentNode ident  = varNode.getName();
    1.25 +                final boolean blockScoped = varNode.isBlockScoped();
    1.26 +                if (blockScoped && lc.inUnprotectedSwitchContext()) {
    1.27 +                    throwUnprotectedSwitchError(varNode);
    1.28                  }
    1.29 -                return varNode;
    1.30 +                final Block block = blockScoped ? lc.getCurrentBlock() : body;
    1.31 +                final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
    1.32 +                if (varNode.isFunctionDeclaration()) {
    1.33 +                    symbol.setIsFunctionDeclaration();
    1.34 +                }
    1.35 +                return varNode.setName(ident.setSymbol(symbol));
    1.36              }
    1.37          });
    1.38      }
    1.39 @@ -1048,6 +1049,15 @@
    1.40          return !(units == null || units.isEmpty());
    1.41      }
    1.42  
    1.43 +    private void throwUnprotectedSwitchError(final VarNode varNode) {
    1.44 +        // Block scoped declarations in switch statements without explicit blocks should be declared
    1.45 +        // in a common block that contains all the case clauses. We cannot support this without a
    1.46 +        // fundamental rewrite of how switch statements are handled (case nodes contain blocks and are
    1.47 +        // directly contained by switch node). As a temporary solution we throw a reference error here.
    1.48 +        final String msg = ECMAErrors.getMessage("syntax.error.unprotected.switch.declaration", varNode.isLet() ? "let" : "const");
    1.49 +        throwParserException(msg, varNode);
    1.50 +    }
    1.51 +
    1.52      private void throwParserException(final String message, final Node origin) {
    1.53          if (origin == null) {
    1.54              throw new ParserException(message);
     2.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Nov 27 17:14:01 2014 +0400
     2.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Nov 27 18:02:28 2014 +0100
     2.3 @@ -3264,6 +3264,13 @@
     2.4              emitContinueLabel(continueLabel, liveLocalsOnContinue);
     2.5          }
     2.6  
     2.7 +        if (loopNode.hasPerIterationScope() && lc.getParentBlock().needsScope()) {
     2.8 +            // ES6 for loops with LET init need a new scope for each iteration. We just create a shallow copy here.
     2.9 +            method.loadCompilerConstant(SCOPE);
    2.10 +            method.invoke(virtualCallNoLookup(ScriptObject.class, "copy", ScriptObject.class));
    2.11 +            method.storeCompilerConstant(SCOPE);
    2.12 +        }
    2.13 +
    2.14          if(method.isReachable()) {
    2.15              if(modify != null) {
    2.16                  lineNumber(loopNode);
     3.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java	Thu Nov 27 17:14:01 2014 +0400
     3.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java	Thu Nov 27 18:02:28 2014 +0100
     3.3 @@ -525,7 +525,7 @@
     3.4  
     3.5          if (isAlwaysTrue(test)) {
     3.6              //turn it into a for node without a test.
     3.7 -            final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, ForNode.IS_FOR).accept(this);
     3.8 +            final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this);
     3.9              lc.replace(whileNode, forNode);
    3.10              return forNode;
    3.11          }
     4.1 --- a/src/jdk/nashorn/internal/ir/ForNode.java	Thu Nov 27 17:14:01 2014 +0400
     4.2 +++ b/src/jdk/nashorn/internal/ir/ForNode.java	Thu Nov 27 18:02:28 2014 +0100
     4.3 @@ -45,14 +45,14 @@
     4.4      /** Iterator symbol. */
     4.5      private Symbol iterator;
     4.6  
     4.7 -    /** Is this a normal for loop? */
     4.8 -    public static final int IS_FOR      = 1 << 0;
     4.9 -
    4.10      /** Is this a normal for in loop? */
    4.11 -    public static final int IS_FOR_IN   = 1 << 1;
    4.12 +    public static final int IS_FOR_IN           = 1 << 0;
    4.13  
    4.14      /** Is this a normal for each in loop? */
    4.15 -    public static final int IS_FOR_EACH = 1 << 2;
    4.16 +    public static final int IS_FOR_EACH         = 1 << 1;
    4.17 +
    4.18 +    /** Does this loop need a per-iteration scope because its init contain a LET declaration? */
    4.19 +    public static final int PER_ITERATION_SCOPE = 1 << 2;
    4.20  
    4.21      private final int flags;
    4.22  
    4.23 @@ -273,4 +273,18 @@
    4.24      JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
    4.25          return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
    4.26      }
    4.27 +
    4.28 +    @Override
    4.29 +    public boolean hasPerIterationScope() {
    4.30 +        return (flags & PER_ITERATION_SCOPE) != 0;
    4.31 +    }
    4.32 +
    4.33 +    /**
    4.34 +     * Set the per-iteration-scope flag on this node.
    4.35 +     * @param lc lexical context
    4.36 +     * @return the node with flag set
    4.37 +     */
    4.38 +    public ForNode setPerIterationScope(final LexicalContext lc) {
    4.39 +        return setFlags(lc, flags | PER_ITERATION_SCOPE);
    4.40 +    }
    4.41  }
     5.1 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java	Thu Nov 27 17:14:01 2014 +0400
     5.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java	Thu Nov 27 18:02:28 2014 +0100
     5.3 @@ -597,6 +597,20 @@
     5.4          throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't");
     5.5      }
     5.6  
     5.7 +    /**
     5.8 +     * Checks whether the current context is inside a switch statement without explicit blocks (curly braces).
     5.9 +     * @return true if in unprotected switch statement
    5.10 +     */
    5.11 +    public boolean inUnprotectedSwitchContext() {
    5.12 +        for (int i = sp; i > 0; i--) {
    5.13 +            final LexicalContextNode next = stack[i];
    5.14 +            if (next instanceof Block) {
    5.15 +                return stack[i - 1] instanceof SwitchNode;
    5.16 +            }
    5.17 +        }
    5.18 +        return false;
    5.19 +    }
    5.20 +
    5.21      @Override
    5.22      public String toString() {
    5.23          final StringBuffer sb = new StringBuffer();
     6.1 --- a/src/jdk/nashorn/internal/ir/LoopNode.java	Thu Nov 27 17:14:01 2014 +0400
     6.2 +++ b/src/jdk/nashorn/internal/ir/LoopNode.java	Thu Nov 27 18:02:28 2014 +0100
     6.3 @@ -176,4 +176,10 @@
     6.4       * @return new loop node if changed otherwise the same
     6.5       */
     6.6      public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes);
     6.7 +
     6.8 +    /**
     6.9 +     * Does this loop have a LET declaration and hence require a per-iteration scope?
    6.10 +     * @return true if a per-iteration scope is required.
    6.11 +     */
    6.12 +    public abstract boolean hasPerIterationScope();
    6.13  }
     7.1 --- a/src/jdk/nashorn/internal/ir/VarNode.java	Thu Nov 27 17:14:01 2014 +0400
     7.2 +++ b/src/jdk/nashorn/internal/ir/VarNode.java	Thu Nov 27 18:02:28 2014 +0100
     7.3 @@ -45,19 +45,16 @@
     7.4      /** Is this a var statement (as opposed to a "var" in a for loop statement) */
     7.5      private final int flags;
     7.6  
     7.7 -    /** Flag that determines if this function node is a statement */
     7.8 -    public static final int IS_STATEMENT                 = 1 << 0;
     7.9 -
    7.10      /** Flag for ES6 LET declaration */
    7.11 -    public static final int IS_LET                       = 1 << 1;
    7.12 +    public static final int IS_LET                       = 1 << 0;
    7.13  
    7.14      /** Flag for ES6 CONST declaration */
    7.15 -    public static final int IS_CONST                     = 1 << 2;
    7.16 +    public static final int IS_CONST                     = 1 << 1;
    7.17  
    7.18      /** Flag that determines if this is the last function declaration in a function
    7.19       *  This is used to micro optimize the placement of return value assignments for
    7.20       *  a program node */
    7.21 -    public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3;
    7.22 +    public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 2;
    7.23  
    7.24      /**
    7.25       * Constructor
    7.26 @@ -69,7 +66,7 @@
    7.27       * @param init       init node or null if just a declaration
    7.28       */
    7.29      public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init) {
    7.30 -        this(lineNumber, token, finish, name, init, IS_STATEMENT);
    7.31 +        this(lineNumber, token, finish, name, init, 0);
    7.32      }
    7.33  
    7.34      private VarNode(final VarNode varNode, final IdentNode name, final Expression init, final int flags) {
    7.35 @@ -260,14 +257,6 @@
    7.36      }
    7.37  
    7.38      /**
    7.39 -     * Returns true if this is a var statement (as opposed to a var initializer in a for loop).
    7.40 -     * @return true if this is a var statement (as opposed to a var initializer in a for loop).
    7.41 -     */
    7.42 -    public boolean isStatement() {
    7.43 -        return (flags & IS_STATEMENT) != 0;
    7.44 -    }
    7.45 -
    7.46 -    /**
    7.47       * Returns true if this is a function declaration.
    7.48       * @return true if this is a function declaration.
    7.49       */
     8.1 --- a/src/jdk/nashorn/internal/ir/WhileNode.java	Thu Nov 27 17:14:01 2014 +0400
     8.2 +++ b/src/jdk/nashorn/internal/ir/WhileNode.java	Thu Nov 27 18:02:28 2014 +0100
     8.3 @@ -148,4 +148,9 @@
     8.4          }
     8.5          return test == null;
     8.6      }
     8.7 +
     8.8 +    @Override
     8.9 +    public boolean hasPerIterationScope() {
    8.10 +        return false;
    8.11 +    }
    8.12  }
     9.1 --- a/src/jdk/nashorn/internal/parser/Parser.java	Thu Nov 27 17:14:01 2014 +0400
     9.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java	Thu Nov 27 18:02:28 2014 +0100
     9.3 @@ -559,7 +559,7 @@
     9.4          // Set up new block. Captures first token.
     9.5          Block newBlock = newBlock();
     9.6          try {
     9.7 -            statement();
     9.8 +            statement(false, false, true);
     9.9          } finally {
    9.10              newBlock = restoreBlock(newBlock);
    9.11          }
    9.12 @@ -772,7 +772,7 @@
    9.13  
    9.14                  try {
    9.15                      // Get the next element.
    9.16 -                    statement(true, allowPropertyFunction);
    9.17 +                    statement(true, allowPropertyFunction, false);
    9.18                      allowPropertyFunction = false;
    9.19  
    9.20                      // check for directive prologues
    9.21 @@ -862,13 +862,15 @@
    9.22       * Parse any of the basic statement types.
    9.23       */
    9.24      private void statement() {
    9.25 -        statement(false, false);
    9.26 +        statement(false, false, false);
    9.27      }
    9.28  
    9.29      /**
    9.30       * @param topLevel does this statement occur at the "top level" of a script or a function?
    9.31 +     * @param allowPropertyFunction allow property "get" and "set" functions?
    9.32 +     * @param singleStatement are we in a single statement context?
    9.33       */
    9.34 -    private void statement(final boolean topLevel, final boolean allowPropertyFunction) {
    9.35 +    private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) {
    9.36          if (type == FUNCTION) {
    9.37              // As per spec (ECMA section 12), function declarations as arbitrary statement
    9.38              // is not "portable". Implementation can issue a warning or disallow the same.
    9.39 @@ -932,6 +934,9 @@
    9.40              break;
    9.41          default:
    9.42              if (useBlockScope() && (type == LET || type == CONST)) {
    9.43 +                if (singleStatement) {
    9.44 +                    throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
    9.45 +                }
    9.46                  variableStatement(type, true);
    9.47                  break;
    9.48              }
    9.49 @@ -1057,7 +1062,7 @@
    9.50          next();
    9.51  
    9.52          final List<VarNode> vars = new ArrayList<>();
    9.53 -        int varFlags = VarNode.IS_STATEMENT;
    9.54 +        int varFlags = 0;
    9.55          if (varType == LET) {
    9.56              varFlags |= VarNode.IS_LET;
    9.57          } else if (varType == CONST) {
    9.58 @@ -1210,7 +1215,7 @@
    9.59          Block outer = useBlockScope() ? newBlock() : null;
    9.60  
    9.61          // Create FOR node, capturing FOR token.
    9.62 -        ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
    9.63 +        ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, 0);
    9.64          lc.push(forNode);
    9.65  
    9.66          try {
    9.67 @@ -1230,19 +1235,22 @@
    9.68  
    9.69              switch (type) {
    9.70              case VAR:
    9.71 -                // Var statements captured in for outer block.
    9.72 +                // Var declaration captured in for outer block.
    9.73                  vars = variableStatement(type, false);
    9.74                  break;
    9.75              case SEMICOLON:
    9.76                  break;
    9.77              default:
    9.78                  if (useBlockScope() && (type == LET || type == CONST)) {
    9.79 -                    // LET/CONST captured in container block created above.
    9.80 +                    if (type == LET) {
    9.81 +                        forNode = forNode.setPerIterationScope(lc);
    9.82 +                    }
    9.83 +                    // LET/CONST declaration captured in container block created above.
    9.84                      vars = variableStatement(type, false);
    9.85                      break;
    9.86                  }
    9.87                  if (env._const_as_var && type == CONST) {
    9.88 -                    // Var statements captured in for outer block.
    9.89 +                    // Var declaration captured in for outer block.
    9.90                      vars = variableStatement(TokenType.VAR, false);
    9.91                      break;
    9.92                  }
    9.93 @@ -1323,11 +1331,12 @@
    9.94              appendStatement(forNode);
    9.95          } finally {
    9.96              lc.pop(forNode);
    9.97 -            if (outer != null) {
    9.98 -                outer.setFinish(forNode.getFinish());
    9.99 -                outer = restoreBlock(outer);
   9.100 -                appendStatement(new BlockStatement(startLine, outer));
   9.101 -            }
   9.102 +        }
   9.103 +
   9.104 +        if (outer != null) {
   9.105 +            outer.setFinish(forNode.getFinish());
   9.106 +            outer = restoreBlock(outer);
   9.107 +            appendStatement(new BlockStatement(startLine, outer));
   9.108          }
   9.109      }
   9.110  
   9.111 @@ -2699,11 +2708,7 @@
   9.112          }
   9.113  
   9.114          if (isStatement) {
   9.115 -            int varFlags = VarNode.IS_STATEMENT;
   9.116 -            if (!topLevel && useBlockScope()) {
   9.117 -                // mark ES6 block functions as lexically scoped
   9.118 -                varFlags |= VarNode.IS_LET;
   9.119 -            }
   9.120 +            final int     varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
   9.121              final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
   9.122              if (topLevel) {
   9.123                  functionDeclarations.add(varNode);
    10.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Nov 27 17:14:01 2014 +0400
    10.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Nov 27 18:02:28 2014 +0100
    10.3 @@ -46,6 +46,8 @@
    10.4  import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
    10.5  import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
    10.6  import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
    10.7 +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag;
    10.8 +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag;
    10.9  import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
   10.10  
   10.11  import java.lang.invoke.MethodHandle;
   10.12 @@ -98,7 +100,7 @@
   10.13   * </ul>
   10.14   */
   10.15  
   10.16 -public abstract class ScriptObject implements PropertyAccess {
   10.17 +public abstract class ScriptObject implements PropertyAccess, Cloneable {
   10.18      /** __proto__ special property name inside object literals. ES6 draft. */
   10.19      public static final String PROTO_PROPERTY_NAME   = "__proto__";
   10.20  
   10.21 @@ -2202,6 +2204,9 @@
   10.22  
   10.23          if (find != null) {
   10.24              if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {
   10.25 +                if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) {
   10.26 +                    throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode.
   10.27 +                }
   10.28                  // Existing, non-writable property
   10.29                  return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
   10.30              }
   10.31 @@ -3103,7 +3108,7 @@
   10.32      private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) {
   10.33          if (longIndex >= oldLength) {
   10.34              if (!isExtensible()) {
   10.35 -                if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
   10.36 +                if (isStrictFlag(callSiteFlags)) {
   10.37                      throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
   10.38                  }
   10.39                  return true;
   10.40 @@ -3127,7 +3132,7 @@
   10.41          final long oldLength = getArray().length();
   10.42          final long longIndex = ArrayIndex.toLongIndex(index);
   10.43          if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
   10.44 -            final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
   10.45 +            final boolean strict = isStrictFlag(callSiteFlags);
   10.46              setArray(getArray().set(index, value, strict));
   10.47              doesNotHaveEnsureDelete(longIndex, oldLength, strict);
   10.48          }
   10.49 @@ -3137,7 +3142,7 @@
   10.50          final long oldLength = getArray().length();
   10.51          final long longIndex = ArrayIndex.toLongIndex(index);
   10.52          if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
   10.53 -            final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
   10.54 +            final boolean strict = isStrictFlag(callSiteFlags);
   10.55              setArray(getArray().set(index, value, strict));
   10.56              doesNotHaveEnsureDelete(longIndex, oldLength, strict);
   10.57          }
   10.58 @@ -3147,7 +3152,7 @@
   10.59          final long oldLength = getArray().length();
   10.60          final long longIndex = ArrayIndex.toLongIndex(index);
   10.61          if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
   10.62 -            final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
   10.63 +            final boolean strict = isStrictFlag(callSiteFlags);
   10.64              setArray(getArray().set(index, value, strict));
   10.65              doesNotHaveEnsureDelete(longIndex, oldLength, strict);
   10.66          }
   10.67 @@ -3157,7 +3162,7 @@
   10.68          final long oldLength = getArray().length();
   10.69          final long longIndex = ArrayIndex.toLongIndex(index);
   10.70          if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
   10.71 -            final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
   10.72 +            final boolean strict = isStrictFlag(callSiteFlags);
   10.73              setArray(getArray().set(index, value, strict));
   10.74              doesNotHaveEnsureDelete(longIndex, oldLength, strict);
   10.75          }
   10.76 @@ -3178,7 +3183,7 @@
   10.77          invalidateGlobalConstant(key);
   10.78  
   10.79          if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
   10.80 -            final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags);
   10.81 +            final boolean isScope = isScopeFlag(callSiteFlags);
   10.82              // If the start object of the find is not this object it means the property was found inside a
   10.83              // 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
   10.84              // to the 'with' object.
   10.85 @@ -3199,16 +3204,19 @@
   10.86  
   10.87          if (f != null) {
   10.88              if (!f.getProperty().isWritable()) {
   10.89 -                if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
   10.90 +                if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
   10.91 +                    throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode.
   10.92 +                }
   10.93 +                if (isStrictFlag(callSiteFlags)) {
   10.94                      throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
   10.95                  }
   10.96                  return;
   10.97              }
   10.98  
   10.99 -            f.setValue(value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags));
  10.100 +            f.setValue(value, isStrictFlag(callSiteFlags));
  10.101  
  10.102          } else if (!isExtensible()) {
  10.103 -            if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
  10.104 +            if (isStrictFlag(callSiteFlags)) {
  10.105                  throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
  10.106              }
  10.107          } else {
  10.108 @@ -3235,7 +3243,7 @@
  10.109          if (isValidArrayIndex(index)) {
  10.110              final ArrayData data = getArray();
  10.111              if (data.has(index)) {
  10.112 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.113 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.114              } else {
  10.115                  doesNotHave(index, value, callSiteFlags);
  10.116              }
  10.117 @@ -3255,7 +3263,7 @@
  10.118          if (isValidArrayIndex(index)) {
  10.119              final ArrayData data = getArray();
  10.120              if (data.has(index)) {
  10.121 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.122 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.123              } else {
  10.124                  doesNotHave(index, value, callSiteFlags);
  10.125              }
  10.126 @@ -3275,7 +3283,7 @@
  10.127          if (isValidArrayIndex(index)) {
  10.128              final ArrayData data = getArray();
  10.129              if (data.has(index)) {
  10.130 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.131 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.132              } else {
  10.133                  doesNotHave(index, value, callSiteFlags);
  10.134              }
  10.135 @@ -3295,7 +3303,7 @@
  10.136          if (isValidArrayIndex(index)) {
  10.137              final ArrayData data = getArray();
  10.138              if (data.has(index)) {
  10.139 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.140 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.141              } else {
  10.142                  doesNotHave(index, value, callSiteFlags);
  10.143              }
  10.144 @@ -3314,7 +3322,7 @@
  10.145          if (isValidArrayIndex(index)) {
  10.146              final ArrayData data = getArray();
  10.147              if (data.has(index)) {
  10.148 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.149 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.150              } else {
  10.151                  doesNotHave(index, value, callSiteFlags);
  10.152              }
  10.153 @@ -3333,7 +3341,7 @@
  10.154          if (isValidArrayIndex(index)) {
  10.155              final ArrayData data = getArray();
  10.156              if (data.has(index)) {
  10.157 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.158 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.159              } else {
  10.160                  doesNotHave(index, value, callSiteFlags);
  10.161              }
  10.162 @@ -3352,7 +3360,7 @@
  10.163          if (isValidArrayIndex(index)) {
  10.164              final ArrayData data = getArray();
  10.165              if (data.has(index)) {
  10.166 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.167 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.168              } else {
  10.169                  doesNotHave(index, value, callSiteFlags);
  10.170              }
  10.171 @@ -3371,7 +3379,7 @@
  10.172          if (isValidArrayIndex(index)) {
  10.173              final ArrayData data = getArray();
  10.174              if (data.has(index)) {
  10.175 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.176 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.177              } else {
  10.178                  doesNotHave(index, value, callSiteFlags);
  10.179              }
  10.180 @@ -3390,7 +3398,7 @@
  10.181          if (isValidArrayIndex(index)) {
  10.182              final ArrayData data = getArray();
  10.183              if (data.has(index)) {
  10.184 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.185 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.186              } else {
  10.187                  doesNotHave(index, value, callSiteFlags);
  10.188              }
  10.189 @@ -3409,7 +3417,7 @@
  10.190          if (isValidArrayIndex(index)) {
  10.191              final ArrayData data = getArray();
  10.192              if (data.has(index)) {
  10.193 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.194 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.195              } else {
  10.196                  doesNotHave(index, value, callSiteFlags);
  10.197              }
  10.198 @@ -3428,7 +3436,7 @@
  10.199          if (isValidArrayIndex(index)) {
  10.200              final ArrayData data = getArray();
  10.201              if (data.has(index)) {
  10.202 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.203 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.204              } else {
  10.205                  doesNotHave(index, value, callSiteFlags);
  10.206              }
  10.207 @@ -3447,7 +3455,7 @@
  10.208          if (isValidArrayIndex(index)) {
  10.209              final ArrayData data = getArray();
  10.210              if (data.has(index)) {
  10.211 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.212 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.213              } else {
  10.214                  doesNotHave(index, value, callSiteFlags);
  10.215              }
  10.216 @@ -3465,7 +3473,7 @@
  10.217          if (isValidArrayIndex(index)) {
  10.218              if (getArray().has(index)) {
  10.219                  final ArrayData data = getArray();
  10.220 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.221 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.222              } else {
  10.223                  doesNotHave(index, value, callSiteFlags);
  10.224              }
  10.225 @@ -3483,7 +3491,7 @@
  10.226          if (isValidArrayIndex(index)) {
  10.227              final ArrayData data = getArray();
  10.228              if (data.has(index)) {
  10.229 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.230 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.231              } else {
  10.232                  doesNotHave(index, value, callSiteFlags);
  10.233              }
  10.234 @@ -3502,7 +3510,7 @@
  10.235          if (isValidArrayIndex(index)) {
  10.236              final ArrayData data = getArray();
  10.237              if (data.has(index)) {
  10.238 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.239 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.240              } else {
  10.241                  doesNotHave(index, value, callSiteFlags);
  10.242              }
  10.243 @@ -3521,7 +3529,7 @@
  10.244          if (isValidArrayIndex(index)) {
  10.245              final ArrayData data = getArray();
  10.246              if (data.has(index)) {
  10.247 -                setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
  10.248 +                setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
  10.249              } else {
  10.250                  doesNotHave(index, value, callSiteFlags);
  10.251              }
  10.252 @@ -3686,6 +3694,29 @@
  10.253      }
  10.254  
  10.255      /**
  10.256 +     * Return a shallow copy of this ScriptObject.
  10.257 +     * @return a shallow copy.
  10.258 +     */
  10.259 +    public final ScriptObject copy() {
  10.260 +        try {
  10.261 +            return clone();
  10.262 +        } catch (final CloneNotSupportedException e) {
  10.263 +            throw new RuntimeException(e);
  10.264 +        }
  10.265 +    }
  10.266 +
  10.267 +    @Override
  10.268 +    protected ScriptObject clone() throws CloneNotSupportedException {
  10.269 +        final ScriptObject clone = (ScriptObject) super.clone();
  10.270 +        if (objectSpill != null) {
  10.271 +            clone.objectSpill = objectSpill.clone();
  10.272 +            clone.primitiveSpill = primitiveSpill.clone();
  10.273 +        }
  10.274 +        clone.arrayData = arrayData.copy();
  10.275 +        return clone;
  10.276 +    }
  10.277 +
  10.278 +    /**
  10.279       * Make a new UserAccessorProperty property. getter and setter functions are stored in
  10.280       * this ScriptObject and slot values are used in property object.
  10.281       *
    11.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Thu Nov 27 17:14:01 2014 +0400
    11.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Thu Nov 27 18:02:28 2014 +0100
    11.3 @@ -61,9 +61,9 @@
    11.4      /**
    11.5       * Length of the array data. Not necessarily length of the wrapped array.
    11.6       * This is private to ensure that no one in a subclass is able to touch the length
    11.7 -     * without going through {@link setLength}. This is used to implement
    11.8 +     * without going through {@link #setLength}. This is used to implement
    11.9       * {@link LengthNotWritableFilter}s, ensuring that there are no ways past
   11.10 -     * a {@link setLength} function replaced by a nop
   11.11 +     * a {@link #setLength} function replaced by a nop
   11.12       */
   11.13      private long length;
   11.14  
   11.15 @@ -79,11 +79,7 @@
   11.16       */
   11.17      private static class UntouchedArrayData extends ContinuousArrayData {
   11.18          private UntouchedArrayData() {
   11.19 -            this(0);
   11.20 -        }
   11.21 -
   11.22 -        private UntouchedArrayData(final int length) {
   11.23 -            super(length);
   11.24 +            super(0);
   11.25          }
   11.26  
   11.27          private ArrayData toRealArrayData() {
   11.28 @@ -100,7 +96,8 @@
   11.29  
   11.30          @Override
   11.31          public ContinuousArrayData copy() {
   11.32 -            return new UntouchedArrayData((int)length());
   11.33 +            assert length() == 0;
   11.34 +            return this;
   11.35          }
   11.36  
   11.37          @Override
   11.38 @@ -246,7 +243,7 @@
   11.39          public Class<?> getBoxedElementType() {
   11.40              return Integer.class;
   11.41          }
   11.42 -    };
   11.43 +    }
   11.44  
   11.45      /**
   11.46       * Constructor
    12.1 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Nov 27 17:14:01 2014 +0400
    12.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Nov 27 18:02:28 2014 +0100
    12.3 @@ -116,6 +116,7 @@
    12.4  type.error.cannot.convert.to.interface=object {0} cannot be converted to {1} due to "{2}"
    12.5  type.error.array.reduce.invalid.init=invalid initialValue for Array.prototype.reduce
    12.6  type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototype.reduceRight
    12.7 +type.error.assign.constant=Assignment to constant "{0}"
    12.8  type.error.cannot.get.default.string=Cannot get default string value
    12.9  type.error.cannot.get.default.number=Cannot get default number value
   12.10  type.error.cant.apply.with.to.null=Cannot apply "with" to null
   12.11 @@ -166,6 +167,7 @@
   12.12  syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
   12.13  syntax.error.redeclare.variable=Variable "{0}" has already been declared
   12.14  syntax.error.assign.constant=Assignment to constant "{0}"
   12.15 +syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
   12.16  
   12.17  io.error.cant.write=cannot write "{0}"
   12.18  config.error.no.dest=no destination directory supplied
    13.1 --- a/test/script/basic/es6/for-let.js	Thu Nov 27 17:14:01 2014 +0400
    13.2 +++ b/test/script/basic/es6/for-let.js	Thu Nov 27 18:02:28 2014 +0100
    13.3 @@ -39,3 +39,40 @@
    13.4  } catch (e) {
    13.5      print(e);
    13.6  }
    13.7 +
    13.8 +let a = [];
    13.9 +
   13.10 +for (let i = 0; i < 10; i++) {
   13.11 +    a.push(function() { print(i); });
   13.12 +}
   13.13 +
   13.14 +a.forEach(function(f) { f(); });
   13.15 +
   13.16 +a = [];
   13.17 +
   13.18 +for (let i = 0; i < 10; i++) {
   13.19 +    if (i == 5) {
   13.20 +        i = "foo";
   13.21 +    }
   13.22 +    a.push(function() { print(i); });
   13.23 +}
   13.24 +
   13.25 +a.forEach(function(f) { f(); });
   13.26 +
   13.27 +try {
   13.28 +    print(i);
   13.29 +} catch (e) {
   13.30 +    print(e);
   13.31 +}
   13.32 +
   13.33 +a = [];
   13.34 +
   13.35 +for (let i = 0; i < 20; i++) {
   13.36 +    if (i % 2 == 1) {
   13.37 +        i += 2;
   13.38 +        continue;
   13.39 +    }
   13.40 +    a.push(function() { print(i); });
   13.41 +}
   13.42 +
   13.43 +a.forEach(function(f) { f(); });
    14.1 --- a/test/script/basic/es6/for-let.js.EXPECTED	Thu Nov 27 17:14:01 2014 +0400
    14.2 +++ b/test/script/basic/es6/for-let.js.EXPECTED	Thu Nov 27 18:02:28 2014 +0100
    14.3 @@ -9,3 +9,25 @@
    14.4  8
    14.5  9
    14.6  ReferenceError: "i" is not defined
    14.7 +0
    14.8 +1
    14.9 +2
   14.10 +3
   14.11 +4
   14.12 +5
   14.13 +6
   14.14 +7
   14.15 +8
   14.16 +9
   14.17 +0
   14.18 +1
   14.19 +2
   14.20 +3
   14.21 +4
   14.22 +foo
   14.23 +ReferenceError: "i" is not defined
   14.24 +0
   14.25 +4
   14.26 +8
   14.27 +12
   14.28 +16
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/test/script/basic/es6/let-const-statement-context.js	Thu Nov 27 18:02:28 2014 +0100
    15.3 @@ -0,0 +1,49 @@
    15.4 +/*
    15.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    15.7 + * 
    15.8 + * This code is free software; you can redistribute it and/or modify it
    15.9 + * under the terms of the GNU General Public License version 2 only, as
   15.10 + * published by the Free Software Foundation.
   15.11 + * 
   15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   15.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15.15 + * version 2 for more details (a copy is included in the LICENSE file that
   15.16 + * accompanied this code).
   15.17 + * 
   15.18 + * You should have received a copy of the GNU General Public License version
   15.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   15.21 + * 
   15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   15.23 + * or visit www.oracle.com if you need additional information or have any
   15.24 + * questions.
   15.25 + */
   15.26 +
   15.27 +/**
   15.28 + * JDK-8057980: let & const: remaining issues with lexical scoping
   15.29 + *
   15.30 + * @test
   15.31 + * @run
   15.32 + * @option --language=es6
   15.33 + */
   15.34 +
   15.35 +function tryEval(s) {
   15.36 +    try {
   15.37 +        eval(s);
   15.38 +    } catch (e) {
   15.39 +        print(String(e).replace(/\\/g, "/"));
   15.40 +    }
   15.41 +}
   15.42 +
   15.43 +tryEval('if (true) let x = 1;');
   15.44 +tryEval('if (true) const x = 1;');
   15.45 +tryEval('while (true) let x = 1;');
   15.46 +tryEval('while (true) const x = 1;');
   15.47 +tryEval('for (;;) let x = 1;');
   15.48 +tryEval('for (;;) const x = 1;');
   15.49 +tryEval('do let x = 1; while (true);');
   15.50 +tryEval('do const x = 1; while (true);');
   15.51 +tryEval('with (y) const x = 1;');
   15.52 +tryEval('with (y) let x = 1;');
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/test/script/basic/es6/let-const-statement-context.js.EXPECTED	Thu Nov 27 18:02:28 2014 +0100
    16.3 @@ -0,0 +1,30 @@
    16.4 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:10 Expected statement but found let declaration
    16.5 +if (true) let x = 1;
    16.6 +          ^
    16.7 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:10 Expected statement but found const declaration
    16.8 +if (true) const x = 1;
    16.9 +          ^
   16.10 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:13 Expected statement but found let declaration
   16.11 +while (true) let x = 1;
   16.12 +             ^
   16.13 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:13 Expected statement but found const declaration
   16.14 +while (true) const x = 1;
   16.15 +             ^
   16.16 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found let declaration
   16.17 +for (;;) let x = 1;
   16.18 +         ^
   16.19 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found const declaration
   16.20 +for (;;) const x = 1;
   16.21 +         ^
   16.22 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:3 Expected statement but found let declaration
   16.23 +do let x = 1; while (true);
   16.24 +   ^
   16.25 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:3 Expected statement but found const declaration
   16.26 +do const x = 1; while (true);
   16.27 +   ^
   16.28 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found const declaration
   16.29 +with (y) const x = 1;
   16.30 +         ^
   16.31 +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found let declaration
   16.32 +with (y) let x = 1;
   16.33 +         ^
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/test/script/basic/es6/let-const-switch.js	Thu Nov 27 18:02:28 2014 +0100
    17.3 @@ -0,0 +1,45 @@
    17.4 +/*
    17.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    17.7 + * 
    17.8 + * This code is free software; you can redistribute it and/or modify it
    17.9 + * under the terms of the GNU General Public License version 2 only, as
   17.10 + * published by the Free Software Foundation.
   17.11 + * 
   17.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   17.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   17.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   17.15 + * version 2 for more details (a copy is included in the LICENSE file that
   17.16 + * accompanied this code).
   17.17 + * 
   17.18 + * You should have received a copy of the GNU General Public License version
   17.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   17.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   17.21 + * 
   17.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   17.23 + * or visit www.oracle.com if you need additional information or have any
   17.24 + * questions.
   17.25 + */
   17.26 +
   17.27 +/**
   17.28 + * JDK-8057980: let & const: remaining issues with lexical scoping
   17.29 + *
   17.30 + * @test
   17.31 + * @run
   17.32 + * @option --language=es6
   17.33 + */
   17.34 +
   17.35 +function tryEval(s) {
   17.36 +    try {
   17.37 +        eval(s);
   17.38 +    } catch (e) {
   17.39 +        print(String(e).replace(/\\/g, "/"));
   17.40 +    }
   17.41 +}
   17.42 +
   17.43 +tryEval('var x = 0; switch (x) { case 0: { let   x = 1; print(x); } case 1: { let   x = 2; print(x); }} print(x);');
   17.44 +tryEval('var x = 0; switch (x) { case 0: { const x = 1; print(x); } case 1: { const x = 2; print(x); }} print(x);');
   17.45 +
   17.46 +// TODO: the following should not throw
   17.47 +tryEval('switch (x) { case 0: let x = 1; }');
   17.48 +tryEval('switch (x) { case 0: const x = 1; }');
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/test/script/basic/es6/let-const-switch.js.EXPECTED	Thu Nov 27 18:02:28 2014 +0100
    18.3 @@ -0,0 +1,12 @@
    18.4 +1
    18.5 +2
    18.6 +0
    18.7 +1
    18.8 +2
    18.9 +0
   18.10 +SyntaxError: test/script/basic/es6/let-const-switch.js#34:8<eval>:1:25 Unsupported let declaration in unprotected switch statement
   18.11 +switch (x) { case 0: let x = 1; }
   18.12 +                         ^
   18.13 +SyntaxError: test/script/basic/es6/let-const-switch.js#34:8<eval>:1:27 Unsupported const declaration in unprotected switch statement
   18.14 +switch (x) { case 0: const x = 1; }
   18.15 +                           ^
    19.1 --- a/test/script/basic/es6/let-load.js	Thu Nov 27 17:14:01 2014 +0400
    19.2 +++ b/test/script/basic/es6/let-load.js	Thu Nov 27 18:02:28 2014 +0100
    19.3 @@ -40,17 +40,8 @@
    19.4  }
    19.5  
    19.6  print("imported var: " + a);
    19.7 -try {
    19.8 -    print("imported let: " + b);
    19.9 -} catch (e) {
   19.10 -    print(e);
   19.11 -}
   19.12 -
   19.13 -try {
   19.14 -    print("imported const: " + c);
   19.15 -} catch (e) {
   19.16 -    print(e);
   19.17 -}
   19.18 +print("imported let: " + b);
   19.19 +print("imported const: " + c);
   19.20  
   19.21  top();
   19.22  
   19.23 @@ -60,4 +51,10 @@
   19.24      print(e);
   19.25  }
   19.26  
   19.27 +try {
   19.28 +    c = "foo";
   19.29 +} catch (e) {
   19.30 +    print(e);
   19.31 +}
   19.32  
   19.33 +
    20.1 --- a/test/script/basic/es6/let-load.js.EXPECTED	Thu Nov 27 17:14:01 2014 +0400
    20.2 +++ b/test/script/basic/es6/let-load.js.EXPECTED	Thu Nov 27 18:02:28 2014 +0100
    20.3 @@ -6,3 +6,4 @@
    20.4  imported const: 3
    20.5  top level function
    20.6  ReferenceError: "block" is not defined
    20.7 +TypeError: Assignment to constant "c"
    21.1 --- a/test/script/basic/es6/let_const_closure.js.EXPECTED	Thu Nov 27 17:14:01 2014 +0400
    21.2 +++ b/test/script/basic/es6/let_const_closure.js.EXPECTED	Thu Nov 27 18:02:28 2014 +0100
    21.3 @@ -5,9 +5,9 @@
    21.4  test
    21.5  test
    21.6  test
    21.7 -3
    21.8 -3
    21.9 -3
   21.10  0
   21.11  1
   21.12  2
   21.13 +0
   21.14 +1
   21.15 +2
    22.1 --- a/test/script/basic/es6/lexical-toplevel.js.EXPECTED	Thu Nov 27 17:14:01 2014 +0400
    22.2 +++ b/test/script/basic/es6/lexical-toplevel.js.EXPECTED	Thu Nov 27 18:02:28 2014 +0100
    22.3 @@ -13,6 +13,7 @@
    22.4  false
    22.5  true
    22.6  true
    22.7 +TypeError: Assignment to constant "CONST"
    22.8  VAR
    22.9  LETLET
   22.10  CONST
   22.11 @@ -28,3 +29,4 @@
   22.12  false
   22.13  true
   22.14  true
   22.15 +TypeError: Assignment to constant "CONST"

mercurial