blob: e6060cf81a62c7d6b7f098845a408ef39674793f [file] [log] [blame]
// 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);
}