138 lines
3.5 KiB
JavaScript
138 lines
3.5 KiB
JavaScript
|
// Copyright 2019 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.
|
||
|
|
||
|
{
|
||
|
let heritageFn;
|
||
|
class O {
|
||
|
#f = "O.#f";
|
||
|
static C = class C extends (heritageFn = function () {
|
||
|
return class D {
|
||
|
exfil(obj) { return obj.#f; }
|
||
|
exfilEval(obj) { return eval("obj.#f"); }
|
||
|
};
|
||
|
}) {
|
||
|
#f = "C.#f";
|
||
|
};
|
||
|
}
|
||
|
|
||
|
const o = new O;
|
||
|
const c = new O.C;
|
||
|
const D = heritageFn();
|
||
|
const d = new D;
|
||
|
assertEquals(d.exfil(o), "O.#f");
|
||
|
assertEquals(d.exfilEval(o), "O.#f");
|
||
|
assertThrows(() => d.exfil(c), TypeError);
|
||
|
assertThrows(() => d.exfilEval(c), TypeError);
|
||
|
}
|
||
|
|
||
|
// Early errors
|
||
|
|
||
|
assertThrows(() => eval("new class extends " +
|
||
|
"(class { m() { let x = this.#f; } }) " +
|
||
|
"{ #f }"), SyntaxError);
|
||
|
|
||
|
assertThrows(() => eval("new class extends this.#foo { #foo }"), SyntaxError);
|
||
|
|
||
|
// Runtime errors
|
||
|
|
||
|
{
|
||
|
// Test private name context chain recalc.
|
||
|
let heritageFn;
|
||
|
class O {
|
||
|
#f = "O.#f";
|
||
|
static C = class C extends (heritageFn = function () {
|
||
|
return class D { exfil(obj) { return obj.#f; } }
|
||
|
}) {
|
||
|
#f = "C.#f";
|
||
|
};
|
||
|
}
|
||
|
|
||
|
const o = new O;
|
||
|
const c = new O.C;
|
||
|
const D = heritageFn();
|
||
|
const d = new D;
|
||
|
assertEquals(d.exfil(o), "O.#f");
|
||
|
assertThrows(() => d.exfil(c), TypeError);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// Test private name context chain recalc with nested closures with context.
|
||
|
let heritageFn;
|
||
|
class O {
|
||
|
#f = "O.#f";
|
||
|
static C = class C extends (heritageFn = function () {
|
||
|
let forceContext = 1;
|
||
|
return () => {
|
||
|
assertEquals(forceContext, 1);
|
||
|
return class D { exfil(obj) { return obj.#f; } }
|
||
|
};
|
||
|
}) {
|
||
|
#f = "C.#f";
|
||
|
};
|
||
|
}
|
||
|
|
||
|
const o = new O;
|
||
|
const c = new O.C;
|
||
|
const D = heritageFn()();
|
||
|
const d = new D;
|
||
|
assertEquals(d.exfil(o), "O.#f");
|
||
|
assertThrows(() => d.exfil(c), TypeError);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// Test private name context chain recalc where skipped class has no context.
|
||
|
let heritageFn;
|
||
|
class O {
|
||
|
#f = "O.#f";
|
||
|
static C = class C0 extends (class C1 extends (heritageFn = function (obj) {
|
||
|
if (obj) { return obj.#f; }
|
||
|
}) {}) {
|
||
|
#f = "C0.#f"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const o = new O;
|
||
|
const c = new O.C;
|
||
|
assertEquals(heritageFn(o), "O.#f");
|
||
|
assertThrows(() => heritageFn(c), TypeError);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// Test private name context chain recalc where skipping function has no
|
||
|
// context.
|
||
|
let heritageFn;
|
||
|
class O {
|
||
|
#f = "O.#f";
|
||
|
static C = class C extends (heritageFn = function () {
|
||
|
return (obj) => { return obj.#f; }
|
||
|
}) {
|
||
|
#f = "C.#f";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const o = new O;
|
||
|
const c = new O.C;
|
||
|
assertEquals(heritageFn()(o), "O.#f");
|
||
|
assertThrows(() => heritageFn()(c), TypeError);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// Test private name context chain recalc where neither skipped class nor
|
||
|
// skipping function has contexts.
|
||
|
let heritageFn;
|
||
|
class O {
|
||
|
#f = "O.#f";
|
||
|
static C = class C0 extends (class C1 extends (heritageFn = function () {
|
||
|
return (obj) => { return obj.#f; }
|
||
|
}) {}) {
|
||
|
#f = "C0.#f";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const o = new O;
|
||
|
const c = new O.C;
|
||
|
assertEquals(heritageFn()(o), "O.#f");
|
||
|
assertThrows(() => heritageFn()(c), TypeError);
|
||
|
}
|