blob: 74e5c8a7650165590e0d092db3e3e31636dceef6 [file] [log] [blame]
//@ defaultNoEagerRun
// 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.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"use strict";
load("./resources/harmony-support.js");
{
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(name) === 'symbol') {
assertFalse($vm.isPrivateSymbol(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);
}
// Additional tests by the WebKit project.
function shouldThrowSyntaxError(script) {
let error;
try {
eval(script);
} catch (e) {
error = e;
}
if (!(error instanceof SyntaxError))
throw new Error('Expected SyntaxError!');
}
shouldThrowSyntaxError("class C { #foo = 0; static #foo = 1; }");
shouldThrowSyntaxError("class C { static #foo = 0; #foo = 1; }");
{
class C {
static #foo = 0;
testAccess(X) { return X.#foo; }
}
class D {
static #foo = 0;
}
let c = new C();
assertDoesNotThrow(c.testAccess(C));
assertThrows(() => c.testAccess(D), TypeError);
}