mirror of
				https://github.com/tc39/test262.git
				synced 2025-11-03 21:24:30 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			669 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			669 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// 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.
 | 
						|
 | 
						|
// 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 shadowingLetDoesntBindGenerator() {
 | 
						|
  let f = function *f() {
 | 
						|
    while(true) {
 | 
						|
      yield 1;
 | 
						|
    }
 | 
						|
  };
 | 
						|
  assertEquals(1, f().next().value);
 | 
						|
  {
 | 
						|
    function *f() {
 | 
						|
      while(true) {
 | 
						|
        yield 2;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    assertEquals(2, f().next().value);
 | 
						|
  }
 | 
						|
  assertEquals(1, f().next().value);
 | 
						|
})();
 | 
						|
 | 
						|
(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 complexParams(a = 0) {
 | 
						|
  {
 | 
						|
    let y = 3;
 | 
						|
    function f(b = 0) {
 | 
						|
      y = 2;
 | 
						|
    }
 | 
						|
    f();
 | 
						|
    assertEquals(2, y);
 | 
						|
  }
 | 
						|
  assertEquals('function', typeof f);
 | 
						|
})();
 | 
						|
 | 
						|
(function complexVarParams(a = 0) {
 | 
						|
  var f;
 | 
						|
  {
 | 
						|
    let y = 3;
 | 
						|
    function f(b = 0) {
 | 
						|
      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());
 | 
						|
})();
 | 
						|
 | 
						|
(function executionOrder() {
 | 
						|
  function getOuter() {
 | 
						|
    return f;
 | 
						|
  }
 | 
						|
  assertEquals('undefined', typeof getOuter());
 | 
						|
 | 
						|
  {
 | 
						|
    assertEquals('function', typeof f);
 | 
						|
    assertEquals('undefined', typeof getOuter());
 | 
						|
    function f () {}
 | 
						|
    assertEquals('function', typeof f);
 | 
						|
    assertEquals('function', typeof getOuter());
 | 
						|
  }
 | 
						|
 | 
						|
  assertEquals('function', typeof getOuter());
 | 
						|
})();
 | 
						|
 | 
						|
(function reassignBindings() {
 | 
						|
  function getOuter() {
 | 
						|
    return f;
 | 
						|
  }
 | 
						|
  assertEquals('undefined', typeof getOuter());
 | 
						|
 | 
						|
  {
 | 
						|
    assertEquals('function', typeof f);
 | 
						|
    assertEquals('undefined', typeof getOuter());
 | 
						|
    f = 1;
 | 
						|
    assertEquals('number', typeof f);
 | 
						|
    assertEquals('undefined', typeof getOuter());
 | 
						|
    function f () {}
 | 
						|
    assertEquals('number', typeof f);
 | 
						|
    assertEquals('number', typeof getOuter());
 | 
						|
    f = '';
 | 
						|
    assertEquals('string', typeof f);
 | 
						|
    assertEquals('number', typeof getOuter());
 | 
						|
  }
 | 
						|
 | 
						|
  assertEquals('number', typeof getOuter());
 | 
						|
})();
 | 
						|
 | 
						|
// 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);
 | 
						|
 | 
						|
 | 
						|
// Don't shadow simple parameter
 | 
						|
(function shadowingParameterDoesntBind(x) {
 | 
						|
  assertEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals(1, x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Don't shadow complex parameter
 | 
						|
(function shadowingDefaultParameterDoesntBind(x = 0) {
 | 
						|
  assertEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals(1, x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Don't shadow nested complex parameter
 | 
						|
(function shadowingNestedParameterDoesntBind([[x]]) {
 | 
						|
  assertEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals(1, x);
 | 
						|
})([[1]]);
 | 
						|
 | 
						|
// Don't shadow rest parameter
 | 
						|
(function shadowingRestParameterDoesntBind(...x) {
 | 
						|
  assertArrayEquals([1], x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertArrayEquals([1], x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Don't shadow complex rest parameter
 | 
						|
(function shadowingComplexRestParameterDoesntBind(...[x]) {
 | 
						|
  assertArrayEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertArrayEquals(1, x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Previous tests with a var declaration thrown in.
 | 
						|
// Don't shadow simple parameter
 | 
						|
(function shadowingVarParameterDoesntBind(x) {
 | 
						|
  var x;
 | 
						|
  assertEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals(1, x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Don't shadow complex parameter
 | 
						|
(function shadowingVarDefaultParameterDoesntBind(x = 0) {
 | 
						|
  var x;
 | 
						|
  assertEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals(1, x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Don't shadow nested complex parameter
 | 
						|
(function shadowingVarNestedParameterDoesntBind([[x]]) {
 | 
						|
  var x;
 | 
						|
  assertEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals(1, x);
 | 
						|
})([[1]]);
 | 
						|
 | 
						|
// Don't shadow rest parameter
 | 
						|
(function shadowingVarRestParameterDoesntBind(...x) {
 | 
						|
  var x;
 | 
						|
  assertArrayEquals([1], x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertArrayEquals([1], x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Don't shadow complex rest parameter
 | 
						|
(function shadowingVarComplexRestParameterDoesntBind(...[x]) {
 | 
						|
  var x;
 | 
						|
  assertArrayEquals(1, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertArrayEquals(1, x);
 | 
						|
})(1);
 | 
						|
 | 
						|
 | 
						|
// Hoisting is not affected by other simple parameters
 | 
						|
(function irrelevantParameterBinds(y, z) {
 | 
						|
  assertEquals(undefined, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals('function', typeof x);
 | 
						|
})(1);
 | 
						|
 | 
						|
// Hoisting is not affected by other complex parameters
 | 
						|
(function irrelevantComplexParameterBinds([y] = [], z) {
 | 
						|
  assertEquals(undefined, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals('function', typeof x);
 | 
						|
})();
 | 
						|
 | 
						|
// Hoisting is not affected by rest parameters
 | 
						|
(function irrelevantRestParameterBinds(y, ...z) {
 | 
						|
  assertEquals(undefined, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals('function', typeof x);
 | 
						|
})();
 | 
						|
 | 
						|
// Hoisting is not affected by complex rest parameters
 | 
						|
(function irrelevantRestParameterBinds(y, ...[z]) {
 | 
						|
  assertEquals(undefined, x);
 | 
						|
  {
 | 
						|
    function x() {}
 | 
						|
  }
 | 
						|
  assertEquals('function', typeof x);
 | 
						|
})();
 | 
						|
 | 
						|
 | 
						|
// Test that shadowing function name is fine
 | 
						|
{
 | 
						|
  let called = false;
 | 
						|
  (function shadowFunctionName() {
 | 
						|
    if (called) assertUnreachable();
 | 
						|
    called = true;
 | 
						|
    {
 | 
						|
      function shadowFunctionName() {
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
      assertEquals(0, shadowFunctionName());
 | 
						|
    }
 | 
						|
    assertEquals(0, shadowFunctionName());
 | 
						|
  })();
 | 
						|
}
 | 
						|
 | 
						|
{
 | 
						|
  let called = false;
 | 
						|
  (function shadowFunctionNameWithComplexParameter(...r) {
 | 
						|
    if (called) assertUnreachable();
 | 
						|
    called = true;
 | 
						|
    {
 | 
						|
      function shadowFunctionNameWithComplexParameter() {
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
      assertEquals(0, shadowFunctionNameWithComplexParameter());
 | 
						|
    }
 | 
						|
    assertEquals(0, shadowFunctionNameWithComplexParameter());
 | 
						|
  })();
 | 
						|
}
 | 
						|
 | 
						|
(function shadowOuterVariable() {
 | 
						|
  {
 | 
						|
    let f = 0;
 | 
						|
    (function () {
 | 
						|
      assertEquals(undefined, f);
 | 
						|
      {
 | 
						|
        assertEquals(1, f());
 | 
						|
        function f() { return 1; }
 | 
						|
        assertEquals(1, f());
 | 
						|
      }
 | 
						|
      assertEquals(1, f());
 | 
						|
    })();
 | 
						|
    assertEquals(0, f);
 | 
						|
  }
 | 
						|
})();
 | 
						|
 | 
						|
(function notInDefaultScope() {
 | 
						|
  var y = 1;
 | 
						|
  (function innerNotInDefaultScope(x = y) {
 | 
						|
    assertEquals('undefined', typeof y);
 | 
						|
    {
 | 
						|
      function y() {}
 | 
						|
    }
 | 
						|
    assertEquals('function', typeof y);
 | 
						|
    assertEquals(1, x);
 | 
						|
  })();
 | 
						|
})();
 | 
						|
 | 
						|
(function noHoistingThroughNestedLexical() {
 | 
						|
  {
 | 
						|
    let f = 2;
 | 
						|
    {
 | 
						|
      let y = 3;
 | 
						|
      function f() {
 | 
						|
        y = 2;
 | 
						|
      }
 | 
						|
      f();
 | 
						|
      assertEquals(2, y);
 | 
						|
    }
 | 
						|
    assertEquals(2, f);
 | 
						|
  }
 | 
						|
  assertThrows(()=>f, ReferenceError);
 | 
						|
})();
 | 
						|
 | 
						|
// Only the first function is hoisted; the second is blocked by the first.
 | 
						|
// Contrast overridingLocalFunction, in which the outer function declaration
 | 
						|
// is not lexical and so the inner declaration is hoisted.
 | 
						|
(function noHoistingThroughNestedFunctions() {
 | 
						|
  assertEquals(undefined, f); // Also checks that the var-binding exists
 | 
						|
 | 
						|
  {
 | 
						|
    assertEquals(4, f());
 | 
						|
 | 
						|
    function f() {
 | 
						|
      return 4;
 | 
						|
    }
 | 
						|
 | 
						|
    {
 | 
						|
      assertEquals(5, f());
 | 
						|
      function f() {
 | 
						|
        return 5;
 | 
						|
      }
 | 
						|
      assertEquals(5, f());
 | 
						|
    }
 | 
						|
 | 
						|
    assertEquals(4, f());
 | 
						|
  }
 | 
						|
 | 
						|
  assertEquals(4, f());
 | 
						|
})();
 | 
						|
 | 
						|
// B.3.5 interacts with B.3.3 to allow this.
 | 
						|
(function hoistingThroughSimpleCatch() {
 | 
						|
  assertEquals(undefined, f);
 | 
						|
 | 
						|
  try {
 | 
						|
    throw 0;
 | 
						|
  } catch (f) {
 | 
						|
    {
 | 
						|
      assertEquals(4, f());
 | 
						|
 | 
						|
      function f() {
 | 
						|
        return 4;
 | 
						|
      }
 | 
						|
 | 
						|
      assertEquals(4, f());
 | 
						|
    }
 | 
						|
 | 
						|
    assertEquals(0, f);
 | 
						|
  }
 | 
						|
 | 
						|
  assertEquals(4, f());
 | 
						|
})();
 | 
						|
 | 
						|
(function noHoistingThroughComplexCatch() {
 | 
						|
  try {
 | 
						|
    throw 0;
 | 
						|
  } catch ({f}) {
 | 
						|
    {
 | 
						|
      assertEquals(4, f());
 | 
						|
 | 
						|
      function f() {
 | 
						|
        return 4;
 | 
						|
      }
 | 
						|
 | 
						|
      assertEquals(4, f());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  assertThrows(()=>f, ReferenceError);
 | 
						|
})();
 | 
						|
 | 
						|
(function hoistingThroughWith() {
 | 
						|
  with ({f: 0}) {
 | 
						|
    assertEquals(0, f);
 | 
						|
 | 
						|
    {
 | 
						|
      assertEquals(4, f());
 | 
						|
 | 
						|
      function f() {
 | 
						|
        return 4;
 | 
						|
      }
 | 
						|
 | 
						|
      assertEquals(4, f());
 | 
						|
    }
 | 
						|
 | 
						|
    assertEquals(0, f);
 | 
						|
  }
 | 
						|
 | 
						|
  assertEquals(4, f());
 | 
						|
})();
 | 
						|
 | 
						|
// Test that hoisting from blocks does happen in global scope
 | 
						|
function globalHoisted() { return 0; }
 | 
						|
{
 | 
						|
  function globalHoisted() { return 1; }
 | 
						|
}
 | 
						|
assertEquals(1, globalHoisted());
 | 
						|
 | 
						|
// Also happens when not previously defined
 | 
						|
assertEquals(undefined, globalUndefinedHoisted);
 | 
						|
{
 | 
						|
  function globalUndefinedHoisted() { return 1; }
 | 
						|
}
 | 
						|
assertEquals(1, globalUndefinedHoisted());
 | 
						|
var globalUndefinedHoistedDescriptor =
 | 
						|
    Object.getOwnPropertyDescriptor(this, "globalUndefinedHoisted");
 | 
						|
assertFalse(globalUndefinedHoistedDescriptor.configurable);
 | 
						|
assertTrue(globalUndefinedHoistedDescriptor.writable);
 | 
						|
assertTrue(globalUndefinedHoistedDescriptor.enumerable);
 | 
						|
assertEquals(1, globalUndefinedHoistedDescriptor.value());
 | 
						|
 | 
						|
// When a function property is hoisted, it should be
 | 
						|
// made enumerable.
 | 
						|
// BUG(v8:4451)
 | 
						|
Object.defineProperty(this, "globalNonEnumerable", {
 | 
						|
  value: false,
 | 
						|
  configurable: true,
 | 
						|
  writable: true,
 | 
						|
  enumerable: false
 | 
						|
});
 | 
						|
eval("{function globalNonEnumerable() { return 1; }}");
 | 
						|
var globalNonEnumerableDescriptor
 | 
						|
    = Object.getOwnPropertyDescriptor(this, "globalNonEnumerable");
 | 
						|
// BUG(v8:4451): Should be made non-configurable
 | 
						|
assertTrue(globalNonEnumerableDescriptor.configurable);
 | 
						|
assertTrue(globalNonEnumerableDescriptor.writable);
 | 
						|
// BUG(v8:4451): Should be made enumerable
 | 
						|
assertFalse(globalNonEnumerableDescriptor.enumerable);
 | 
						|
assertEquals(1, globalNonEnumerableDescriptor.value());
 | 
						|
 | 
						|
// When a function property is hoisted, it should be overwritten and
 | 
						|
// made writable and overwritten, even if the property was non-writable.
 | 
						|
Object.defineProperty(this, "globalNonWritable", {
 | 
						|
  value: false,
 | 
						|
  configurable: true,
 | 
						|
  writable: false,
 | 
						|
  enumerable: true
 | 
						|
});
 | 
						|
eval("{function globalNonWritable() { return 1; }}");
 | 
						|
var globalNonWritableDescriptor
 | 
						|
    = Object.getOwnPropertyDescriptor(this, "globalNonWritable");
 | 
						|
// BUG(v8:4451): Should be made non-configurable
 | 
						|
assertTrue(globalNonWritableDescriptor.configurable);
 | 
						|
// BUG(v8:4451): Should be made writable
 | 
						|
assertFalse(globalNonWritableDescriptor.writable);
 | 
						|
assertFalse(globalNonEnumerableDescriptor.enumerable);
 | 
						|
// BUG(v8:4451): Should be overwritten
 | 
						|
assertEquals(false, globalNonWritableDescriptor.value);
 | 
						|
 | 
						|
// Test that hoisting from blocks does happen in an eval
 | 
						|
eval(`
 | 
						|
  function evalHoisted() { return 0; }
 | 
						|
  {
 | 
						|
    function evalHoisted() { return 1; }
 | 
						|
  }
 | 
						|
  assertEquals(1, evalHoisted());
 | 
						|
`);
 | 
						|
 | 
						|
// Test that hoisting from blocks happens from eval in a function
 | 
						|
!function() {
 | 
						|
  eval(`
 | 
						|
    function evalInFunctionHoisted() { return 0; }
 | 
						|
    {
 | 
						|
      function evalInFunctionHoisted() { return 1; }
 | 
						|
    }
 | 
						|
    assertEquals(1, evalInFunctionHoisted());
 | 
						|
  `);
 | 
						|
}();
 | 
						|
 | 
						|
(function evalHoistingThroughSimpleCatch() {
 | 
						|
  try {
 | 
						|
    throw 0;
 | 
						|
  } catch (f) {
 | 
						|
    eval(`{ function f() {
 | 
						|
      return 4;
 | 
						|
    } }`);
 | 
						|
 | 
						|
    assertEquals(0, f);
 | 
						|
  }
 | 
						|
 | 
						|
  assertEquals(4, f());
 | 
						|
})();
 | 
						|
 | 
						|
(function evalHoistingThroughWith() {
 | 
						|
  with ({f: 0}) {
 | 
						|
    eval(`{ function f() {
 | 
						|
      return 4;
 | 
						|
    } }`);
 | 
						|
 | 
						|
    assertEquals(0, f);
 | 
						|
  }
 | 
						|
 | 
						|
  assertEquals(4, f());
 | 
						|
})();
 | 
						|
 | 
						|
let dontHoistGlobal;
 | 
						|
{ function dontHoistGlobal() {} }
 | 
						|
assertEquals(undefined, dontHoistGlobal);
 | 
						|
 | 
						|
let dontHoistEval;
 | 
						|
var throws = false;
 | 
						|
try {
 | 
						|
  eval("{ function dontHoistEval() {} }");
 | 
						|
} catch (e) {
 | 
						|
  throws = true;
 | 
						|
}
 | 
						|
assertFalse(throws);
 | 
						|
 | 
						|
// When the global object is frozen, silently don't hoist
 | 
						|
// Currently this actually throws BUG(v8:4452)
 | 
						|
Object.freeze(this);
 | 
						|
{
 | 
						|
  let throws = false;
 | 
						|
  try {
 | 
						|
    eval('{ function hoistWhenFrozen() {} }');
 | 
						|
  } catch (e) {
 | 
						|
    throws = true;
 | 
						|
  }
 | 
						|
  assertFalse(this.hasOwnProperty("hoistWhenFrozen"));
 | 
						|
  assertThrows(() => hoistWhenFrozen, ReferenceError);
 | 
						|
  // Should be assertFalse BUG(v8:4452)
 | 
						|
  assertTrue(throws);
 | 
						|
}
 |