v8/test/mjsunit/harmony/class-static-blocks.js
Shu-yu Guo 8804443f47 [class] Disallow return in class static blocks
Bug: v8:11719
Change-Id: Ib9064e09a77b03adc1234e2f1739983cdab24113
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2898778
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74619}
2021-05-18 06:19:07 +00:00

158 lines
3.9 KiB
JavaScript

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