6ac4de87a8
Per TC39 Nov 2014 decision. This patch also changes behavior for "legacy const": assignments to sloppy const in strict mode is now also a type error. This fixes v8:2243 and also brings us in compliance with other engines re assignment to function names (see updated webkit test), but might have bigger implications. That change can easily be reverted by changing Variable::IsSignallingAssignmentToConst. BUG=v8:3713,v8:2243 LOG=N Review URL: https://codereview.chromium.org/749633002 Cr-Commit-Position: refs/heads/master@{#25516}
780 lines
16 KiB
JavaScript
780 lines
16 KiB
JavaScript
// 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: --harmony-classes --harmony-sloppy
|
|
|
|
(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);
|
|
|
|
// TODO(arv): The logic for the name of anonymous functions in ES6 requires
|
|
// the below to be 'E';
|
|
var E = class {}
|
|
assertEquals('', E.name); // Should be 'E'.
|
|
|
|
var F = class { constructor() {} };
|
|
assertEquals('', 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;
|
|
})();
|
|
|
|
|
|
(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() {
|
|
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() {
|
|
arguments.caller;
|
|
} {};
|
|
assertThrows(function() {
|
|
Object.getPrototypeOf(D).arguments;
|
|
}, TypeError);
|
|
assertThrows(function() {
|
|
new D;
|
|
}, TypeError);
|
|
})();
|
|
|
|
|
|
(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);
|
|
assertTrue(descr.enumerable);
|
|
assertTrue(descr.writable);
|
|
assertEquals('function', typeof descr.value);
|
|
assertFalse('prototype' in descr.value);
|
|
}
|
|
|
|
|
|
function assertGetterDescriptor(object, name) {
|
|
var descr = Object.getOwnPropertyDescriptor(object, name);
|
|
assertTrue(descr.configurable);
|
|
assertTrue(descr.enumerable);
|
|
assertEquals('function', typeof descr.get);
|
|
assertEquals(undefined, descr.set);
|
|
}
|
|
|
|
|
|
function assertSetterDescriptor(object, name) {
|
|
var descr = Object.getOwnPropertyDescriptor(object, name);
|
|
assertTrue(descr.configurable);
|
|
assertTrue(descr.enumerable);
|
|
assertEquals(undefined, descr.get);
|
|
assertEquals('function', typeof descr.set);
|
|
}
|
|
|
|
|
|
function assertAccessorDescriptor(object, name) {
|
|
var descr = Object.getOwnPropertyDescriptor(object, name);
|
|
assertTrue(descr.configurable);
|
|
assertTrue(descr.enumerable);
|
|
assertEquals('function', typeof descr.get);
|
|
assertEquals('function', typeof descr.set);
|
|
}
|
|
|
|
|
|
(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(_) {}
|
|
}
|
|
|
|
assertMethodDescriptor(B.prototype, '1');
|
|
assertGetterDescriptor(B.prototype, '2');
|
|
assertSetterDescriptor(B.prototype, '3');
|
|
|
|
assertMethodDescriptor(B, '4');
|
|
assertGetterDescriptor(B, '5');
|
|
assertSetterDescriptor(B, '6');
|
|
|
|
class C extends B {
|
|
1() { return super[1](); }
|
|
get 2() { return super[2]; }
|
|
|
|
static 4() { return super[4](); }
|
|
static get 5() { return super[5]; }
|
|
}
|
|
|
|
assertEquals(1, new C()[1]());
|
|
assertEquals(2, new C()[2]);
|
|
assertEquals(4, C[4]());
|
|
assertEquals(5, C[5]);
|
|
})();
|
|
|
|
|
|
(function TestDefaultConstructorNoCrash() {
|
|
// Regression test for https://code.google.com/p/v8/issues/detail?id=3661
|
|
class C {}
|
|
assertEquals(undefined, C());
|
|
assertEquals(undefined, C(1));
|
|
assertTrue(new C() instanceof C);
|
|
assertTrue(new C(1) instanceof C);
|
|
})();
|
|
|
|
|
|
(function TestDefaultConstructor() {
|
|
var calls = 0;
|
|
class Base {
|
|
constructor() {
|
|
calls++;
|
|
}
|
|
}
|
|
class Derived extends Base {}
|
|
var object = new Derived;
|
|
assertEquals(1, calls);
|
|
|
|
calls = 0;
|
|
Derived();
|
|
assertEquals(1, 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 = {};
|
|
Derived.apply(obj, arr);
|
|
assertEquals(100, args.length);
|
|
assertEquals(obj, self);
|
|
})();
|
|
|
|
|
|
(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);
|
|
})();
|