Source code

Revision control

Copy as Markdown

Other Tools

class A {
#x = 10
x() {
return this.#x;
}
ix() {
this.#x++;
}
static readx(o) {
return o.#x;
}
static optionalx(o) {
return o?.#x;
}
static orEqual(o, v) {
o.#x ||= v;
return o.#x;
}
setX(v) {
this.#x = v;
}
compoundInc() {
this.#x += 1;
return this.#x;
}
compoundDec() {
this.#x -= 1;
return this.#x;
}
#y = () => 'hi';
invoke() {
return this.#y();
}
static #z = 'static';
gz() {
return A.#z;
}
sz(o) {
A.#z = o;
}
static sgz() {
return this.#z;
}
static ssz(o) {
this.#z = o;
}
static six(o) {
o.#x++;
}
static dix(o) {
o.#x--;
}
};
for (var i = 0; i < 1000; i++) {
var a = new A();
assertEq(a.x(), 10);
a.ix();
assertEq(a.x(), 11);
assertEq(A.readx(a), 11);
assertEq(a.compoundInc(), 12);
assertEq(A.orEqual(a, 13), 12);
a.setX(null);
assertEq(A.orEqual(a, 12), 12);
assertEq(a.compoundDec(), 11);
assertEq(a.invoke(), 'hi');
assertEq(a.gz(), 'static');
assertEq(A.sgz(), 'static');
A.ssz(i);
assertEq(A.sgz(), i);
a.sz(i + 1);
assertEq(A.sgz(), i + 1);
A.ssz('static'); // reset for next iteration!
assertEq(A.optionalx(a), 11);
assertEq(A.optionalx(null), undefined);
try {
A.optionalx({}); // Should throw type error
assertEq(0, 1);
} catch (TypeError) {
}
}
function assertThrows(fun, errorType) {
try {
fun();
throw 'Expected error, but none was thrown';
} catch (e) {
if (!(e instanceof errorType)) {
throw 'Wrong error type thrown';
}
}
}
function testTypeErrors(v) {
assertThrows(() => A.readx(v), TypeError); // Read value
assertThrows(() => A.six(v), TypeError); // increment
assertThrows(() => A.dix(v), TypeError); // decrement
}
testTypeErrors(undefined); // Undefined
testTypeErrors({}); // Random object
testTypeErrors(1); // Random primitive
assertThrows(
() => eval('class B extends class { #x; } { g() { return super.#x; } }'),
SyntaxError); // Access super.#private
assertThrows(
() => eval('class C { #x = 10; static #x = 14; }'),
SyntaxError); // Duplicate name declaration.
assertThrows(
() => eval('delete this.#x'),
SyntaxError); // deleting a private field in non-strict mode.
class B extends class {
constructor(o) {
return o;
}
}
{
#x = 12;
static gx(o) {
return o.#x;
}
static sx(o) {
o.#x++;
}
}
var bn = new B(1);
var bu = new B(undefined);
// Test we can read an outer classes private fields.
class Outer {
#outer = 3;
test() {
let outerThis = this;
class Inner {
#inner = 2;
test() {
return outerThis.#outer;
}
}
return new Inner().test();
}
}
var o = new Outer;
assertEq(o.test(), 3);
// IC tests:
var alreadyConstructedB = new B();
assertEq(B.gx(alreadyConstructedB), 12);
function initIC(o) {
new B(o);
}
var array = [];
// warm up init IC
for (var i = 1; i < 1000; i++) {
var newB = {};
initIC(newB);
}
// Successfully catch double initialization type error.
assertThrows(() => initIC(alreadyConstructedB), TypeError);
// Do it again, to make sure we didn't attach a stub that is invalid.
assertThrows(() => initIC(alreadyConstructedB), TypeError);
// Test getters work, and ICs can't be tricked. Setup an array of
//
// [B, B, B, B, ..., {}, {}]
//
// Then test that as we execute the sudden appearance of {} doesn't
// trick our ICs into setting or getting anything -- do it twice
// to make sure that we didn't get a stub that is invalid.
var elements = [];
for (var i = 0; i < 99; i++) {
elements.push(new B);
}
elements.push({});
elements.push({});
function getterCheck(e) {
assertEq(B.gx(e), 12);
}
function setterCheck(e) {
B.sx(e);
}
var checksPassed = 0;
try {
for (var e of elements) {
getterCheck(e);
checksPassed++;
}
throw `Shouldn't arrive here`;
} catch (e) {
if (!(e instanceof TypeError)) {
throw e;
}
// All but last element should have done the right thing.
assertEq(checksPassed, elements.length - 2);
}
checksPassed = 0;
try {
for (var e of elements) {
setterCheck(e);
checksPassed++;
}
throw `Shouldn't arrive here`;
} catch (e) {
if (!(e instanceof TypeError)) {
throw e;
}
// All but last element should have done the right thing.
assertEq(checksPassed, elements.length - 2);
}
// Verify setter did the thing, but throws in the correct places
for (var index in elements) {
if (index < elements.length - 2) {
assertEq(B.gx(elements[index]), 13);
} else {
assertThrows(() => {
B.gx(elements[index]);
}, TypeError);
}
}
// Megamorphic Cache Testing:
for (var i = 0; i < 100; i++) {
var inputs = [{ a: 1 }, { b: 2 }, { c: 3 }, { d: 4 }, { e: 5 }, new Proxy({}, {})];
for (var o of inputs) {
assertThrows(() => B.gx(o), TypeError);
assertThrows(() => B.sx(o), TypeError);
new B(o);
assertEq(B.gx(o), 12);
B.sx(o);
assertEq(B.gx(o), 13);
}
}