// 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); }