| // Copyright 2014 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: --allow-natives-syntax --harmony-do-expressions | |
| (function TestBasics() { | |
| var C = class C {} | |
| assertEquals(typeof C, 'function'); | |
| assertEquals(C.__proto__, Function.prototype); | |
| assertEquals(Object.prototype, Object.getPrototypeOf(C.prototype)); | |
| assertEquals(Function.prototype, Object.getPrototypeOf(C)); | |
| assertEquals('C', C.name); | |
| class D {} | |
| assertEquals(typeof D, 'function'); | |
| assertEquals(D.__proto__, Function.prototype); | |
| assertEquals(Object.prototype, Object.getPrototypeOf(D.prototype)); | |
| assertEquals(Function.prototype, Object.getPrototypeOf(D)); | |
| assertEquals('D', D.name); | |
| class D2 { constructor() {} } | |
| assertEquals('D2', D2.name); | |
| var E = class {} | |
| assertEquals('E', E.name); // Should be 'E'. | |
| var F = class { constructor() {} }; | |
| assertEquals('F', F.name); // Should be 'F'. | |
| })(); | |
| (function TestBasicsExtends() { | |
| class C extends null {} | |
| assertEquals(typeof C, 'function'); | |
| assertEquals(C.__proto__, Function.prototype); | |
| assertEquals(null, Object.getPrototypeOf(C.prototype)); | |
| class D extends C {} | |
| assertEquals(typeof D, 'function'); | |
| assertEquals(D.__proto__, C); | |
| assertEquals(C.prototype, Object.getPrototypeOf(D.prototype)); | |
| })(); | |
| (function TestSideEffectInExtends() { | |
| var calls = 0; | |
| class C {} | |
| class D extends (calls++, C) {} | |
| assertEquals(1, calls); | |
| assertEquals(typeof D, 'function'); | |
| assertEquals(D.__proto__, C); | |
| assertEquals(C.prototype, Object.getPrototypeOf(D.prototype)); | |
| })(); | |
| (function TestInvalidExtends() { | |
| assertThrows(function() { | |
| class C extends 42 {} | |
| }, TypeError); | |
| assertThrows(function() { | |
| // Function but its .prototype is not null or a function. | |
| class C extends Math.abs {} | |
| }, TypeError); | |
| assertThrows(function() { | |
| Math.abs.prototype = 42; | |
| class C extends Math.abs {} | |
| }, TypeError); | |
| delete Math.abs.prototype; | |
| assertThrows(function() { | |
| function* g() {} | |
| class C extends g {} | |
| }, TypeError); | |
| })(); | |
| (function TestConstructorProperty() { | |
| class C {} | |
| assertEquals(C, C.prototype.constructor); | |
| var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor'); | |
| assertTrue(descr.configurable); | |
| assertFalse(descr.enumerable); | |
| assertTrue(descr.writable); | |
| })(); | |
| (function TestPrototypeProperty() { | |
| class C {} | |
| var descr = Object.getOwnPropertyDescriptor(C, 'prototype'); | |
| assertFalse(descr.configurable); | |
| assertFalse(descr.enumerable); | |
| assertFalse(descr.writable); | |
| })(); | |
| (function TestConstructor() { | |
| var count = 0; | |
| class C { | |
| constructor() { | |
| assertEquals(Object.getPrototypeOf(this), C.prototype); | |
| count++; | |
| } | |
| } | |
| assertEquals(C, C.prototype.constructor); | |
| var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor'); | |
| assertTrue(descr.configurable); | |
| assertFalse(descr.enumerable); | |
| assertTrue(descr.writable); | |
| var c = new C(); | |
| assertEquals(1, count); | |
| assertEquals(Object.getPrototypeOf(c), C.prototype); | |
| })(); | |
| (function TestImplicitConstructor() { | |
| class C {} | |
| var c = new C(); | |
| assertEquals(Object.getPrototypeOf(c), C.prototype); | |
| })(); | |
| (function TestConstructorStrict() { | |
| class C { | |
| constructor() { | |
| assertThrows(function() { | |
| nonExistingBinding = 42; | |
| }, ReferenceError); | |
| } | |
| } | |
| new C(); | |
| })(); | |
| (function TestSuperInConstructor() { | |
| var calls = 0; | |
| class B {} | |
| B.prototype.x = 42; | |
| class C extends B { | |
| constructor() { | |
| super(); | |
| calls++; | |
| assertEquals(42, super.x); | |
| } | |
| } | |
| new C; | |
| assertEquals(1, calls); | |
| })(); | |
| (function TestStrictMode() { | |
| class C {} | |
| with ({a: 1}) { | |
| assertEquals(1, a); | |
| } | |
| assertThrows('class C extends function B() { with ({}); return B; }() {}', | |
| SyntaxError); | |
| var D = class extends function() { | |
| this.args = arguments; | |
| } {}; | |
| assertThrows(function() { | |
| Object.getPrototypeOf(D).arguments; | |
| }, TypeError); | |
| var e = new D(); | |
| assertThrows(() => e.args.callee, TypeError); | |
| assertEquals(undefined, Object.getOwnPropertyDescriptor(e.args, 'caller')); | |
| assertFalse('caller' in e.args); | |
| })(); | |
| (function TestToString() { | |
| class C {} | |
| assertEquals('class C {}', C.toString()); | |
| class D { constructor() { 42; } } | |
| assertEquals('class D { constructor() { 42; } }', D.toString()); | |
| class E { x() { 42; } } | |
| assertEquals('class E { x() { 42; } }', E.toString()); | |
| })(); | |
| function assertMethodDescriptor(object, name) { | |
| var descr = Object.getOwnPropertyDescriptor(object, name); | |
| assertTrue(descr.configurable); | |
| assertFalse(descr.enumerable); | |
| assertTrue(descr.writable); | |
| assertEquals('function', typeof descr.value); | |
| assertFalse('prototype' in descr.value); | |
| assertEquals(name, descr.value.name); | |
| } | |
| function assertGetterDescriptor(object, name) { | |
| var descr = Object.getOwnPropertyDescriptor(object, name); | |
| assertTrue(descr.configurable); | |
| assertFalse(descr.enumerable); | |
| assertEquals('function', typeof descr.get); | |
| assertFalse('prototype' in descr.get); | |
| assertEquals(undefined, descr.set); | |
| assertEquals("get " + name, descr.get.name); | |
| } | |
| function assertSetterDescriptor(object, name) { | |
| var descr = Object.getOwnPropertyDescriptor(object, name); | |
| assertTrue(descr.configurable); | |
| assertFalse(descr.enumerable); | |
| assertEquals(undefined, descr.get); | |
| assertEquals('function', typeof descr.set); | |
| assertFalse('prototype' in descr.set); | |
| assertEquals("set " + name, descr.set.name); | |
| } | |
| function assertAccessorDescriptor(object, name) { | |
| var descr = Object.getOwnPropertyDescriptor(object, name); | |
| assertTrue(descr.configurable); | |
| assertFalse(descr.enumerable); | |
| assertEquals('function', typeof descr.get); | |
| assertEquals('function', typeof descr.set); | |
| assertFalse('prototype' in descr.get); | |
| assertFalse('prototype' in descr.set); | |
| assertEquals("get " + name, descr.get.name); | |
| assertEquals("set " + name, descr.set.name); | |
| } | |
| (function TestMethods() { | |
| class C { | |
| method() { return 1; } | |
| static staticMethod() { return 2; } | |
| method2() { return 3; } | |
| static staticMethod2() { return 4; } | |
| } | |
| assertMethodDescriptor(C.prototype, 'method'); | |
| assertMethodDescriptor(C.prototype, 'method2'); | |
| assertMethodDescriptor(C, 'staticMethod'); | |
| assertMethodDescriptor(C, 'staticMethod2'); | |
| assertEquals(1, new C().method()); | |
| assertEquals(2, C.staticMethod()); | |
| assertEquals(3, new C().method2()); | |
| assertEquals(4, C.staticMethod2()); | |
| })(); | |
| (function TestGetters() { | |
| class C { | |
| get x() { return 1; } | |
| static get staticX() { return 2; } | |
| get y() { return 3; } | |
| static get staticY() { return 4; } | |
| } | |
| assertGetterDescriptor(C.prototype, 'x'); | |
| assertGetterDescriptor(C.prototype, 'y'); | |
| assertGetterDescriptor(C, 'staticX'); | |
| assertGetterDescriptor(C, 'staticY'); | |
| assertEquals(1, new C().x); | |
| assertEquals(2, C.staticX); | |
| assertEquals(3, new C().y); | |
| assertEquals(4, C.staticY); | |
| })(); | |
| (function TestSetters() { | |
| var x, staticX, y, staticY; | |
| class C { | |
| set x(v) { x = v; } | |
| static set staticX(v) { staticX = v; } | |
| set y(v) { y = v; } | |
| static set staticY(v) { staticY = v; } | |
| } | |
| assertSetterDescriptor(C.prototype, 'x'); | |
| assertSetterDescriptor(C.prototype, 'y'); | |
| assertSetterDescriptor(C, 'staticX'); | |
| assertSetterDescriptor(C, 'staticY'); | |
| assertEquals(1, new C().x = 1); | |
| assertEquals(1, x); | |
| assertEquals(2, C.staticX = 2); | |
| assertEquals(2, staticX); | |
| assertEquals(3, new C().y = 3); | |
| assertEquals(3, y); | |
| assertEquals(4, C.staticY = 4); | |
| assertEquals(4, staticY); | |
| })(); | |
| (function TestSideEffectsInPropertyDefine() { | |
| function B() {} | |
| B.prototype = { | |
| constructor: B, | |
| set m(v) { | |
| throw Error(); | |
| } | |
| }; | |
| class C extends B { | |
| m() { return 1; } | |
| } | |
| assertEquals(1, new C().m()); | |
| })(); | |
| (function TestAccessors() { | |
| class C { | |
| constructor(x) { | |
| this._x = x; | |
| } | |
| get x() { return this._x; } | |
| set x(v) { this._x = v; } | |
| static get staticX() { return this._x; } | |
| static set staticX(v) { this._x = v; } | |
| } | |
| assertAccessorDescriptor(C.prototype, 'x'); | |
| assertAccessorDescriptor(C, 'staticX'); | |
| var c = new C(1); | |
| c._x = 1; | |
| assertEquals(1, c.x); | |
| c.x = 2; | |
| assertEquals(2, c._x); | |
| C._x = 3; | |
| assertEquals(3, C.staticX); | |
| C._x = 4; | |
| assertEquals(4, C.staticX ); | |
| })(); | |
| (function TestProto() { | |
| class C { | |
| __proto__() { return 1; } | |
| } | |
| assertMethodDescriptor(C.prototype, '__proto__'); | |
| assertEquals(1, new C().__proto__()); | |
| })(); | |
| (function TestProtoStatic() { | |
| class C { | |
| static __proto__() { return 1; } | |
| } | |
| assertMethodDescriptor(C, '__proto__'); | |
| assertEquals(1, C.__proto__()); | |
| })(); | |
| (function TestProtoAccessor() { | |
| class C { | |
| get __proto__() { return this._p; } | |
| set __proto__(v) { this._p = v; } | |
| } | |
| assertAccessorDescriptor(C.prototype, '__proto__'); | |
| var c = new C(); | |
| c._p = 1; | |
| assertEquals(1, c.__proto__); | |
| c.__proto__ = 2; | |
| assertEquals(2, c.__proto__); | |
| })(); | |
| (function TestStaticProtoAccessor() { | |
| class C { | |
| static get __proto__() { return this._p; } | |
| static set __proto__(v) { this._p = v; } | |
| } | |
| assertAccessorDescriptor(C, '__proto__'); | |
| C._p = 1; | |
| assertEquals(1, C.__proto__); | |
| C.__proto__ = 2; | |
| assertEquals(2, C.__proto__); | |
| })(); | |
| (function TestSettersOnProto() { | |
| function Base() {} | |
| Base.prototype = { | |
| set constructor(_) { | |
| assertUnreachable(); | |
| }, | |
| set m(_) { | |
| assertUnreachable(); | |
| } | |
| }; | |
| Object.defineProperty(Base, 'staticM', { | |
| set: function() { | |
| assertUnreachable(); | |
| } | |
| }); | |
| class C extends Base { | |
| m() { | |
| return 1; | |
| } | |
| static staticM() { | |
| return 2; | |
| } | |
| } | |
| assertEquals(1, new C().m()); | |
| assertEquals(2, C.staticM()); | |
| })(); | |
| (function TestConstructableButNoPrototype() { | |
| var Base = function() {}.bind(); | |
| assertThrows(function() { | |
| class C extends Base {} | |
| }, TypeError); | |
| })(); | |
| (function TestPrototypeGetter() { | |
| var calls = 0; | |
| var Base = function() {}.bind(); | |
| Object.defineProperty(Base, 'prototype', { | |
| get: function() { | |
| calls++; | |
| return null; | |
| }, | |
| configurable: true | |
| }); | |
| class C extends Base {} | |
| assertEquals(1, calls); | |
| calls = 0; | |
| Object.defineProperty(Base, 'prototype', { | |
| get: function() { | |
| calls++; | |
| return 42; | |
| }, | |
| configurable: true | |
| }); | |
| assertThrows(function() { | |
| class C extends Base {} | |
| }, TypeError); | |
| assertEquals(1, calls); | |
| })(); | |
| (function TestPrototypeSetter() { | |
| var Base = function() {}.bind(); | |
| Object.defineProperty(Base, 'prototype', { | |
| set: function() { | |
| assertUnreachable(); | |
| } | |
| }); | |
| assertThrows(function() { | |
| class C extends Base {} | |
| }, TypeError); | |
| })(); | |
| (function TestSuperInMethods() { | |
| class B { | |
| method() { | |
| return 1; | |
| } | |
| get x() { | |
| return 2; | |
| } | |
| } | |
| class C extends B { | |
| method() { | |
| assertEquals(2, super.x); | |
| return super.method(); | |
| } | |
| } | |
| assertEquals(1, new C().method()); | |
| })(); | |
| (function TestSuperInGetter() { | |
| class B { | |
| method() { | |
| return 1; | |
| } | |
| get x() { | |
| return 2; | |
| } | |
| } | |
| class C extends B { | |
| get y() { | |
| assertEquals(2, super.x); | |
| return super.method(); | |
| } | |
| } | |
| assertEquals(1, new C().y); | |
| })(); | |
| (function TestSuperInSetter() { | |
| class B { | |
| method() { | |
| return 1; | |
| } | |
| get x() { | |
| return 2; | |
| } | |
| } | |
| class C extends B { | |
| set y(v) { | |
| assertEquals(3, v); | |
| assertEquals(2, super.x); | |
| assertEquals(1, super.method()); | |
| } | |
| } | |
| assertEquals(3, new C().y = 3); | |
| })(); | |
| (function TestSuperInStaticMethods() { | |
| class B { | |
| static method() { | |
| return 1; | |
| } | |
| static get x() { | |
| return 2; | |
| } | |
| } | |
| class C extends B { | |
| static method() { | |
| assertEquals(2, super.x); | |
| return super.method(); | |
| } | |
| } | |
| assertEquals(1, C.method()); | |
| })(); | |
| (function TestSuperInStaticGetter() { | |
| class B { | |
| static method() { | |
| return 1; | |
| } | |
| static get x() { | |
| return 2; | |
| } | |
| } | |
| class C extends B { | |
| static get x() { | |
| assertEquals(2, super.x); | |
| return super.method(); | |
| } | |
| } | |
| assertEquals(1, C.x); | |
| })(); | |
| (function TestSuperInStaticSetter() { | |
| class B { | |
| static method() { | |
| return 1; | |
| } | |
| static get x() { | |
| return 2; | |
| } | |
| } | |
| class C extends B { | |
| static set x(v) { | |
| assertEquals(3, v); | |
| assertEquals(2, super.x); | |
| assertEquals(1, super.method()); | |
| } | |
| } | |
| assertEquals(3, C.x = 3); | |
| })(); | |
| (function TestNumericPropertyNames() { | |
| class B { | |
| 1() { return 1; } | |
| get 2() { return 2; } | |
| set 3(_) {} | |
| static 4() { return 4; } | |
| static get 5() { return 5; } | |
| static set 6(_) {} | |
| 2147483649() { return 2147483649; } | |
| get 2147483650() { return 2147483650; } | |
| set 2147483651(_) {} | |
| static 2147483652() { return 2147483652; } | |
| static get 2147483653() { return 2147483653; } | |
| static set 2147483654(_) {} | |
| 4294967294() { return 4294967294; } | |
| 4294967295() { return 4294967295; } | |
| static 4294967294() { return 4294967294; } | |
| static 4294967295() { return 4294967295; } | |
| } | |
| assertMethodDescriptor(B.prototype, '1'); | |
| assertGetterDescriptor(B.prototype, '2'); | |
| assertSetterDescriptor(B.prototype, '3'); | |
| assertMethodDescriptor(B.prototype, '2147483649'); | |
| assertGetterDescriptor(B.prototype, '2147483650'); | |
| assertSetterDescriptor(B.prototype, '2147483651'); | |
| assertMethodDescriptor(B.prototype, '4294967294'); | |
| assertMethodDescriptor(B.prototype, '4294967295'); | |
| assertMethodDescriptor(B, '4'); | |
| assertGetterDescriptor(B, '5'); | |
| assertSetterDescriptor(B, '6'); | |
| assertMethodDescriptor(B, '2147483652'); | |
| assertGetterDescriptor(B, '2147483653'); | |
| assertSetterDescriptor(B, '2147483654'); | |
| assertMethodDescriptor(B, '4294967294'); | |
| assertMethodDescriptor(B, '4294967295'); | |
| class C extends B { | |
| 1() { return super[1](); } | |
| get 2() { return super[2]; } | |
| static 4() { return super[4](); } | |
| static get 5() { return super[5]; } | |
| 2147483649() { return super[2147483649](); } | |
| get 2147483650() { return super[2147483650]; } | |
| static 2147483652() { return super[2147483652](); } | |
| static get 2147483653() { return super[2147483653]; } | |
| } | |
| assertEquals(1, new C()[1]()); | |
| assertEquals(2, new C()[2]); | |
| assertEquals(2147483649, new C()[2147483649]()); | |
| assertEquals(2147483650, new C()[2147483650]); | |
| assertEquals(4, C[4]()); | |
| assertEquals(5, C[5]); | |
| assertEquals(2147483652, C[2147483652]()); | |
| assertEquals(2147483653, C[2147483653]); | |
| })(); | |
| (function TestDefaultConstructorNoCrash() { | |
| // Regression test for https://code.google.com/p/v8/issues/detail?id=3661 | |
| class C {} | |
| assertThrows(function () {C();}, TypeError); | |
| assertThrows(function () {C(1);}, TypeError); | |
| assertTrue(new C() instanceof C); | |
| assertTrue(new C(1) instanceof C); | |
| })(); | |
| (function TestConstructorCall(){ | |
| var realmIndex = Realm.create(); | |
| var otherTypeError = Realm.eval(realmIndex, "TypeError"); | |
| var A = Realm.eval(realmIndex, '"use strict"; class A {}; A'); | |
| var instance = new A(); | |
| var constructor = instance.constructor; | |
| var otherTypeError = Realm.eval(realmIndex, 'TypeError'); | |
| if (otherTypeError === TypeError) { | |
| throw Error('Should not happen!'); | |
| } | |
| // ES6 9.2.1[[Call]] throws a TypeError in the caller context/Realm when the | |
| // called function is a classConstructor | |
| assertThrows(function() { Realm.eval(realmIndex, "A()") }, otherTypeError); | |
| assertThrows(function() { instance.constructor() }, TypeError); | |
| assertThrows(function() { A() }, TypeError); | |
| // ES6 9.3.1 call() first activates the callee context before invoking the | |
| // method. The TypeError from the constructor is thus thrown in the other | |
| // Realm. | |
| assertThrows(function() { Realm.eval(realmIndex, "A.call()") }, | |
| otherTypeError); | |
| assertThrows(function() { constructor.call() }, otherTypeError); | |
| assertThrows(function() { A.call() }, otherTypeError); | |
| })(); | |
| (function TestConstructorCallOptimized() { | |
| class A { }; | |
| function invoke_constructor() { A() } | |
| function call_constructor() { A.call() } | |
| function apply_constructor() { A.apply() } | |
| for (var i=0; i<3; i++) { | |
| assertThrows(invoke_constructor); | |
| assertThrows(call_constructor); | |
| assertThrows(apply_constructor); | |
| } | |
| // Make sure we still check for class constructors when calling optimized | |
| // code. | |
| %OptimizeFunctionOnNextCall(invoke_constructor); | |
| assertThrows(invoke_constructor); | |
| %OptimizeFunctionOnNextCall(call_constructor); | |
| assertThrows(call_constructor); | |
| %OptimizeFunctionOnNextCall(apply_constructor); | |
| assertThrows(apply_constructor); | |
| })(); | |
| (function TestDefaultConstructor() { | |
| var calls = 0; | |
| class Base { | |
| constructor() { | |
| calls++; | |
| } | |
| } | |
| class Derived extends Base {} | |
| var object = new Derived; | |
| assertEquals(1, calls); | |
| calls = 0; | |
| assertThrows(function() { Derived(); }, TypeError); | |
| assertEquals(0, calls); | |
| })(); | |
| (function TestDefaultConstructorArguments() { | |
| var args, self; | |
| class Base { | |
| constructor() { | |
| self = this; | |
| args = arguments; | |
| } | |
| } | |
| class Derived extends Base {} | |
| new Derived; | |
| assertEquals(0, args.length); | |
| new Derived(0, 1, 2); | |
| assertEquals(3, args.length); | |
| assertTrue(self instanceof Derived); | |
| var arr = new Array(100); | |
| var obj = {}; | |
| assertThrows(function() {Derived.apply(obj, arr);}, TypeError); | |
| })(); | |
| (function TestDefaultConstructorArguments2() { | |
| var args; | |
| class Base { | |
| constructor(x, y) { | |
| args = arguments; | |
| } | |
| } | |
| class Derived extends Base {} | |
| new Derived; | |
| assertEquals(0, args.length); | |
| new Derived(1); | |
| assertEquals(1, args.length); | |
| assertEquals(1, args[0]); | |
| new Derived(1, 2, 3); | |
| assertEquals(3, args.length); | |
| assertEquals(1, args[0]); | |
| assertEquals(2, args[1]); | |
| assertEquals(3, args[2]); | |
| })(); | |
| (function TestNameBindingConst() { | |
| assertThrows('class C { constructor() { C = 42; } }; new C();', TypeError); | |
| assertThrows('new (class C { constructor() { C = 42; } })', TypeError); | |
| assertThrows('class C { m() { C = 42; } }; new C().m()', TypeError); | |
| assertThrows('new (class C { m() { C = 42; } }).m()', TypeError); | |
| assertThrows('class C { get x() { C = 42; } }; new C().x', TypeError); | |
| assertThrows('(new (class C { get x() { C = 42; } })).x', TypeError); | |
| assertThrows('class C { set x(_) { C = 42; } }; new C().x = 15;', TypeError); | |
| assertThrows('(new (class C { set x(_) { C = 42; } })).x = 15;', TypeError); | |
| })(); | |
| (function TestNameBinding() { | |
| var C2; | |
| class C { | |
| constructor() { | |
| C2 = C; | |
| } | |
| m() { | |
| C2 = C; | |
| } | |
| get x() { | |
| C2 = C; | |
| } | |
| set x(_) { | |
| C2 = C; | |
| } | |
| } | |
| new C(); | |
| assertEquals(C, C2); | |
| C2 = undefined; | |
| new C().m(); | |
| assertEquals(C, C2); | |
| C2 = undefined; | |
| new C().x; | |
| assertEquals(C, C2); | |
| C2 = undefined; | |
| new C().x = 1; | |
| assertEquals(C, C2); | |
| })(); | |
| (function TestNameBindingExpression() { | |
| var C3; | |
| var C = class C2 { | |
| constructor() { | |
| assertEquals(C2, C); | |
| C3 = C2; | |
| } | |
| m() { | |
| assertEquals(C2, C); | |
| C3 = C2; | |
| } | |
| get x() { | |
| assertEquals(C2, C); | |
| C3 = C2; | |
| } | |
| set x(_) { | |
| assertEquals(C2, C); | |
| C3 = C2; | |
| } | |
| } | |
| new C(); | |
| assertEquals(C, C3); | |
| C3 = undefined; | |
| new C().m(); | |
| assertEquals(C, C3); | |
| C3 = undefined; | |
| new C().x; | |
| assertEquals(C, C3); | |
| C3 = undefined; | |
| new C().x = 1; | |
| assertEquals(C, C3); | |
| })(); | |
| (function TestNameBindingInExtendsExpression() { | |
| assertThrows(function() { | |
| class x extends x {} | |
| }, ReferenceError); | |
| assertThrows(function() { | |
| (class x extends x {}); | |
| }, ReferenceError); | |
| assertThrows(function() { | |
| var x = (class x extends x {}); | |
| }, ReferenceError); | |
| })(); | |
| (function TestThisAccessRestriction() { | |
| class Base {} | |
| (function() { | |
| class C extends Base { | |
| constructor() { | |
| var y; | |
| super(); | |
| } | |
| }; new C(); | |
| }()); | |
| assertThrows(function() { | |
| class C extends Base { | |
| constructor() { | |
| super(this.x); | |
| } | |
| }; new C(); | |
| }, ReferenceError); | |
| assertThrows(function() { | |
| class C extends Base { | |
| constructor() { | |
| super(this); | |
| } | |
| }; new C(); | |
| }, ReferenceError); | |
| assertThrows(function() { | |
| class C extends Base { | |
| constructor() { | |
| super.method(); | |
| super(this); | |
| } | |
| }; new C(); | |
| }, ReferenceError); | |
| assertThrows(function() { | |
| class C extends Base { | |
| constructor() { | |
| super(super.method()); | |
| } | |
| }; new C(); | |
| }, ReferenceError); | |
| assertThrows(function() { | |
| class C extends Base { | |
| constructor() { | |
| super(super()); | |
| } | |
| }; new C(); | |
| }, ReferenceError); | |
| assertThrows(function() { | |
| class C extends Base { | |
| constructor() { | |
| super(1, 2, Object.getPrototypeOf(this)); | |
| } | |
| }; new C(); | |
| }, ReferenceError); | |
| (function() { | |
| class C extends Base { | |
| constructor() { | |
| { super(1, 2); } | |
| } | |
| }; new C(); | |
| }()); | |
| (function() { | |
| class C extends Base { | |
| constructor() { | |
| if (1) super(); | |
| } | |
| }; new C(); | |
| }()); | |
| class C1 extends Object { | |
| constructor() { | |
| 'use strict'; | |
| super(); | |
| } | |
| }; | |
| new C1(); | |
| class C2 extends Object { | |
| constructor() { | |
| ; 'use strict';;;;; | |
| super(); | |
| } | |
| }; | |
| new C2(); | |
| class C3 extends Object { | |
| constructor() { | |
| ; 'use strict';;;;; | |
| // This is a comment. | |
| super(); | |
| } | |
| }; | |
| new C3(); | |
| }()); | |
| function testClassRestrictedProperties(C) { | |
| assertEquals(false, C.hasOwnProperty("arguments")); | |
| assertThrows(function() { return C.arguments; }, TypeError); | |
| assertThrows(function() { C.arguments = {}; }, TypeError); | |
| assertEquals(false, C.hasOwnProperty("caller")); | |
| assertThrows(function() { return C.caller; }, TypeError); | |
| assertThrows(function() { C.caller = {}; }, TypeError); | |
| assertEquals(false, (new C).method.hasOwnProperty("arguments")); | |
| assertThrows(function() { return new C().method.arguments; }, TypeError); | |
| assertThrows(function() { new C().method.arguments = {}; }, TypeError); | |
| assertEquals(false, (new C).method.hasOwnProperty("caller")); | |
| assertThrows(function() { return new C().method.caller; }, TypeError); | |
| assertThrows(function() { new C().method.caller = {}; }, TypeError); | |
| } | |
| (function testRestrictedPropertiesStrict() { | |
| "use strict"; | |
| class ClassWithDefaultConstructor { | |
| method() {} | |
| } | |
| class Class { | |
| constructor() {} | |
| method() {} | |
| } | |
| class DerivedClassWithDefaultConstructor extends Class {} | |
| class DerivedClass extends Class { constructor() { super(); } } | |
| testClassRestrictedProperties(ClassWithDefaultConstructor); | |
| testClassRestrictedProperties(Class); | |
| testClassRestrictedProperties(DerivedClassWithDefaultConstructor); | |
| testClassRestrictedProperties(DerivedClass); | |
| testClassRestrictedProperties(class { method() {} }); | |
| testClassRestrictedProperties(class { constructor() {} method() {} }); | |
| testClassRestrictedProperties(class extends Class { }); | |
| testClassRestrictedProperties( | |
| class extends Class { constructor() { super(); } }); | |
| })(); | |
| (function testRestrictedPropertiesSloppy() { | |
| class ClassWithDefaultConstructor { | |
| method() {} | |
| } | |
| class Class { | |
| constructor() {} | |
| method() {} | |
| } | |
| class DerivedClassWithDefaultConstructor extends Class {} | |
| class DerivedClass extends Class { constructor() { super(); } } | |
| testClassRestrictedProperties(ClassWithDefaultConstructor); | |
| testClassRestrictedProperties(Class); | |
| testClassRestrictedProperties(DerivedClassWithDefaultConstructor); | |
| testClassRestrictedProperties(DerivedClass); | |
| testClassRestrictedProperties(class { method() {} }); | |
| testClassRestrictedProperties(class { constructor() {} method() {} }); | |
| testClassRestrictedProperties(class extends Class { }); | |
| testClassRestrictedProperties( | |
| class extends Class { constructor() { super(); } }); | |
| })(); | |
| (function testReturnFromClassLiteral() { | |
| function usingDoExpressionInBody() { | |
| let x = 42; | |
| let dummy = function() {x}; | |
| try { | |
| class C { | |
| dummy() {C} | |
| [do {return}]() {} | |
| }; | |
| } finally { | |
| return x; | |
| } | |
| } | |
| assertEquals(42, usingDoExpressionInBody()); | |
| function usingDoExpressionInExtends() { | |
| let x = 42; | |
| let dummy = function() {x}; | |
| try { | |
| class C extends (do {return}) { dummy() {C} }; | |
| } finally { | |
| return x; | |
| } | |
| } | |
| assertEquals(42, usingDoExpressionInExtends()); | |
| function usingYieldInBody() { | |
| function* foo() { | |
| class C { | |
| [yield]() {} | |
| } | |
| } | |
| var g = foo(); | |
| g.next(); | |
| return g.return(42).value; | |
| } | |
| assertEquals(42, usingYieldInBody()); | |
| function usingYieldInExtends() { | |
| function* foo() { | |
| class C extends (yield) {}; | |
| } | |
| var g = foo(); | |
| g.next(); | |
| return g.return(42).value; | |
| } | |
| assertEquals(42, usingYieldInExtends()); | |
| })(); | |
| (function testLargeClassesMethods() { | |
| const kLimit = 2000; | |
| let evalString = "(function(i) { " + | |
| "let clazz = class { " + | |
| " constructor(i) { this.value = i; } "; | |
| for (let i = 0; i < 2000; i++) { | |
| evalString += "property"+i+"() { return "+i+"; }; " | |
| } | |
| evalString += "};" + | |
| " return new clazz(i); })"; | |
| let fn = eval(evalString); | |
| assertEquals(fn(1).value, 1); | |
| assertEquals(fn(2).value, 2); | |
| assertEquals(fn(3).value, 3); | |
| %OptimizeFunctionOnNextCall(fn); | |
| assertEquals(fn(4).value, 4); | |
| let instance = fn(1); | |
| assertEquals(Object.getOwnPropertyNames(instance).length, 1); | |
| assertEquals(Object.getOwnPropertyNames(instance.__proto__).length, | |
| kLimit + 1); | |
| // Call all instance functions. | |
| for (let i = 0; i < kLimit; i++) { | |
| const key = "property" + i; | |
| assertEquals(instance[key](), i); | |
| } | |
| })(); | |
| (function testLargeClassesStaticMethods() { | |
| const kLimit = 2000; | |
| let evalString = "(function(i) { " + | |
| "let clazz = class { " + | |
| " constructor(i) { this.value = i; } "; | |
| for (let i = 0; i < kLimit; i++) { | |
| evalString += "static property"+i+"() { return "+i+" }; " | |
| } | |
| evalString += "};" + | |
| " return new clazz(i); })"; | |
| let fn = eval(evalString); | |
| assertEquals(fn(1).value, 1); | |
| assertEquals(fn(2).value, 2); | |
| assertEquals(fn(3).value, 3); | |
| %OptimizeFunctionOnNextCall(fn); | |
| assertEquals(fn(4).value, 4); | |
| let instance = fn(1); | |
| assertEquals(Object.getOwnPropertyNames(instance).length, 1); | |
| assertEquals(instance.value, 1); | |
| instance.value = 10; | |
| assertEquals(instance.value, 10); | |
| // kLimit + nof default properties (length, prototype, name). | |
| assertEquals(Object.getOwnPropertyNames(instance.constructor).length, | |
| kLimit + 3); | |
| // Call all static properties. | |
| for (let i = 0; i < kLimit; i++) { | |
| const key = "property" + i; | |
| assertEquals(instance.constructor[key](), i); | |
| } | |
| })(); | |
| (function testLargeClassesProperties(){ | |
| const kLimit = 2000; | |
| let evalString = "(function(i) { " + | |
| "let clazz = class { " + | |
| " constructor(i) { this.value = i;"; | |
| for (let i = 0; i < kLimit ; i++) { | |
| evalString += "this.property"+i +" = "+i+"; " | |
| } | |
| evalString += "}};" + | |
| " return (new clazz(i)); })"; | |
| let fn = eval(evalString); | |
| assertEquals(fn(1).value, 1); | |
| assertEquals(fn(2).value, 2); | |
| assertEquals(fn(3).value, 3); | |
| %OptimizeFunctionOnNextCall(fn); | |
| assertEquals(fn(4).value, 4); | |
| let instance = fn(1); | |
| assertEquals(Object.getOwnPropertyNames(instance).length, kLimit+1); | |
| // Get and set all properties. | |
| for (let i = 0; i < kLimit; i++) { | |
| const key = "property" + i; | |
| assertEquals(instance[key], i); | |
| const value = "value"+i; | |
| instance[key] = value; | |
| assertEquals(instance[key], value); | |
| } | |
| })(); |