|  | // Copyright 2018 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: --allow-natives-syntax | 
|  |  | 
|  |  | 
|  | "use strict"; | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a; | 
|  | static getA() { return this.#a; } | 
|  | } | 
|  |  | 
|  | assertEquals(undefined, C.a); | 
|  | assertEquals(undefined, C.getA()); | 
|  |  | 
|  | let c = new C; | 
|  | assertEquals(undefined, c.a); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a; } | 
|  | } | 
|  |  | 
|  | assertEquals(undefined, C.a); | 
|  | assertEquals(1, C.getA()); | 
|  |  | 
|  | let c = new C; | 
|  | assertEquals(undefined, c.a); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = 1; | 
|  | static #b = this.#a; | 
|  | static getB() { return this.#b; } | 
|  | } | 
|  |  | 
|  | assertEquals(1, C.getB()); | 
|  |  | 
|  | let c = new C; | 
|  | assertEquals(undefined, c.getB); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a; } | 
|  | constructor() { | 
|  | assertThrows(() => this.#a, TypeError); | 
|  | C.#a = 2; | 
|  | } | 
|  | } | 
|  |  | 
|  | assertEquals(1, C.getA()); | 
|  |  | 
|  | let c = new C; | 
|  | assertThrows(() => C.prototype.getA.call(c)); | 
|  | assertEquals(2, C.getA()); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = this; | 
|  | static #b = () => this; | 
|  | static getA() { return this.#a; } | 
|  | static getB() { return this.#b; } | 
|  | } | 
|  |  | 
|  | assertSame(C, C.getA()); | 
|  | assertSame(C, C.getB()()); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = this; | 
|  | static #b = function() { return this; }; | 
|  | static getA() { return this.#a; } | 
|  | static getB() { return this.#b; } | 
|  | } | 
|  |  | 
|  | assertSame(C, C.getA()); | 
|  | assertSame(C, C.getB().call(C)); | 
|  | assertSame(undefined, C.getB()()); | 
|  | } | 
|  |  | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = function() { return 1 }; | 
|  | static getA() {return this.#a;} | 
|  | } | 
|  |  | 
|  | assertEquals('#a', C.getA().name); | 
|  | } | 
|  |  | 
|  | { | 
|  | let d = function() { return new.target; } | 
|  | class C { | 
|  | static #c = d; | 
|  | static getC() { return this.#c; } | 
|  | } | 
|  |  | 
|  | assertEquals(undefined, C.getC()()); | 
|  | assertSame(new d, new (C.getC())); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = 1; | 
|  | static getA(instance) { return instance.#a; } | 
|  | } | 
|  |  | 
|  | class B { } | 
|  |  | 
|  | assertEquals(undefined, C.a); | 
|  | assertEquals(1, C.getA(C)); | 
|  | assertThrows(() => C.getA(B), TypeError); | 
|  | } | 
|  |  | 
|  | { | 
|  | class A { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a; } | 
|  | } | 
|  |  | 
|  | class B extends A {} | 
|  | assertThrows(() => B.getA(), TypeError); | 
|  | } | 
|  |  | 
|  | { | 
|  | class A { | 
|  | static #a = 1; | 
|  | static getA() { return A.#a; } | 
|  | } | 
|  |  | 
|  | class B extends A {} | 
|  | assertSame(1, B.getA()); | 
|  | } | 
|  |  | 
|  | { | 
|  | let prototypeLookup = false; | 
|  | class A { | 
|  | static set a(val) { | 
|  | prototypeLookup = true; | 
|  | } | 
|  |  | 
|  | static get a() { return undefined; } | 
|  | } | 
|  |  | 
|  | class C extends A { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a; } | 
|  | } | 
|  |  | 
|  | assertEquals(1, C.getA()); | 
|  | assertEquals(false, prototypeLookup); | 
|  | } | 
|  |  | 
|  | { | 
|  | class A { | 
|  | static a = 1; | 
|  | } | 
|  |  | 
|  | class B extends A { | 
|  | static #b = this.a; | 
|  | static getB() { return this.#b; } | 
|  | } | 
|  |  | 
|  | assertEquals(1, B.getB()); | 
|  | } | 
|  |  | 
|  | { | 
|  | class A { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a; } | 
|  | } | 
|  |  | 
|  | class B extends A { | 
|  | static getA() { return super.getA(); } | 
|  | } | 
|  |  | 
|  | assertThrows(() => B.getA(), TypeError); | 
|  | } | 
|  |  | 
|  | { | 
|  | class A { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a;} | 
|  | } | 
|  |  | 
|  | class B extends A { | 
|  | static #a = 2; | 
|  | static get_A() { return this.#a;} | 
|  | } | 
|  |  | 
|  | assertEquals(1, A.getA()); | 
|  | assertThrows(() => B.getA(), TypeError); | 
|  | assertEquals(2, B.get_A()); | 
|  | } | 
|  |  | 
|  | { | 
|  | let foo = undefined; | 
|  | class A { | 
|  | static #a = (function() { foo = 1; })(); | 
|  | } | 
|  |  | 
|  | assertEquals(1, foo); | 
|  | } | 
|  |  | 
|  | { | 
|  | let foo = undefined; | 
|  | class A extends class {} { | 
|  | static #a = (function() { foo = 1; })(); | 
|  | } | 
|  |  | 
|  | assertEquals(1, foo); | 
|  | } | 
|  |  | 
|  | { | 
|  | function makeClass() { | 
|  | return class { | 
|  | static #a; | 
|  | static setA(val) { this.#a = val; } | 
|  | static getA() { return this.#a; } | 
|  | } | 
|  | } | 
|  |  | 
|  | let classA = makeClass(); | 
|  | let classB = makeClass(); | 
|  |  | 
|  | assertEquals(undefined, classA.getA()); | 
|  | assertEquals(undefined, classB.getA()); | 
|  |  | 
|  | classA.setA(3); | 
|  | assertEquals(3, classA.getA()); | 
|  | assertEquals(undefined, classB.getA()); | 
|  |  | 
|  | classB.setA(5); | 
|  | assertEquals(3, classA.getA()); | 
|  | assertEquals(5, classB.getA()); | 
|  |  | 
|  | assertThrows(() => classA.getA.call(classB), TypeError); | 
|  | assertThrows(() => classB.getA.call(classA), TypeError); | 
|  | } | 
|  |  | 
|  | { | 
|  | let value = undefined; | 
|  |  | 
|  | new class { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a; } | 
|  |  | 
|  | constructor() { | 
|  | new class C { | 
|  | static #a = 2; | 
|  | constructor() { | 
|  | value = C.#a; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | assertEquals(2, value); | 
|  | } | 
|  |  | 
|  | { | 
|  | class A { | 
|  | static #a = 1; | 
|  | static b = class { | 
|  | static getA() { return this.#a; } | 
|  | static get_A(val) { return val.#a; } | 
|  | } | 
|  | } | 
|  |  | 
|  | assertEquals(1, A.b.getA.call(A)); | 
|  | assertEquals(1, A.b.get_A(A)); | 
|  | } | 
|  |  | 
|  | { | 
|  | assertThrows(() => class { static b = this.#a; static #a = 1 }, TypeError); | 
|  | } | 
|  |  | 
|  | { | 
|  | let symbol = Symbol(); | 
|  |  | 
|  | class C { | 
|  | static #a = 1; | 
|  | static [symbol] = 1; | 
|  | static getA() { return this.#a; } | 
|  | static setA(val) { this.#a = val; } | 
|  | } | 
|  |  | 
|  | var p = new Proxy(C, { | 
|  | get: function(target, name) { | 
|  | if (typeof(arg) === 'symbol') { | 
|  | assertFalse(%SymbolIsPrivate(name)); | 
|  | } | 
|  | return target[name]; | 
|  | } | 
|  | }); | 
|  |  | 
|  | assertThrows(() => p.getA(), TypeError); | 
|  | assertThrows(() => p.setA(1), TypeError); | 
|  | assertEquals(1, p[symbol]); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #b = Object.freeze(this); | 
|  | static getA() { return this.#a; } | 
|  | static #a = 1; | 
|  | } | 
|  |  | 
|  | assertEquals(1, C.getA()); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = 1; | 
|  | static getA() { return eval('this.#a'); } | 
|  | } | 
|  |  | 
|  | assertEquals(1, C.getA()); | 
|  | } | 
|  |  | 
|  | { | 
|  | var C; | 
|  | eval('C = class { static #a = 1; static getA() { return eval(\'this.#a\'); }}'); | 
|  |  | 
|  | assertEquals(1, C.getA()); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static #a = 1; | 
|  | static getA() { return this.#a; } | 
|  | static setA() { eval('this.#a = 4'); } | 
|  | } | 
|  |  | 
|  | assertEquals(1, C.getA()); | 
|  | C.setA(); | 
|  | assertEquals(4, C.getA()); | 
|  | } | 
|  |  | 
|  | { | 
|  | class C { | 
|  | static getA() { return eval('this.#a'); } | 
|  | } | 
|  |  | 
|  | assertThrows(() => C.getA(), SyntaxError); | 
|  | } |