mirror of https://github.com/tc39/test262.git
[decorators] Support public auto-accessors
Add support for the accessor keywords for public class fields as part of the decorators proposal. Changes to the parser: - Minor cleanup of reused code. - Support declaration of public auto-accessors. Changes to the bytecode generator: - Add logic to create the accessor storage private name for public members. - Add the generated getter and setter to the arguments list passed to Runtime::kDefineClass Changes to class boilerplate: - Add logic to add a template AccessorPair to the descriptors lists for each auto accessor property. The template AccessorPair object is initialized with consecutive indices corresponding to the positions in the Runtime::kDefineClass arguments. Add tests. Bug: 42202709 Change-Id: I2253eddb734e950d8faf83fff1763e32b7f53a73 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5745256 Reviewed-by: Shu-yu Guo <syg@chromium.org> Reviewed-by: Seth Brenith <seth.brenith@microsoft.com> Commit-Queue: Luis Pardo <lpardosixtos@microsoft.com> Cr-Commit-Position: refs/heads/main@{#95784}
This commit is contained in:
parent
b70b75793d
commit
2e1843d0a5
|
@ -0,0 +1,509 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
/*---
|
||||
description: Test public auto-accessors.
|
||||
features: [decorators]
|
||||
---*/
|
||||
|
||||
(function TestPublicAutoAccessor() {
|
||||
let name = 'x3';
|
||||
let symbol = Symbol();
|
||||
class C {
|
||||
accessor x0;
|
||||
accessor x1 = 1;
|
||||
accessor 'x2' = 2;
|
||||
accessor [name] = 3;
|
||||
accessor [symbol] = 4;
|
||||
accessor 1 = 5;
|
||||
}
|
||||
let c = new C();
|
||||
assert.sameValue(c.x0, undefined);
|
||||
assert.sameValue(c.x1, 1);
|
||||
assert.sameValue(c.x2, 2);
|
||||
assert.sameValue(c.x3, 3);
|
||||
assert.sameValue(c[symbol], 4);
|
||||
assert.sameValue(c[1], 5);
|
||||
c.x0 = 42;
|
||||
c.x1 = 43;
|
||||
c.x2 = 44;
|
||||
c.x3 = 45;
|
||||
c[symbol] = 46;
|
||||
c[1] = 47;
|
||||
assert.sameValue(c.x0, 42);
|
||||
assert.sameValue(c.x1, 43);
|
||||
assert.sameValue(c.x2, 44);
|
||||
assert.sameValue(c.x3, 45);
|
||||
assert.sameValue(c[symbol], 46);
|
||||
assert.sameValue(c[1], 47);
|
||||
})();
|
||||
|
||||
(function TestRedeclaredPublicAutoaccessor() {
|
||||
let name = 'y';
|
||||
let symbol = Symbol();
|
||||
class C {
|
||||
accessor x = 0;
|
||||
accessor x = 1;
|
||||
accessor y = 2;
|
||||
accessor [name] = 3;
|
||||
accessor [symbol] = 4;
|
||||
accessor [symbol] = 5;
|
||||
accessor 1 = 6;
|
||||
accessor 1 = 7;
|
||||
}
|
||||
let c = new C();
|
||||
// Latest values should override previous ones.
|
||||
assert.sameValue(c.x, 1);
|
||||
assert.sameValue(c.y, 3);
|
||||
assert.sameValue(c[symbol], 5);
|
||||
})();
|
||||
|
||||
(function TestDerivedPublicAutoAccessor() {
|
||||
let name = 'x3';
|
||||
let symbol = Symbol();
|
||||
let name2 = 'y3';
|
||||
let symbol2 = Symbol();
|
||||
class C {
|
||||
accessor x0;
|
||||
accessor x1 = 1;
|
||||
accessor 'x2' = 2;
|
||||
accessor [name] = 3;
|
||||
accessor [symbol] = 4;
|
||||
accessor 1 = 5;
|
||||
|
||||
accessor y0 = 7;
|
||||
accessor y1 = 8;
|
||||
accessor 'y2' = 9;
|
||||
accessor [name2] = 10;
|
||||
accessor [symbol2] = 11;
|
||||
accessor 2 = 12;
|
||||
}
|
||||
class D extends C {
|
||||
accessor y0;
|
||||
accessor y1 = 13;
|
||||
accessor 'y2' = 14;
|
||||
accessor [name2] = 15;
|
||||
accessor [symbol2] = 16;
|
||||
accessor 2 = 17;
|
||||
}
|
||||
|
||||
// Test inherited accessors.
|
||||
let d = new D();
|
||||
assert.sameValue(d.x0, undefined);
|
||||
assert.sameValue(d.x1, 1);
|
||||
assert.sameValue(d.x2, 2);
|
||||
assert.sameValue(d.x3, 3);
|
||||
assert.sameValue(d[symbol], 4);
|
||||
assert.sameValue(d[1], 5);
|
||||
|
||||
// Test overridden accessors.
|
||||
assert.sameValue(d.y0, undefined);
|
||||
assert.sameValue(d.y1, 13);
|
||||
assert.sameValue(d.y2, 14);
|
||||
assert.sameValue(d.y3, 15);
|
||||
assert.sameValue(d[symbol2], 16);
|
||||
assert.sameValue(d[2], 17);
|
||||
d.y0 = 42;
|
||||
d.y1 = 43;
|
||||
d.y2 = 44;
|
||||
d.y3 = 45;
|
||||
d[symbol2] = 46;
|
||||
d[2] = 47;
|
||||
assert.sameValue(d.y0, 42);
|
||||
assert.sameValue(d.y1, 43);
|
||||
assert.sameValue(d.y2, 44);
|
||||
assert.sameValue(d.y3, 45);
|
||||
assert.sameValue(d[symbol2], 46);
|
||||
assert.sameValue(d[2], 47);
|
||||
|
||||
// Test base class accessors.
|
||||
let c = new C();
|
||||
assert.sameValue(c.y0, 7);
|
||||
assert.sameValue(c.y1, 8);
|
||||
assert.sameValue(c.y2, 9);
|
||||
assert.sameValue(c.y3, 10);
|
||||
assert.sameValue(c[symbol2], 11);
|
||||
assert.sameValue(c[2], 12);
|
||||
c.y0 = 48;
|
||||
c.y1 = 49;
|
||||
c.y2 = 50;
|
||||
c.y3 = 51;
|
||||
c[symbol2] = 52;
|
||||
c[2] = 53;
|
||||
assert.sameValue(c.y0, 48);
|
||||
assert.sameValue(c.y1, 49);
|
||||
assert.sameValue(c.y2, 50);
|
||||
assert.sameValue(c.y3, 51);
|
||||
assert.sameValue(c[symbol2], 52);
|
||||
assert.sameValue(c[2], 53);
|
||||
})();
|
||||
|
||||
(function TestAccessorsInPrototype() {
|
||||
const name = 'x2';
|
||||
class C {
|
||||
accessor x0 = 0;
|
||||
accessor x1 = 2;
|
||||
accessor [name] = 4;
|
||||
accessor 1 = 6;
|
||||
}
|
||||
|
||||
const assertIsAccessorDescriptor = (key, value) => {
|
||||
let c = new C();
|
||||
assert.sameValue(
|
||||
Object.getOwnPropertyDescriptor(C.prototype, key).get.call(c), value);
|
||||
value++;
|
||||
Object.getOwnPropertyDescriptor(C.prototype, key).set.call(c, value);
|
||||
assert.sameValue(
|
||||
Object.getOwnPropertyDescriptor(C.prototype, key).get.call(c), value);
|
||||
};
|
||||
|
||||
assertIsAccessorDescriptor('x0', 0);
|
||||
assertIsAccessorDescriptor('x1', 2);
|
||||
assertIsAccessorDescriptor('x2', 4);
|
||||
assertIsAccessorDescriptor(1, 6);
|
||||
})();
|
||||
|
||||
(function TestPublicStaticAutoAccessor() {
|
||||
let name = 'x3';
|
||||
let symbol = Symbol();
|
||||
class C {
|
||||
static accessor x0;
|
||||
static accessor x1 = 1;
|
||||
static accessor 'x2' = 2;
|
||||
static accessor [name] = 3;
|
||||
static accessor [symbol] = 4;
|
||||
static accessor 1 = 5;
|
||||
}
|
||||
assert.sameValue(C.x0, undefined);
|
||||
assert.sameValue(C.x1, 1);
|
||||
assert.sameValue(C.x2, 2);
|
||||
assert.sameValue(C.x3, 3);
|
||||
assert.sameValue(C[symbol], 4);
|
||||
assert.sameValue(C[1], 5);
|
||||
C.x0 = 42;
|
||||
C.x1 = 43;
|
||||
C.x2 = 44;
|
||||
C.x3 = 45;
|
||||
C[symbol] = 46;
|
||||
C[1] = 47;
|
||||
assert.sameValue(C.x0, 42);
|
||||
assert.sameValue(C.x1, 43);
|
||||
assert.sameValue(C.x2, 44);
|
||||
assert.sameValue(C.x3, 45);
|
||||
assert.sameValue(C[symbol], 46);
|
||||
assert.sameValue(C[1], 47);
|
||||
})();
|
||||
|
||||
(function TestRedeclaredPublicAutoaccessor() {
|
||||
let name = 'y';
|
||||
let symbol = Symbol();
|
||||
class C {
|
||||
static accessor x = 0;
|
||||
static accessor x = 1;
|
||||
static accessor y = 2;
|
||||
static accessor [name] = 3;
|
||||
static accessor [symbol] = 4;
|
||||
static accessor [symbol] = 5;
|
||||
static accessor 1 = 6;
|
||||
static accessor 1 = 7;
|
||||
}
|
||||
// Latest values should override previous ones.
|
||||
assert.sameValue(C.x, 1);
|
||||
assert.sameValue(C.y, 3);
|
||||
assert.sameValue(C[symbol], 5);
|
||||
assert.sameValue(C[1], 7);
|
||||
})();
|
||||
|
||||
(function TestDerivedPublicStaticAutoAccessor() {
|
||||
let name = 'x3';
|
||||
let symbol = Symbol();
|
||||
let name2 = 'y3';
|
||||
let symbol2 = Symbol();
|
||||
class C {
|
||||
static accessor x0;
|
||||
static accessor x1 = 1;
|
||||
static accessor 'x2' = 2;
|
||||
static accessor [name] = 3;
|
||||
static accessor [symbol] = 4;
|
||||
static accessor 1 = 5;
|
||||
|
||||
static accessor y0 = 6;
|
||||
static accessor y1 = 7;
|
||||
static accessor 'y2' = 8;
|
||||
static accessor [name2] = 9;
|
||||
static accessor [symbol2] = 10;
|
||||
static accessor 2 = 11;
|
||||
}
|
||||
class D extends C {
|
||||
static accessor y0;
|
||||
static accessor y1 = 12;
|
||||
static accessor 'y2' = 13;
|
||||
static accessor [name2] = 14;
|
||||
static accessor [symbol2] = 15;
|
||||
static accessor 2 = 16;
|
||||
}
|
||||
let assertThrowsTypeError = (code_string) => {
|
||||
assert.throws(TypeError, () => {eval(code_string)});
|
||||
};
|
||||
// Calling the accessor on the derived class passes such class as the receiver
|
||||
// to the generated getter/setter, which doesn't contain the static private
|
||||
// "accessor storage" variable and hence throws a TypeError.
|
||||
assertThrowsTypeError('D.x0');
|
||||
assertThrowsTypeError('D.x1');
|
||||
assertThrowsTypeError('D.x2');
|
||||
assertThrowsTypeError('D.x3');
|
||||
assertThrowsTypeError('D[symbol]');
|
||||
assertThrowsTypeError('D.x0 = 0');
|
||||
assertThrowsTypeError('D.x1 = 0');
|
||||
assertThrowsTypeError('D.x2 = 0');
|
||||
assertThrowsTypeError('D.x3 = 0');
|
||||
assertThrowsTypeError('D[symbol] = 0');
|
||||
assertThrowsTypeError('D[1]');
|
||||
|
||||
// Test overridden accessors.
|
||||
assert.sameValue(D.y0, undefined);
|
||||
assert.sameValue(D.y1, 12);
|
||||
assert.sameValue(D.y2, 13);
|
||||
assert.sameValue(D.y3, 14);
|
||||
assert.sameValue(D[symbol2], 15);
|
||||
assert.sameValue(D[2], 16);
|
||||
|
||||
D.y0 = 42;
|
||||
D.y1 = 43;
|
||||
D.y2 = 44;
|
||||
D.y3 = 45;
|
||||
D[symbol2] = 46;
|
||||
D[2] = 47;
|
||||
assert.sameValue(D.y0, 42);
|
||||
assert.sameValue(D.y1, 43);
|
||||
assert.sameValue(D.y2, 44);
|
||||
assert.sameValue(D.y3, 45);
|
||||
assert.sameValue(D[symbol2], 46);
|
||||
assert.sameValue(D[2], 47);
|
||||
|
||||
// Test base class accessors.
|
||||
assert.sameValue(C.y0, 6);
|
||||
assert.sameValue(C.y1, 7);
|
||||
assert.sameValue(C.y2, 8);
|
||||
assert.sameValue(C.y3, 9);
|
||||
assert.sameValue(C[symbol2], 10);
|
||||
assert.sameValue(C[2], 11);
|
||||
C.y0 = 48;
|
||||
C.y1 = 49;
|
||||
C.y2 = 50;
|
||||
C.y3 = 51;
|
||||
C[symbol2] = 52;
|
||||
C[2] = 53;
|
||||
assert.sameValue(C.y0, 48);
|
||||
assert.sameValue(C.y1, 49);
|
||||
assert.sameValue(C.y2, 50);
|
||||
assert.sameValue(C.y3, 51);
|
||||
assert.sameValue(C[symbol2], 52);
|
||||
assert.sameValue(C[2], 53);
|
||||
})();
|
||||
|
||||
(function TestStaticAccessorsInPrototype() {
|
||||
const name = 'x2';
|
||||
class C {
|
||||
static accessor x0 = 0;
|
||||
static accessor x1 = 2;
|
||||
static accessor [name] = 4;
|
||||
static accessor 1 = 6;
|
||||
}
|
||||
|
||||
const assertIsAccessorDescriptor = (key, value) => {
|
||||
assert.sameValue(
|
||||
Object.getOwnPropertyDescriptor(C.prototype.constructor, key)
|
||||
.get.call(C),
|
||||
value);
|
||||
value++;
|
||||
Object.getOwnPropertyDescriptor(C.prototype.constructor, key)
|
||||
.set.call(C, value);
|
||||
assert.sameValue(
|
||||
Object.getOwnPropertyDescriptor(C.prototype.constructor, key)
|
||||
.get.call(C),
|
||||
value);
|
||||
};
|
||||
|
||||
assertIsAccessorDescriptor('x0', 0);
|
||||
assertIsAccessorDescriptor('x1', 2);
|
||||
assertIsAccessorDescriptor('x2', 4);
|
||||
assertIsAccessorDescriptor(1, 6);
|
||||
})();
|
||||
|
||||
(function TestPublicAutoAccessorLiteralNameOverrides() {
|
||||
// Auto-accessors are override by getter/setter.
|
||||
class A {
|
||||
#x = 1;
|
||||
accessor x = 2;
|
||||
get x () {return this.#x};
|
||||
set x (v) {this.#x = v};
|
||||
xValue() {return this.#x};
|
||||
}
|
||||
const a = new A();
|
||||
assert.sameValue(a.x, 1); // Read from #x.
|
||||
a.x = 3; // Set #x to 3.
|
||||
assert.sameValue(a.x, 3); // Read from #x.
|
||||
assert.sameValue(a.xValue(), 3); // Read from #x.
|
||||
|
||||
// Auto-accessor getter overrides user-defined getter.
|
||||
// User-defined setter overrides auto-accessor setter.
|
||||
class B {
|
||||
#x = 1;
|
||||
get x () {return this.#x};
|
||||
accessor x = 2;
|
||||
set x (v) {this.#x = v};
|
||||
xValue() {return this.#x};
|
||||
}
|
||||
const b = new B();
|
||||
assert.sameValue(b.x, 2); // Read from accessor backing storage.
|
||||
b.x = 3; // Set #x to 3.
|
||||
assert.sameValue(b.x, 2); // Read from accessor backing storage.
|
||||
assert.sameValue(b.xValue(), 3); // Read from #x.
|
||||
|
||||
// Auto-accessor overrdes user-defined getter and setter.
|
||||
class C {
|
||||
#x = 1;
|
||||
get x () {return this.#x};
|
||||
set x (v) {this.#x = v};
|
||||
accessor x = 2;
|
||||
xValue() {return this.#x};
|
||||
}
|
||||
const c = new C(); // Read from accessor backing storage.
|
||||
assert.sameValue(c.x, 2);
|
||||
c.x = 3; // Set accessor backing storage.
|
||||
assert.sameValue(c.x, 3); // Read from accessor backing storage.
|
||||
assert.sameValue(c.xValue(), 1); // Read from #x.
|
||||
})();
|
||||
|
||||
(function TestStaticPublicAutoAccessorLiteralNameOverrides() {
|
||||
// Auto-accessors are override by getter/setter.
|
||||
class A {
|
||||
static #x = 1;
|
||||
static accessor x = 2;
|
||||
static get x () {return this.#x};
|
||||
static set x (v) {this.#x = v};
|
||||
static xValue() {return this.#x};
|
||||
}
|
||||
assert.sameValue(A.x, 1);
|
||||
A.x = 3;
|
||||
assert.sameValue(A.x, 3);
|
||||
assert.sameValue(A.xValue(), 3);
|
||||
|
||||
// Auto-accessor getter overrides user-defined getter.
|
||||
// User-defined setter overrides auto-accessor setter.
|
||||
class B {
|
||||
static #x = 1;
|
||||
static get x () {return this.#x};
|
||||
static accessor x = 2;
|
||||
static set x (v) {this.#x = v};
|
||||
static xValue() {return this.#x};
|
||||
}
|
||||
assert.sameValue(B.x, 2);
|
||||
B.x = 3; // Set #x to 3.
|
||||
assert.sameValue(B.x, 2); // Read from accessor backing storage.
|
||||
assert.sameValue(B.xValue(),3); // Read from #x.
|
||||
|
||||
// Auto-accessor overrdes user-defined getter and setter.
|
||||
class C {
|
||||
static #x = 1;
|
||||
static get x () {return this.#x};
|
||||
static set x (v) {this.#x = v};
|
||||
static accessor x = 2;
|
||||
static xValue() {return this.#x};
|
||||
}
|
||||
assert.sameValue(C.x, 2);
|
||||
C.x = 3; // Set accessor backing storage.
|
||||
assert.sameValue(C.x, 3); // Read from accessor backing storage.
|
||||
assert.sameValue(C.xValue(), 1); // Read from #x.
|
||||
})();
|
||||
|
||||
(function TestPublicAutoAccessorComputedNameOverrides() {
|
||||
let name = 'x';
|
||||
// Auto-accessors are override by getter/setter.
|
||||
class A {
|
||||
#x = 1;
|
||||
accessor [name] = 2;
|
||||
get x () {return this.#x};
|
||||
set x (v) {this.#x = v};
|
||||
xValue() {return this.#x};
|
||||
}
|
||||
const a = new A();
|
||||
assert.sameValue(a.x, 1); // Read from #x.
|
||||
a.x = 3; // Set #x to 3.
|
||||
assert.sameValue(a.x, 3); // Read from #x.
|
||||
assert.sameValue(a.xValue(), 3); // Read from #x.
|
||||
|
||||
// Auto-accessor getter overrides user-defined getter.
|
||||
// User-defined setter overrides auto-accessor setter.
|
||||
class B {
|
||||
#x = 1;
|
||||
get x () {return this.#x};
|
||||
accessor [name] = 2;
|
||||
set x (v) {this.#x = v};
|
||||
xValue() {return this.#x};
|
||||
}
|
||||
const b = new B();
|
||||
assert.sameValue(b.x, 2); // Read from accessor backing storage.
|
||||
b.x = 3; // Set #x to 3.
|
||||
assert.sameValue(b.x, 2); // Read from accessor backing storage.
|
||||
assert.sameValue(b.xValue(), 3); // Read from #x.
|
||||
|
||||
// Auto-accessor overrdes user-defined getter and setter.
|
||||
class C {
|
||||
#x = 1;
|
||||
get x () {return this.#x};
|
||||
set x (v) {this.#x = v};
|
||||
accessor [name] = 2;
|
||||
xValue() {return this.#x};
|
||||
}
|
||||
const c = new C(); // Read from accessor backing storage.
|
||||
assert.sameValue(c.x, 2);
|
||||
c.x = 3; // Set accessor backing storage.
|
||||
assert.sameValue(c.x, 3); // Read from accessor backing storage.
|
||||
assert.sameValue(c.xValue(), 1); // Read from #x.
|
||||
})();
|
||||
|
||||
(function TestStaticPublicAutoAccessorComputedNameOverrides() {
|
||||
let name = 'x';
|
||||
// Auto-accessors are override by getter/setter.
|
||||
class A {
|
||||
static #x = 1;
|
||||
static accessor [name] = 2;
|
||||
static get x () {return this.#x};
|
||||
static set x (v) {this.#x = v};
|
||||
static xValue() {return this.#x};
|
||||
}
|
||||
assert.sameValue(A.x, 1);
|
||||
A.x = 3;
|
||||
assert.sameValue(A.x, 3);
|
||||
assert.sameValue(A.xValue(), 3);
|
||||
|
||||
// Auto-accessor getter overrides user-defined getter.
|
||||
// User-defined setter overrides auto-accessor setter.
|
||||
class B {
|
||||
static #x = 1;
|
||||
static get x () {return this.#x};
|
||||
static accessor [name] = 2;
|
||||
static set x (v) {this.#x = v};
|
||||
static xValue() {return this.#x};
|
||||
}
|
||||
assert.sameValue(B.x, 2);
|
||||
B.x = 3; // Set #x to 3.
|
||||
assert.sameValue(B.x, 2); // Read from accessor backing storage.
|
||||
assert.sameValue(B.xValue(), 3); // Read from #x.
|
||||
|
||||
// Auto-accessor overrdes user-defined getter and setter.
|
||||
class C {
|
||||
static #x = 1;
|
||||
static get x () {return this.#x};
|
||||
static set x (v) {this.#x = v};
|
||||
static accessor [name] = 2;
|
||||
static xValue() {return this.#x};
|
||||
}
|
||||
assert.sameValue(C.x, 2);
|
||||
C.x = 3; // Set accessor backing storage.
|
||||
assert.sameValue(C.x, 3); // Read from accessor backing storage.
|
||||
assert.sameValue(C.xValue(), 1); // Read from #x.
|
||||
})();
|
Loading…
Reference in New Issue