Skip to content

Commit 8fc8c95

Browse files
authored
Decorators normative updates (#55276)
1 parent b1c4dc4 commit 8fc8c95

File tree

35 files changed

+735
-89
lines changed

35 files changed

+735
-89
lines changed

src/compiler/checker.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -32875,7 +32875,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3287532875
*/
3287632876
function getThisArgumentOfCall(node: CallLikeExpression): LeftHandSideExpression | undefined {
3287732877
const expression = node.kind === SyntaxKind.CallExpression ? node.expression :
32878-
node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : undefined;
32878+
node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag :
32879+
node.kind === SyntaxKind.Decorator && !legacyDecorators ? node.expression :
32880+
undefined;
3287932881
if (expression) {
3288032882
const callee = skipOuterExpressions(expression);
3288132883
if (isAccessExpression(callee)) {

src/compiler/factory/utilities.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1645,7 +1645,7 @@ export function createAccessorPropertyBackingField(factory: NodeFactory, node: P
16451645
*
16461646
* @internal
16471647
*/
1648-
export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, name: PropertyName): GetAccessorDeclaration {
1648+
export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: readonly Modifier[] | undefined, name: PropertyName, receiver: Expression = factory.createThis()): GetAccessorDeclaration {
16491649
return factory.createGetAccessorDeclaration(
16501650
modifiers,
16511651
name,
@@ -1654,7 +1654,7 @@ export function createAccessorPropertyGetRedirector(factory: NodeFactory, node:
16541654
factory.createBlock([
16551655
factory.createReturnStatement(
16561656
factory.createPropertyAccessExpression(
1657-
factory.createThis(),
1657+
receiver,
16581658
factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage")
16591659
)
16601660
)
@@ -1667,7 +1667,7 @@ export function createAccessorPropertyGetRedirector(factory: NodeFactory, node:
16671667
*
16681668
* @internal
16691669
*/
1670-
export function createAccessorPropertySetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, name: PropertyName) {
1670+
export function createAccessorPropertySetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: readonly Modifier[] | undefined, name: PropertyName, receiver: Expression = factory.createThis()) {
16711671
return factory.createSetAccessorDeclaration(
16721672
modifiers,
16731673
name,
@@ -1680,7 +1680,7 @@ export function createAccessorPropertySetRedirector(factory: NodeFactory, node:
16801680
factory.createExpressionStatement(
16811681
factory.createAssignment(
16821682
factory.createPropertyAccessExpression(
1683-
factory.createThis(),
1683+
receiver,
16841684
factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage")
16851685
),
16861686
factory.createIdentifier("value")

src/compiler/transformers/classFields.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ import {
154154
Modifier,
155155
ModifierFlags,
156156
ModifierLike,
157+
modifiersToFlags,
157158
moveRangePastModifiers,
158159
moveRangePos,
159160
newPrivateEnvironment,
@@ -896,6 +897,12 @@ export function transformClassFields(context: TransformationContext): (x: Source
896897
}
897898
}
898899

900+
function getClassThis() {
901+
const lex = getClassLexicalEnvironment();
902+
const classThis = lex.classThis ?? lex.classConstructor ?? currentClassContainer?.name;
903+
return Debug.checkDefined(classThis);
904+
}
905+
899906
function transformAutoAccessor(node: AutoAccessorPropertyDeclaration): VisitResult<Node> {
900907
// transforms:
901908
// accessor x = 1;
@@ -935,12 +942,15 @@ export function transformClassFields(context: TransformationContext): (x: Source
935942
setEmitFlags(backingField, EmitFlags.NoComments);
936943
setSourceMapRange(backingField, sourceMapRange);
937944

938-
const getter = createAccessorPropertyGetRedirector(factory, node, modifiers, getterName);
945+
const receiver = isStatic(node) ? getClassThis() : factory.createThis();
946+
const getter = createAccessorPropertyGetRedirector(factory, node, modifiers, getterName, receiver);
939947
setOriginalNode(getter, node);
940948
setCommentRange(getter, commentRange);
941949
setSourceMapRange(getter, sourceMapRange);
942950

943-
const setter = createAccessorPropertySetRedirector(factory, node, modifiers, setterName);
951+
// create a fresh copy of the modifiers so that we don't duplicate comments
952+
const setterModifiers = factory.createModifiersFromModifierFlags(modifiersToFlags(modifiers));
953+
const setter = createAccessorPropertySetRedirector(factory, node, setterModifiers, setterName, receiver);
944954
setOriginalNode(setter, node);
945955
setEmitFlags(setter, EmitFlags.NoComments);
946956
setSourceMapRange(setter, sourceMapRange);
@@ -1692,11 +1702,13 @@ export function transformClassFields(context: TransformationContext): (x: Source
16921702
let containsInstanceAutoAccessors = false;
16931703
for (const member of node.members) {
16941704
if (isStatic(member)) {
1695-
if (member.name &&
1696-
(isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) &&
1705+
if (member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) &&
16971706
shouldTransformPrivateElementsOrClassStaticBlocks) {
16981707
facts |= ClassFacts.NeedsClassConstructorReference;
16991708
}
1709+
else if (isAutoAccessorPropertyDeclaration(member) && shouldTransformAutoAccessors === Ternary.True && !node.name && !node.emitNode?.classThis) {
1710+
facts |= ClassFacts.NeedsClassConstructorReference;
1711+
}
17001712
if (isPropertyDeclaration(member) || isClassStaticBlockDeclaration(member)) {
17011713
if (shouldTransformThisInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalThis) {
17021714
facts |= ClassFacts.NeedsSubstitutionForThisInClassStaticField;
@@ -1846,10 +1858,10 @@ export function transformClassFields(context: TransformationContext): (x: Source
18461858
getClassLexicalEnvironment().classConstructor = factory.cloneNode(temp);
18471859
pendingClassReferenceAssignment = factory.createAssignment(temp, factory.getInternalName(node));
18481860
}
1861+
}
18491862

1850-
if (node.emitNode?.classThis) {
1851-
getClassLexicalEnvironment().classThis = node.emitNode.classThis;
1852-
}
1863+
if (node.emitNode?.classThis) {
1864+
getClassLexicalEnvironment().classThis = node.emitNode.classThis;
18531865
}
18541866

18551867
const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsConstructorReference;

src/compiler/transformers/esDecorators.ts

+10
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
getAllDecoratorsOfClassElement,
4848
getCommentRange,
4949
getEffectiveBaseTypeNode,
50+
getEmitScriptTarget,
5051
getFirstConstructorWithBody,
5152
getHeritageClause,
5253
getNonAssignmentOperatorForCompoundAssignment,
@@ -62,6 +63,7 @@ import {
6263
injectClassNamedEvaluationHelperBlockIfMissing,
6364
injectClassThisAssignmentIfMissing,
6465
InternalEmitFlags,
66+
isAccessExpression,
6567
isAmbientPropertyDeclaration,
6668
isArrayBindingOrAssignmentElement,
6769
isArrayLiteralExpression,
@@ -289,6 +291,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
289291
hoistVariableDeclaration,
290292
} = context;
291293

294+
const languageVersion = getEmitScriptTarget(context.getCompilerOptions());
292295
let top: LexicalEnvironmentStackEntry | undefined;
293296
let classInfo: ClassInfo | undefined;
294297
let classThis: Identifier | undefined;
@@ -2147,6 +2150,13 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
21472150
function transformDecorator(decorator: Decorator) {
21482151
const expression = visitNode(decorator.expression, visitor, isExpression);
21492152
setEmitFlags(expression, EmitFlags.NoComments);
2153+
2154+
// preserve the 'this' binding for an access expression
2155+
const innerExpression = skipOuterExpressions(expression);
2156+
if (isAccessExpression(innerExpression)) {
2157+
const { target, thisArg } = factory.createCallBinding(expression, hoistVariableDeclaration, languageVersion, /*cacheIdentifiers*/ true);
2158+
return factory.restoreOuterExpressions(expression, factory.createFunctionBindCall(target, thisArg, []));
2159+
}
21502160
return expression;
21512161
}
21522162

tests/baselines/reference/autoAccessor1(target=es2015).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ class C1 {
3131
set a(value) { __classPrivateFieldSet(this, _C1_a_accessor_storage, value, "f"); }
3232
get b() { return __classPrivateFieldGet(this, _C1_b_accessor_storage, "f"); }
3333
set b(value) { __classPrivateFieldSet(this, _C1_b_accessor_storage, value, "f"); }
34-
static get c() { return __classPrivateFieldGet(this, _a, "f", _C1_c_accessor_storage); }
35-
static set c(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_c_accessor_storage); }
36-
static get d() { return __classPrivateFieldGet(this, _a, "f", _C1_d_accessor_storage); }
37-
static set d(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_d_accessor_storage); }
34+
static get c() { return __classPrivateFieldGet(_a, _a, "f", _C1_c_accessor_storage); }
35+
static set c(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_c_accessor_storage); }
36+
static get d() { return __classPrivateFieldGet(_a, _a, "f", _C1_d_accessor_storage); }
37+
static set d(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_d_accessor_storage); }
3838
}
3939
_a = C1, _C1_a_accessor_storage = new WeakMap(), _C1_b_accessor_storage = new WeakMap();
4040
_C1_c_accessor_storage = { value: void 0 };

tests/baselines/reference/autoAccessor1(target=es2022).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ class C1 {
1818
get b() { return this.#b_accessor_storage; }
1919
set b(value) { this.#b_accessor_storage = value; }
2020
static #c_accessor_storage;
21-
static get c() { return this.#c_accessor_storage; }
22-
static set c(value) { this.#c_accessor_storage = value; }
21+
static get c() { return C1.#c_accessor_storage; }
22+
static set c(value) { C1.#c_accessor_storage = value; }
2323
static #d_accessor_storage = 2;
24-
static get d() { return this.#d_accessor_storage; }
25-
static set d(value) { this.#d_accessor_storage = value; }
24+
static get d() { return C1.#d_accessor_storage; }
25+
static set d(value) { C1.#d_accessor_storage = value; }
2626
}

tests/baselines/reference/autoAccessor10.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ class C3 {
5757
}
5858
class C4_1 {
5959
static #a3_accessor_storage = 1;
60-
static get a3() { return this.#a3_accessor_storage; }
61-
static set a3(value) { this.#a3_accessor_storage = value; }
60+
static get a3() { return C4_1.#a3_accessor_storage; }
61+
static set a3(value) { C4_1.#a3_accessor_storage = value; }
6262
}
6363
class C4_2 {
6464
static #a3_accessor_storage = 1;
65-
static get a3() { return this.#a3_accessor_storage; }
66-
static set a3(value) { this.#a3_accessor_storage = value; }
65+
static get a3() { return C4_2.#a3_accessor_storage; }
66+
static set a3(value) { C4_2.#a3_accessor_storage = value; }
6767
}

tests/baselines/reference/autoAccessor2(target=es2015).js

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class C1 {
4141
__classPrivateFieldSet(this, _C1_instances, 4, "a", _C1_b_set);
4242
}
4343
}
44-
_a = C1, _C1_instances = new WeakSet(), _C1_a_accessor_storage = new WeakMap(), _C1_b_accessor_storage = new WeakMap(), _C1_a_get = function _C1_a_get() { return __classPrivateFieldGet(this, _C1_a_accessor_storage, "f"); }, _C1_a_set = function _C1_a_set(value) { __classPrivateFieldSet(this, _C1_a_accessor_storage, value, "f"); }, _C1_b_get = function _C1_b_get() { return __classPrivateFieldGet(this, _C1_b_accessor_storage, "f"); }, _C1_b_set = function _C1_b_set(value) { __classPrivateFieldSet(this, _C1_b_accessor_storage, value, "f"); }, _C1_c_get = function _C1_c_get() { return __classPrivateFieldGet(this, _a, "f", _C1_c_accessor_storage); }, _C1_c_set = function _C1_c_set(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_c_accessor_storage); }, _C1_d_get = function _C1_d_get() { return __classPrivateFieldGet(this, _a, "f", _C1_d_accessor_storage); }, _C1_d_set = function _C1_d_set(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_d_accessor_storage); };
44+
_a = C1, _C1_instances = new WeakSet(), _C1_a_accessor_storage = new WeakMap(), _C1_b_accessor_storage = new WeakMap(), _C1_a_get = function _C1_a_get() { return __classPrivateFieldGet(this, _C1_a_accessor_storage, "f"); }, _C1_a_set = function _C1_a_set(value) { __classPrivateFieldSet(this, _C1_a_accessor_storage, value, "f"); }, _C1_b_get = function _C1_b_get() { return __classPrivateFieldGet(this, _C1_b_accessor_storage, "f"); }, _C1_b_set = function _C1_b_set(value) { __classPrivateFieldSet(this, _C1_b_accessor_storage, value, "f"); }, _C1_c_get = function _C1_c_get() { return __classPrivateFieldGet(_a, _a, "f", _C1_c_accessor_storage); }, _C1_c_set = function _C1_c_set(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_c_accessor_storage); }, _C1_d_get = function _C1_d_get() { return __classPrivateFieldGet(_a, _a, "f", _C1_d_accessor_storage); }, _C1_d_set = function _C1_d_set(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_d_accessor_storage); };
4545
_C1_c_accessor_storage = { value: void 0 };
4646
_C1_d_accessor_storage = { value: 2 };
4747
(() => {

tests/baselines/reference/autoAccessor2(target=es2022).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ class C1 {
2828
get #b() { return this.#b_accessor_storage; }
2929
set #b(value) { this.#b_accessor_storage = value; }
3030
static #c_accessor_storage;
31-
static get #c() { return this.#c_accessor_storage; }
32-
static set #c(value) { this.#c_accessor_storage = value; }
31+
static get #c() { return C1.#c_accessor_storage; }
32+
static set #c(value) { C1.#c_accessor_storage = value; }
3333
static #d_accessor_storage = 2;
34-
static get #d() { return this.#d_accessor_storage; }
35-
static set #d(value) { this.#d_accessor_storage = value; }
34+
static get #d() { return C1.#d_accessor_storage; }
35+
static set #d(value) { C1.#d_accessor_storage = value; }
3636
constructor() {
3737
this.#a = 3;
3838
this.#b = 4;

tests/baselines/reference/autoAccessor3(target=es2015).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ class C1 {
3131
set "w"(value) { __classPrivateFieldSet(this, _C1__a_accessor_storage, value, "f"); }
3232
get "x"() { return __classPrivateFieldGet(this, _C1__b_accessor_storage, "f"); }
3333
set "x"(value) { __classPrivateFieldSet(this, _C1__b_accessor_storage, value, "f"); }
34-
static get "y"() { return __classPrivateFieldGet(this, _a, "f", _C1__c_accessor_storage); }
35-
static set "y"(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__c_accessor_storage); }
36-
static get "z"() { return __classPrivateFieldGet(this, _a, "f", _C1__d_accessor_storage); }
37-
static set "z"(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__d_accessor_storage); }
34+
static get "y"() { return __classPrivateFieldGet(_a, _a, "f", _C1__c_accessor_storage); }
35+
static set "y"(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__c_accessor_storage); }
36+
static get "z"() { return __classPrivateFieldGet(_a, _a, "f", _C1__d_accessor_storage); }
37+
static set "z"(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__d_accessor_storage); }
3838
}
3939
_a = C1, _C1__a_accessor_storage = new WeakMap(), _C1__b_accessor_storage = new WeakMap();
4040
_C1__c_accessor_storage = { value: void 0 };

tests/baselines/reference/autoAccessor3(target=es2022).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ class C1 {
1818
get "x"() { return this.#_b_accessor_storage; }
1919
set "x"(value) { this.#_b_accessor_storage = value; }
2020
static #_c_accessor_storage;
21-
static get "y"() { return this.#_c_accessor_storage; }
22-
static set "y"(value) { this.#_c_accessor_storage = value; }
21+
static get "y"() { return C1.#_c_accessor_storage; }
22+
static set "y"(value) { C1.#_c_accessor_storage = value; }
2323
static #_d_accessor_storage = 2;
24-
static get "z"() { return this.#_d_accessor_storage; }
25-
static set "z"(value) { this.#_d_accessor_storage = value; }
24+
static get "z"() { return C1.#_d_accessor_storage; }
25+
static set "z"(value) { C1.#_d_accessor_storage = value; }
2626
}

tests/baselines/reference/autoAccessor4(target=es2015).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ class C1 {
3131
set 0(value) { __classPrivateFieldSet(this, _C1__a_accessor_storage, value, "f"); }
3232
get 1() { return __classPrivateFieldGet(this, _C1__b_accessor_storage, "f"); }
3333
set 1(value) { __classPrivateFieldSet(this, _C1__b_accessor_storage, value, "f"); }
34-
static get 2() { return __classPrivateFieldGet(this, _a, "f", _C1__c_accessor_storage); }
35-
static set 2(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__c_accessor_storage); }
36-
static get 3() { return __classPrivateFieldGet(this, _a, "f", _C1__d_accessor_storage); }
37-
static set 3(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__d_accessor_storage); }
34+
static get 2() { return __classPrivateFieldGet(_a, _a, "f", _C1__c_accessor_storage); }
35+
static set 2(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__c_accessor_storage); }
36+
static get 3() { return __classPrivateFieldGet(_a, _a, "f", _C1__d_accessor_storage); }
37+
static set 3(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__d_accessor_storage); }
3838
}
3939
_a = C1, _C1__a_accessor_storage = new WeakMap(), _C1__b_accessor_storage = new WeakMap();
4040
_C1__c_accessor_storage = { value: void 0 };

tests/baselines/reference/autoAccessor4(target=es2022).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ class C1 {
1818
get 1() { return this.#_b_accessor_storage; }
1919
set 1(value) { this.#_b_accessor_storage = value; }
2020
static #_c_accessor_storage;
21-
static get 2() { return this.#_c_accessor_storage; }
22-
static set 2(value) { this.#_c_accessor_storage = value; }
21+
static get 2() { return C1.#_c_accessor_storage; }
22+
static set 2(value) { C1.#_c_accessor_storage = value; }
2323
static #_d_accessor_storage = 2;
24-
static get 3() { return this.#_d_accessor_storage; }
25-
static set 3(value) { this.#_d_accessor_storage = value; }
24+
static get 3() { return C1.#_d_accessor_storage; }
25+
static set 3(value) { C1.#_d_accessor_storage = value; }
2626
}

tests/baselines/reference/autoAccessor5(target=es2015).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ class C1 {
3535
set ["w"](value) { __classPrivateFieldSet(this, _C1__a_accessor_storage, value, "f"); }
3636
get ["x"]() { return __classPrivateFieldGet(this, _C1__b_accessor_storage, "f"); }
3737
set ["x"](value) { __classPrivateFieldSet(this, _C1__b_accessor_storage, value, "f"); }
38-
static get ["y"]() { return __classPrivateFieldGet(this, _a, "f", _C1__c_accessor_storage); }
39-
static set ["y"](value) { __classPrivateFieldSet(this, _a, value, "f", _C1__c_accessor_storage); }
40-
static get ["z"]() { return __classPrivateFieldGet(this, _a, "f", _C1__d_accessor_storage); }
41-
static set ["z"](value) { __classPrivateFieldSet(this, _a, value, "f", _C1__d_accessor_storage); }
38+
static get ["y"]() { return __classPrivateFieldGet(_a, _a, "f", _C1__c_accessor_storage); }
39+
static set ["y"](value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__c_accessor_storage); }
40+
static get ["z"]() { return __classPrivateFieldGet(_a, _a, "f", _C1__d_accessor_storage); }
41+
static set ["z"](value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__d_accessor_storage); }
4242
}
4343
_a = C1;
4444
_C1__c_accessor_storage = { value: void 0 };

tests/baselines/reference/autoAccessor5(target=es2022).js

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ class C1 {
2323
get ["x"]() { return this.#_b_accessor_storage; }
2424
set ["x"](value) { this.#_b_accessor_storage = value; }
2525
static #_c_accessor_storage;
26-
static get ["y"]() { return this.#_c_accessor_storage; }
27-
static set ["y"](value) { this.#_c_accessor_storage = value; }
26+
static get ["y"]() { return C1.#_c_accessor_storage; }
27+
static set ["y"](value) { C1.#_c_accessor_storage = value; }
2828
static #_d_accessor_storage = 2;
29-
static get ["z"]() { return this.#_d_accessor_storage; }
30-
static set ["z"](value) { this.#_d_accessor_storage = value; }
29+
static get ["z"]() { return C1.#_d_accessor_storage; }
30+
static set ["z"](value) { C1.#_d_accessor_storage = value; }
3131
}
3232
class C2 {
3333
#_e_accessor_storage = 1;

0 commit comments

Comments
 (0)