// Copyright 2021 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: --harmony-class-static-blocks { // Basic functionality let log = []; class C { static { log.push("block1"); } static { log.push("block2"); } } assertArrayEquals(["block1", "block2"], log); } { // Static blocks run in textual order interleaved with field initializers. let log = []; class C { static { log.push("block1"); } static public_static_method() {} static public_field = log.push("public_field"); static { log.push("block2"); } static #private_field = log.push("private_field"); static { log.push("block3"); } } assertArrayEquals(["block1", "public_field", "block2", "private_field", "block3"], log); } { // Static blocks have access to private fields. let exfil; class C { #foo; constructor(x) { this.#foo = x; } static { exfil = function(o) { return o.#foo; }; } } assertEquals(exfil(new C(42)), 42); } { // 'this' is the constructor. let log = []; class C { static x = 42; static { log.push(this.x); } } assertArrayEquals([42], log); } { // super.property accesses work as expected. let log = []; class B { static foo = 42; static get field_getter() { return "field_getter"; } static set field_setter(x) { log.push(x); }; static method() { return "bar"; } } class C extends B { static { log.push(super.foo); log.push(super.field_getter); super.field_setter = "C"; log.push(super.method()); } } assertArrayEquals([42, "field_getter", "C", "bar"], log); } { // Each static block is its own var and let scope. let log = []; let f; class C { static { var x = "x1"; let y = "y1"; log.push(x); log.push(y); } static { var x = "x2"; let y = "y2"; f = () => [x, y]; } static { assertThrows(() => x, ReferenceError); assertThrows(() => y, ReferenceError); } } assertArrayEquals(["x1", "y1"], log); assertArrayEquals(["x2", "y2"], f()); } { // new.target is undefined. let log = []; class C { static { log.push(new.target); } } assertArrayEquals([undefined], log); } { // 'await' is allowed as an identifier name in named function expressions. class C1 { static { (function await() {}); } } // 'return' is allowed across function boundaries inside static blocks. class C2 { static { function f1() { return; } function f2() { return 0; } let f3 = (x => { return x; }) let f4 = (x => { return; }) } } } function assertDoesntParse(expr, context_start, context_end) { assertThrows(() => { eval(`${context_start} class C { static { ${expr} } } ${context_end}`); }, SyntaxError); } for (let [s, e] of [['', ''], ['function* g() {', '}'], ['async function af() {', '}'], ['async function* ag() {', '}']]) { assertDoesntParse('arguments;', s, e); assertDoesntParse('arguments[0] = 42;', s, e); assertDoesntParse('super();', s, e); assertDoesntParse('yield 42;', s, e); assertDoesntParse('await 42;', s, e); // 'await' is disallowed as an identifier. assertDoesntParse('let await;', s, e); assertDoesntParse('await;', s, e); assertDoesntParse('function await() {}', s, e); assertDoesntParse('class await() {}', s, e); assertDoesntParse('try {} catch (await) {}', s, e); assertDoesntParse('try {} catch ({await}) {}', s, e); assertDoesntParse('var {await} = 0;', s, e); assertDoesntParse('({await} = 0);', s, e); assertDoesntParse('return;', s, e); assertDoesntParse('return 0;', s, e); assertDoesntParse('{ return; }', s, e); assertDoesntParse('{ return 0; }', s, e); }