| Index: test/mjsunit/harmony/block-sloppy-function.js
 | 
| diff --git a/test/mjsunit/harmony/block-sloppy-function.js b/test/mjsunit/harmony/block-sloppy-function.js
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..a17a4c0799c7d9bced58941597f0b150f532ee7b
 | 
| --- /dev/null
 | 
| +++ b/test/mjsunit/harmony/block-sloppy-function.js
 | 
| @@ -0,0 +1,203 @@
 | 
| +// Copyright 2015 the V8 project authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +// Flags: --no-legacy-const --harmony-sloppy --harmony-sloppy-let
 | 
| +// Flags: --harmony-sloppy-function --harmony-destructuring
 | 
| +// Flags: --harmony-rest-parameters
 | 
| +
 | 
| +// Test Annex B 3.3 semantics for functions declared in blocks in sloppy mode.
 | 
| +// http://www.ecma-international.org/ecma-262/6.0/#sec-block-level-function-declarations-web-legacy-compatibility-semantics
 | 
| +
 | 
| +(function overridingLocalFunction() {
 | 
| +  var x = [];
 | 
| +  assertEquals('function', typeof f);
 | 
| +  function f() {
 | 
| +    x.push(1);
 | 
| +  }
 | 
| +  f();
 | 
| +  {
 | 
| +    f();
 | 
| +    function f() {
 | 
| +      x.push(2);
 | 
| +    }
 | 
| +    f();
 | 
| +  }
 | 
| +  f();
 | 
| +  {
 | 
| +    f();
 | 
| +    function f() {
 | 
| +      x.push(3);
 | 
| +    }
 | 
| +    f();
 | 
| +  }
 | 
| +  f();
 | 
| +  assertArrayEquals([1, 2, 2, 2, 3, 3, 3], x);
 | 
| +})();
 | 
| +
 | 
| +(function newFunctionBinding() {
 | 
| +  var x = [];
 | 
| +  assertEquals('undefined', typeof f);
 | 
| +  {
 | 
| +    f();
 | 
| +    function f() {
 | 
| +      x.push(2);
 | 
| +    }
 | 
| +    f();
 | 
| +  }
 | 
| +  f();
 | 
| +  {
 | 
| +    f();
 | 
| +    function f() {
 | 
| +      x.push(3);
 | 
| +    }
 | 
| +    f();
 | 
| +  }
 | 
| +  f();
 | 
| +  assertArrayEquals([2, 2, 2, 3, 3, 3], x);
 | 
| +})();
 | 
| +
 | 
| +(function shadowingLetDoesntBind() {
 | 
| +  let f = 1;
 | 
| +  assertEquals(1, f);
 | 
| +  {
 | 
| +    let y = 3;
 | 
| +    function f() {
 | 
| +      y = 2;
 | 
| +    }
 | 
| +    f();
 | 
| +    assertEquals(2, y);
 | 
| +  }
 | 
| +  assertEquals(1, f);
 | 
| +})();
 | 
| +
 | 
| +(function shadowingClassDoesntBind() {
 | 
| +  class f { }
 | 
| +  assertEquals('class f { }', f.toString());
 | 
| +  {
 | 
| +    let y = 3;
 | 
| +    function f() {
 | 
| +      y = 2;
 | 
| +    }
 | 
| +    f();
 | 
| +    assertEquals(2, y);
 | 
| +  }
 | 
| +  assertEquals('class f { }', f.toString());
 | 
| +})();
 | 
| +
 | 
| +(function shadowingConstDoesntBind() {
 | 
| +  const f = 1;
 | 
| +  assertEquals(1, f);
 | 
| +  {
 | 
| +    let y = 3;
 | 
| +    function f() {
 | 
| +      y = 2;
 | 
| +    }
 | 
| +    f();
 | 
| +    assertEquals(2, y);
 | 
| +  }
 | 
| +  assertEquals(1, f);
 | 
| +})();
 | 
| +
 | 
| +(function shadowingVarBinds() {
 | 
| +  var f = 1;
 | 
| +  assertEquals(1, f);
 | 
| +  {
 | 
| +    let y = 3;
 | 
| +    function f() {
 | 
| +      y = 2;
 | 
| +    }
 | 
| +    f();
 | 
| +    assertEquals(2, y);
 | 
| +  }
 | 
| +  assertEquals('function', typeof f);
 | 
| +})();
 | 
| +
 | 
| +(function conditional() {
 | 
| +  if (true) {
 | 
| +    function f() { return 1; }
 | 
| +  } else {
 | 
| +    function f() { return 2; }
 | 
| +  }
 | 
| +  assertEquals(1, f());
 | 
| +
 | 
| +  if (false) {
 | 
| +    function g() { return 1; }
 | 
| +  } else {
 | 
| +    function g() { return 2; }
 | 
| +  }
 | 
| +  assertEquals(2, g());
 | 
| +})();
 | 
| +
 | 
| +(function skipExecution() {
 | 
| +  {
 | 
| +    function f() { return 1; }
 | 
| +  }
 | 
| +  assertEquals(1, f());
 | 
| +  {
 | 
| +    function f() { return 2; }
 | 
| +  }
 | 
| +  assertEquals(2, f());
 | 
| +  L: {
 | 
| +    assertEquals(3, f());
 | 
| +    break L;
 | 
| +    function f() { return 3; }
 | 
| +  }
 | 
| +  assertEquals(2, f());
 | 
| +})();
 | 
| +
 | 
| +// Test that hoisting from blocks doesn't happen in global scope
 | 
| +function globalUnhoisted() { return 0; }
 | 
| +{
 | 
| +  function globalUnhoisted() { return 1; }
 | 
| +}
 | 
| +assertEquals(0, globalUnhoisted());
 | 
| +
 | 
| +// Test that shadowing arguments is fine
 | 
| +(function shadowArguments(x) {
 | 
| +  assertArrayEquals([1], arguments);
 | 
| +  {
 | 
| +    assertEquals('function', typeof arguments);
 | 
| +    function arguments() {}
 | 
| +    assertEquals('function', typeof arguments);
 | 
| +  }
 | 
| +  assertEquals('function', typeof arguments);
 | 
| +})(1);
 | 
| +
 | 
| +// Shadow function parameter
 | 
| +(function shadowParameter(x) {
 | 
| +  assertEquals(1, x);
 | 
| +  {
 | 
| +    function x() {}
 | 
| +  }
 | 
| +  assertEquals('function', typeof x);
 | 
| +})(1);
 | 
| +
 | 
| +// Shadow function parameter
 | 
| +(function shadowDefaultParameter(x = 0) {
 | 
| +  assertEquals(1, x);
 | 
| +  {
 | 
| +    function x() {}
 | 
| +  }
 | 
| +  // TODO(littledan): Once destructured parameters are no longer
 | 
| +  // let-bound, enable this assertion. This is the core of the test.
 | 
| +  // assertEquals('function', typeof x);
 | 
| +})(1);
 | 
| +
 | 
| +(function shadowRestParameter(...x) {
 | 
| +  assertArrayEquals([1], x);
 | 
| +  {
 | 
| +    function x() {}
 | 
| +  }
 | 
| +  // TODO(littledan): Once destructured parameters are no longer
 | 
| +  // let-bound, enable this assertion. This is the core of the test.
 | 
| +  // assertEquals('function', typeof x);
 | 
| +})(1);
 | 
| +
 | 
| +assertThrows(function notInDefaultScope(x = y) {
 | 
| +  {
 | 
| +    function y() {}
 | 
| +  }
 | 
| +  assertEquals('function', typeof y);
 | 
| +  assertEquals(x, undefined);
 | 
| +}, ReferenceError);
 | 
| 
 |