diff --git a/tsc/internal/transformers/estransforms/classfields.go b/tsc/internal/transformers/estransforms/classfields.go index 68dc3950413d9..52ae3c681a0c4 100644 --- a/tsc/internal/transformers/estransforms/classfields.go +++ b/tsc/internal/transformers/estransforms/classfields.go @@ -2040,23 +2040,22 @@ func (tx *classFieldsTransformer) visitClassExpressionInNewClassLexicalEnvironme } staticPropertiesOrClassStaticBlocks := tx.getStaticPropertiesAndClassStaticBlock(node) + hasTransformableStatics := (tx.shouldTransformPrivateElementsOrClassStaticBlocks || + tx.nodeHasTransformPrivateStaticElementsFlag(node)) && + core.Some(staticPropertiesOrClassStaticBlocks, func(n *ast.Node) bool { + return ast.IsClassStaticBlockDeclaration(n) || + ast.IsPrivateIdentifierClassElementDeclaration(n) || + (tx.shouldTransformInitializers && ast.IsInitializedProperty(n)) + }) // Pre-compute whether the class expression will need a temp variable wrapper. // Strada registers class aliases AFTER transformClassMembers (since onSubstituteNode runs // at emit time), but we must predict this before visiting members since we substitute // eagerly. This requires pre-detecting willHavePrivatePendingExpressions. isClassWithConstructorReference := false - hasTransformableStatics := false deferTempDeclaration := false if !isDecoratedClassDeclaration { isClassWithConstructorReference = tx.classContainsConstructorReference(node) - hasTransformableStatics = (tx.shouldTransformPrivateElementsOrClassStaticBlocks || - tx.nodeHasTransformPrivateStaticElementsFlag(node)) && - core.Some(staticPropertiesOrClassStaticBlocks, func(n *ast.Node) bool { - return ast.IsClassStaticBlockDeclaration(n) || - ast.IsPrivateIdentifierClassElementDeclaration(n) || - (tx.shouldTransformInitializers && ast.IsInitializedProperty(n)) - }) // Private instance elements (fields, methods, accessors) transformed to // WeakMap/WeakSet will add initialization expressions to pendingExpressions @@ -2139,7 +2138,7 @@ func (tx *classFieldsTransformer) visitClassExpressionInNewClassLexicalEnvironme } else { expressions = append(expressions, classExpression) } - } else { + } else if hasTransformableStatics || len(tx.pendingExpressions) > 0 { // Decorated class declaration path: emit static properties as separate statements // via pendingStatements, matching the class declaration output structure. @@ -2167,6 +2166,8 @@ func (tx *classFieldsTransformer) visitClassExpressionInNewClassLexicalEnvironme } else { expressions = append(expressions, classExpression) } + } else { + expressions = append(expressions, classExpression) } if len(expressions) > 1 { diff --git a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2015).js b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2015).js index 3bcdba587ec86..0d38b0cc8bfc8 100644 --- a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2015).js @@ -5,6 +5,22 @@ declare let dec: any; @dec class C {} +@dec class C1 { + #field = C1; +} + +@dec class C2 { + #method() { return C2; } +} + +@dec class C3 { + get #accessor() { return C3; } +} + +@dec class C4 { + set #accessor(value: unknown) { C4; } +} + export {} //// [b.ts] @@ -41,6 +57,97 @@ let C = (() => { })(); return C = _classThis; })(); +let C1 = (() => { + var _C1_field; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C1 = _classThis = class { + constructor() { + _C1_field.set(this, C1); + } + }; + _C1_field = new WeakMap(); + __setFunctionName(_classThis, "C1"); + (() => { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C1 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + })(); + return C1 = _classThis; +})(); +let C2 = (() => { + var _C2_instances, _C2_method; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C2 = _classThis = class { + constructor() { + _C2_instances.add(this); + } + }; + _C2_instances = new WeakSet(); + _C2_method = function _C2_method() { return C2; }; + __setFunctionName(_classThis, "C2"); + (() => { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C2 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + })(); + return C2 = _classThis; +})(); +let C3 = (() => { + var _C3_instances, _C3_accessor_get; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C3 = _classThis = class { + constructor() { + _C3_instances.add(this); + } + }; + _C3_instances = new WeakSet(); + _C3_accessor_get = function _C3_accessor_get() { return C3; }; + __setFunctionName(_classThis, "C3"); + (() => { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C3 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + })(); + return C3 = _classThis; +})(); +let C4 = (() => { + var _C4_instances, _C4_accessor_set; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C4 = _classThis = class { + constructor() { + _C4_instances.add(this); + } + }; + _C4_instances = new WeakSet(); + _C4_accessor_set = function _C4_accessor_set(value) { C4; }; + __setFunctionName(_classThis, "C4"); + (() => { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C4 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + })(); + return C4 = _classThis; +})(); export {}; //// [b.js] let C = (() => { diff --git a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2022).js b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2022).js index 2569ebe10eeb2..d26864c21d9c2 100644 --- a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2022).js +++ b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=es2022).js @@ -5,6 +5,22 @@ declare let dec: any; @dec class C {} +@dec class C1 { + #field = C1; +} + +@dec class C2 { + #method() { return C2; } +} + +@dec class C3 { + get #accessor() { return C3; } +} + +@dec class C4 { + set #accessor(value: unknown) { C4; } +} + export {} //// [b.ts] @@ -41,6 +57,82 @@ let C = (() => { }; return C = _classThis; })(); +let C1 = (() => { + var _a; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C1 = class { + static { _classThis = this; } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C1 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + } + #field = C1; + }; + return C1 = _classThis; +})(); +let C2 = (() => { + var _a; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C2 = class { + static { _classThis = this; } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C2 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + } + #method() { return C2; } + }; + return C2 = _classThis; +})(); +let C3 = (() => { + var _a; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C3 = class { + static { _classThis = this; } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C3 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + } + get #accessor() { return C3; } + }; + return C3 = _classThis; +})(); +let C4 = (() => { + var _a; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C4 = class { + static { _classThis = this; } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C4 = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + } + set #accessor(value) { C4; } + }; + return C4 = _classThis; +})(); export {}; //// [b.js] let C = (() => { diff --git a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=esnext).js b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=esnext).js index 6c0889fa38717..6ef509c31f464 100644 --- a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=esnext).js +++ b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionName(target=esnext).js @@ -5,6 +5,22 @@ declare let dec: any; @dec class C {} +@dec class C1 { + #field = C1; +} + +@dec class C2 { + #method() { return C2; } +} + +@dec class C3 { + get #accessor() { return C3; } +} + +@dec class C4 { + set #accessor(value: unknown) { C4; } +} + export {} //// [b.ts] @@ -27,6 +43,22 @@ declare let dec: any; @dec class C { } +@dec +class C1 { + #field = C1; +} +@dec +class C2 { + #method() { return C2; } +} +@dec +class C3 { + get #accessor() { return C3; } +} +@dec +class C4 { + set #accessor(value) { C4; } +} export {}; //// [b.js] @dec diff --git a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionNameComputedField(usedefineforclassfields=false).js b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionNameComputedField(usedefineforclassfields=false).js new file mode 100644 index 0000000000000..442a68c12d676 --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionNameComputedField(usedefineforclassfields=false).js @@ -0,0 +1,46 @@ +//// [tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionNameComputedField.ts] //// + +//// [esDecorators-classDeclaration-setFunctionNameComputedField.ts] +declare let dec: any; + +const keys = { + get field(): "field" { return "field"; } +}; + +@dec class C { + #self = C; + [keys.field] = 0; +} + +export {}; + + +//// [esDecorators-classDeclaration-setFunctionNameComputedField.js] +const keys = { + get field() { return "field"; } +}; +let C = (() => { + var _a, _b; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C = class { + static { _classThis = this; } + constructor() { + this.#self = C; + this[_b] = 0; + } + static { _b = keys.field; } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + } + #self; + }; + return C = _classThis; +})(); +export {}; diff --git a/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionNameComputedField(usedefineforclassfields=true).js b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionNameComputedField(usedefineforclassfields=true).js new file mode 100644 index 0000000000000..0cb63ae5b6140 --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/esDecorators-classDeclaration-setFunctionNameComputedField(usedefineforclassfields=true).js @@ -0,0 +1,42 @@ +//// [tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionNameComputedField.ts] //// + +//// [esDecorators-classDeclaration-setFunctionNameComputedField.ts] +declare let dec: any; + +const keys = { + get field(): "field" { return "field"; } +}; + +@dec class C { + #self = C; + [keys.field] = 0; +} + +export {}; + + +//// [esDecorators-classDeclaration-setFunctionNameComputedField.js] +const keys = { + get field() { return "field"; } +}; +let C = (() => { + var _a; + let _classDecorators = [dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var C = class { + static { _classThis = this; } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + C = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + __runInitializers(_classThis, _classExtraInitializers); + } + #self = C; + [keys.field] = 0; + }; + return C = _classThis; +})(); +export {}; diff --git a/tsc/testdata/tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionName.ts b/tsc/testdata/tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionName.ts index b479b27785e45..35e12a9caac62 100644 --- a/tsc/testdata/tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionName.ts +++ b/tsc/testdata/tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionName.ts @@ -7,6 +7,22 @@ declare let dec: any; @dec class C {} +@dec class C1 { + #field = C1; +} + +@dec class C2 { + #method() { return C2; } +} + +@dec class C3 { + get #accessor() { return C3; } +} + +@dec class C4 { + set #accessor(value: unknown) { C4; } +} + export {} // @filename: b.ts diff --git a/tsc/testdata/tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionNameComputedField.ts b/tsc/testdata/tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionNameComputedField.ts new file mode 100644 index 0000000000000..8812f93bbee3b --- /dev/null +++ b/tsc/testdata/tests/cases/conformance/esDecorators/classDeclaration/esDecorators-classDeclaration-setFunctionNameComputedField.ts @@ -0,0 +1,17 @@ +// @target: es2022 +// @useDefineForClassFields: true, false +// @noEmitHelpers: true +// @noTypesAndSymbols: true + +declare let dec: any; + +const keys = { + get field(): "field" { return "field"; } +}; + +@dec class C { + #self = C; + [keys.field] = 0; +} + +export {};