diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 0a59c319876..6a7cf797903 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10531,9 +10531,7 @@ func (c *Checker) needCollisionCheckForIdentifier(node *ast.Node, identifier *as func (c *Checker) setNodeLinksForPrivateIdentifierScope(node *ast.Node) { if name := node.Name(); ast.IsPrivateIdentifier(name) { - if c.languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || - c.languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || - !c.compilerOptions.GetUseDefineForClassFields() { + if c.languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks { for lexicalScope := ast.GetEnclosingBlockScopeContainer(node); lexicalScope != nil; lexicalScope = ast.GetEnclosingBlockScopeContainer(lexicalScope) { c.nodeLinks.Get(lexicalScope).flags |= NodeCheckFlagsContainsClassWithPrivateIdentifiers } @@ -11271,9 +11269,8 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l isAnyLike := IsTypeAny(apparentType) || apparentType == c.silentNeverType var prop *ast.Symbol if ast.IsPrivateIdentifier(right) { - if c.languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || - c.languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || - !c.compilerOptions.GetUseDefineForClassFields() { + lexicallyScopedSymbol := c.lookupSymbolForPrivateIdentifierDeclaration(right.Text(), right) + if c.languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || c.isStaticPrivateElementOfDecoratedClass(lexicallyScopedSymbol) { if assignmentKind != AssignmentKindNone { c.checkExternalEmitHelpers(node, ExternalEmitHelpersClassPrivateFieldSet) } @@ -11281,7 +11278,6 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l c.checkExternalEmitHelpers(node, ExternalEmitHelpersClassPrivateFieldGet) } } - lexicallyScopedSymbol := c.lookupSymbolForPrivateIdentifierDeclaration(right.Text(), right) if assignmentKind != AssignmentKindNone && lexicallyScopedSymbol != nil && lexicallyScopedSymbol.ValueDeclaration != nil && ast.IsMethodDeclaration(lexicallyScopedSymbol.ValueDeclaration) { c.grammarErrorOnNode(right, diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, right.Text()) } @@ -11496,6 +11492,21 @@ func (c *Checker) getPrivateIdentifierPropertyOfType(leftType *Type, lexicallySc return c.getPropertyOfType(leftType, lexicallyScopedIdentifier.Name) } +// isStaticPrivateElementOfDecoratedClass reports whether symbol is a static private class element +// (field, method, accessor, or auto-accessor) declared in a class whose native (non-legacy) decorators +// will actually be lowered. Decorator lowering hoists a decorated class's static private elements out +// of the class body into a wrapping closure, which forces accesses to them to use the +// classPrivateField* emit helpers even at targets that otherwise support private fields natively - see +// esDecoratorTransformer's hasStaticPrivateClassElements/shouldTransformPrivateStaticElementsInClass. +func (c *Checker) isStaticPrivateElementOfDecoratedClass(symbol *ast.Symbol) bool { + if symbol == nil || symbol.ValueDeclaration == nil || c.legacyDecorators || !ast.HasStaticModifier(symbol.ValueDeclaration) { + return false + } + class := ast.GetContainingClass(symbol.ValueDeclaration) + return class != nil && ast.HasDecorators(class) && + (c.languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || !c.compilerOptions.GetUseDefineForClassFields()) +} + func (c *Checker) checkPrivateIdentifierPropertyAccess(leftType *Type, right *ast.Node, lexicallyScopedIdentifier *ast.Symbol) bool { // Either the identifier could not be looked up in the lexical scope OR the lexically scoped identifier did not exist on the type. // Find a private identifier with the same description on the type. @@ -13084,14 +13095,13 @@ func (c *Checker) checkInExpression(left *ast.Expression, right *ast.Expression, return c.silentNeverType } if ast.IsPrivateIdentifier(left) { - if c.languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || - c.languageVersion < LanguageFeatureMinimumTarget.ClassAndClassElementDecorators || - !c.compilerOptions.GetUseDefineForClassFields() { + lexicallyScopedSymbol := c.symbolNodeLinks.Get(left).resolvedSymbol + if c.languageVersion < LanguageFeatureMinimumTarget.PrivateNamesAndClassStaticBlocks || c.isStaticPrivateElementOfDecoratedClass(lexicallyScopedSymbol) { c.checkExternalEmitHelpers(left, ExternalEmitHelpersClassPrivateFieldIn) } // Unlike in 'checkPrivateIdentifierExpression' we now have access to the RHS type // which provides us with the opportunity to emit more detailed errors - if c.symbolNodeLinks.Get(left).resolvedSymbol == nil && ast.GetContainingClass(left) != nil { + if lexicallyScopedSymbol == nil && ast.GetContainingClass(left) != nil { isUncheckedJS := c.isUncheckedJSSuggestion(left, rightType.symbol, true /*excludeClasses*/) c.reportNonexistentProperty(left, rightType, isUncheckedJS) } diff --git a/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.js b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.js new file mode 100644 index 00000000000..f700dc1d0a9 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.js @@ -0,0 +1,60 @@ +//// [tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.ts] //// + +//// [main.ts] +export class Foo { + #field = true; + static #staticField = true; + #method() {} + static #staticMethod() {} + get #accessor() { return this.#field; } + set #accessor(v: boolean) { this.#field = v; } + accessor #autoAccessor = true; + static accessor #staticAutoAccessor = true; + static { + Foo.#staticField = true; + } + f() { + this.#field = this.#field; + this.#method(); + Foo.#staticField = Foo.#staticField; + Foo.#staticMethod(); + this.#accessor = this.#accessor; + this.#autoAccessor = this.#autoAccessor; + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; + #field in this; + } +} + + +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Foo = void 0; +class Foo { + #field = true; + static #staticField = true; + #method() { } + static #staticMethod() { } + get #accessor() { return this.#field; } + set #accessor(v) { this.#field = v; } + #autoAccessor_accessor_storage = true; + get #autoAccessor() { return this.#autoAccessor_accessor_storage; } + set #autoAccessor(value) { this.#autoAccessor_accessor_storage = value; } + static #staticAutoAccessor_accessor_storage = true; + static get #staticAutoAccessor() { return Foo.#staticAutoAccessor_accessor_storage; } + static set #staticAutoAccessor(value) { Foo.#staticAutoAccessor_accessor_storage = value; } + static { + Foo.#staticField = true; + } + f() { + this.#field = this.#field; + this.#method(); + Foo.#staticField = Foo.#staticField; + Foo.#staticMethod(); + this.#accessor = this.#accessor; + this.#autoAccessor = this.#autoAccessor; + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; + #field in this; + } +} +exports.Foo = Foo; diff --git a/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.symbols b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.symbols new file mode 100644 index 00000000000..374cd2d4702 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.symbols @@ -0,0 +1,88 @@ +//// [tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.ts] //// + +=== main.ts === +export class Foo { +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + + #field = true; +>#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) + + static #staticField = true; +>#staticField : Symbol(Foo.#staticField, Decl(main.ts, 1, 18)) + + #method() {} +>#method : Symbol(Foo.#method, Decl(main.ts, 2, 31)) + + static #staticMethod() {} +>#staticMethod : Symbol(Foo.#staticMethod, Decl(main.ts, 3, 16)) + + get #accessor() { return this.#field; } +>#accessor : Symbol(Foo.#accessor, Decl(main.ts, 4, 29), Decl(main.ts, 5, 43)) +>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + + set #accessor(v: boolean) { this.#field = v; } +>#accessor : Symbol(Foo.#accessor, Decl(main.ts, 4, 29), Decl(main.ts, 5, 43)) +>v : Symbol(v, Decl(main.ts, 6, 18)) +>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) +>v : Symbol(v, Decl(main.ts, 6, 18)) + + accessor #autoAccessor = true; +>#autoAccessor : Symbol(Foo.#autoAccessor, Decl(main.ts, 6, 50)) + + static accessor #staticAutoAccessor = true; +>#staticAutoAccessor : Symbol(Foo.#staticAutoAccessor, Decl(main.ts, 7, 34)) + + static { + Foo.#staticField = true; +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 1, 18)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + } + f() { +>f : Symbol(Foo.f, Decl(main.ts, 11, 5)) + + this.#field = this.#field; +>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) +>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + + this.#method(); +>this.#method : Symbol(Foo.#method, Decl(main.ts, 2, 31)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + + Foo.#staticField = Foo.#staticField; +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 1, 18)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 1, 18)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + + Foo.#staticMethod(); +>Foo.#staticMethod : Symbol(Foo.#staticMethod, Decl(main.ts, 3, 16)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + + this.#accessor = this.#accessor; +>this.#accessor : Symbol(Foo.#accessor, Decl(main.ts, 4, 29), Decl(main.ts, 5, 43)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) +>this.#accessor : Symbol(Foo.#accessor, Decl(main.ts, 4, 29), Decl(main.ts, 5, 43)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + + this.#autoAccessor = this.#autoAccessor; +>this.#autoAccessor : Symbol(Foo.#autoAccessor, Decl(main.ts, 6, 50)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) +>this.#autoAccessor : Symbol(Foo.#autoAccessor, Decl(main.ts, 6, 50)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; +>Foo.#staticAutoAccessor : Symbol(Foo.#staticAutoAccessor, Decl(main.ts, 7, 34)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) +>Foo.#staticAutoAccessor : Symbol(Foo.#staticAutoAccessor, Decl(main.ts, 7, 34)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + + #field in this; +>#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + } +} + diff --git a/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.types b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.types new file mode 100644 index 00000000000..3562c783c32 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.types @@ -0,0 +1,103 @@ +//// [tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.ts] //// + +=== main.ts === +export class Foo { +>Foo : Foo + + #field = true; +>#field : boolean +>true : true + + static #staticField = true; +>#staticField : boolean +>true : true + + #method() {} +>#method : () => void + + static #staticMethod() {} +>#staticMethod : () => void + + get #accessor() { return this.#field; } +>#accessor : boolean +>this.#field : boolean +>this : this + + set #accessor(v: boolean) { this.#field = v; } +>#accessor : boolean +>v : boolean +>this.#field = v : boolean +>this.#field : boolean +>this : this +>v : boolean + + accessor #autoAccessor = true; +>#autoAccessor : boolean +>true : true + + static accessor #staticAutoAccessor = true; +>#staticAutoAccessor : boolean +>true : true + + static { + Foo.#staticField = true; +>Foo.#staticField = true : true +>Foo.#staticField : boolean +>Foo : typeof Foo +>true : true + } + f() { +>f : () => void + + this.#field = this.#field; +>this.#field = this.#field : boolean +>this.#field : boolean +>this : this +>this.#field : boolean +>this : this + + this.#method(); +>this.#method() : void +>this.#method : () => void +>this : this + + Foo.#staticField = Foo.#staticField; +>Foo.#staticField = Foo.#staticField : boolean +>Foo.#staticField : boolean +>Foo : typeof Foo +>Foo.#staticField : boolean +>Foo : typeof Foo + + Foo.#staticMethod(); +>Foo.#staticMethod() : void +>Foo.#staticMethod : () => void +>Foo : typeof Foo + + this.#accessor = this.#accessor; +>this.#accessor = this.#accessor : boolean +>this.#accessor : boolean +>this : this +>this.#accessor : boolean +>this : this + + this.#autoAccessor = this.#autoAccessor; +>this.#autoAccessor = this.#autoAccessor : boolean +>this.#autoAccessor : boolean +>this : this +>this.#autoAccessor : boolean +>this : this + + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; +>Foo.#staticAutoAccessor = Foo.#staticAutoAccessor : boolean +>Foo.#staticAutoAccessor : boolean +>Foo : typeof Foo +>Foo.#staticAutoAccessor : boolean +>Foo : typeof Foo + + #field in this; +>#field in this : boolean +>#field : any +>this : this + } +} + diff --git a/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.js b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.js new file mode 100644 index 00000000000..852bd21f7d1 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.js @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.ts] //// + +//// [main.ts] +export class Foo { + #field = true; + static #staticField = true; + #method() {} + static #staticMethod() {} + f() { + this.#field = this.#field; + this.#method(); + Foo.#staticField = Foo.#staticField; + Foo.#staticMethod(); + #field in this; + } +} + + +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Foo = void 0; +class Foo { + #field = true; + static #staticField = true; + #method() { } + static #staticMethod() { } + f() { + this.#field = this.#field; + this.#method(); + Foo.#staticField = Foo.#staticField; + Foo.#staticMethod(); + #field in this; + } +} +exports.Foo = Foo; diff --git a/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.symbols b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.symbols new file mode 100644 index 00000000000..a25ba762982 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.symbols @@ -0,0 +1,47 @@ +//// [tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.ts] //// + +=== main.ts === +export class Foo { +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + + #field = true; +>#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) + + static #staticField = true; +>#staticField : Symbol(Foo.#staticField, Decl(main.ts, 1, 18)) + + #method() {} +>#method : Symbol(Foo.#method, Decl(main.ts, 2, 31)) + + static #staticMethod() {} +>#staticMethod : Symbol(Foo.#staticMethod, Decl(main.ts, 3, 16)) + + f() { +>f : Symbol(Foo.f, Decl(main.ts, 4, 29)) + + this.#field = this.#field; +>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) +>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + + this.#method(); +>this.#method : Symbol(Foo.#method, Decl(main.ts, 2, 31)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + + Foo.#staticField = Foo.#staticField; +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 1, 18)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 1, 18)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + + Foo.#staticMethod(); +>Foo.#staticMethod : Symbol(Foo.#staticMethod, Decl(main.ts, 3, 16)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 0)) + + #field in this; +>#field : Symbol(Foo.#field, Decl(main.ts, 0, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 0)) + } +} + diff --git a/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.types b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.types new file mode 100644 index 00000000000..eb5d0654fd7 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.types @@ -0,0 +1,54 @@ +//// [tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.ts] //// + +=== main.ts === +export class Foo { +>Foo : Foo + + #field = true; +>#field : boolean +>true : true + + static #staticField = true; +>#staticField : boolean +>true : true + + #method() {} +>#method : () => void + + static #staticMethod() {} +>#staticMethod : () => void + + f() { +>f : () => void + + this.#field = this.#field; +>this.#field = this.#field : boolean +>this.#field : boolean +>this : this +>this.#field : boolean +>this : this + + this.#method(); +>this.#method() : void +>this.#method : () => void +>this : this + + Foo.#staticField = Foo.#staticField; +>Foo.#staticField = Foo.#staticField : boolean +>Foo.#staticField : boolean +>Foo : typeof Foo +>Foo.#staticField : boolean +>Foo : typeof Foo + + Foo.#staticMethod(); +>Foo.#staticMethod() : void +>Foo.#staticMethod : () => void +>Foo : typeof Foo + + #field in this; +>#field in this : boolean +>#field : any +>this : this + } +} + diff --git a/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.js b/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.js new file mode 100644 index 00000000000..488baa9b1a4 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.js @@ -0,0 +1,32 @@ +//// [tests/cases/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.ts] //// + +//// [main.ts] +export declare var dec: any; + +// At target: esnext with the default useDefineForClassFields: true, native decorators need no +// transform at all (see newESDecoratorTransformer's skip condition), so even a decorated class's +// static private elements stay fully native and never need the classPrivateField* helpers. +@dec +export class Foo { + static #staticField = 1; + static getStaticField() { + return Foo.#staticField; + } +} + + +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Foo = void 0; +// At target: esnext with the default useDefineForClassFields: true, native decorators need no +// transform at all (see newESDecoratorTransformer's skip condition), so even a decorated class's +// static private elements stay fully native and never need the classPrivateField* helpers. +@exports.dec +class Foo { + static #staticField = 1; + static getStaticField() { + return Foo.#staticField; + } +} +exports.Foo = Foo; diff --git a/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.symbols b/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.symbols new file mode 100644 index 00000000000..61fc80a0ec3 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.symbols @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.ts] //// + +=== main.ts === +export declare var dec: any; +>dec : Symbol(dec, Decl(main.ts, 0, 18)) + +// At target: esnext with the default useDefineForClassFields: true, native decorators need no +// transform at all (see newESDecoratorTransformer's skip condition), so even a decorated class's +// static private elements stay fully native and never need the classPrivateField* helpers. +@dec +>dec : Symbol(dec, Decl(main.ts, 0, 18)) + +export class Foo { +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + + static #staticField = 1; +>#staticField : Symbol(Foo.#staticField, Decl(main.ts, 6, 18)) + + static getStaticField() { +>getStaticField : Symbol(Foo.getStaticField, Decl(main.ts, 7, 28)) + + return Foo.#staticField; +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 6, 18)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + } +} + diff --git a/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.types b/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.types new file mode 100644 index 00000000000..24107615a20 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.types @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.ts] //// + +=== main.ts === +export declare var dec: any; +>dec : any + +// At target: esnext with the default useDefineForClassFields: true, native decorators need no +// transform at all (see newESDecoratorTransformer's skip condition), so even a decorated class's +// static private elements stay fully native and never need the classPrivateField* helpers. +@dec +>dec : any + +export class Foo { +>Foo : Foo + + static #staticField = 1; +>#staticField : number +>1 : 1 + + static getStaticField() { +>getStaticField : () => number + + return Foo.#staticField; +>Foo.#staticField : number +>Foo : typeof Foo + } +} + diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.errors.txt b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.errors.txt new file mode 100644 index 00000000000..7babac6827a --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.errors.txt @@ -0,0 +1,54 @@ +main.ts(20,16): error TS2343: This syntax requires an imported helper named '__classPrivateFieldGet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. +main.ts(26,9): error TS2343: This syntax requires an imported helper named '__classPrivateFieldSet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. +main.ts(32,16): error TS2343: This syntax requires an imported helper named '__classPrivateFieldIn' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. + + +==== main.ts (3 errors) ==== + export declare var dec: any; + + // Class decorators hoist a class's static private/auto-accessor elements out of the class body, so + // accessing them still requires the classPrivateField* helpers even at targets (like es2022) that + // otherwise support private fields natively. Instance private fields are unaffected by this and stay + // fully native even in a decorated class. + @dec + export class Foo { + #instanceField = 1; + static #staticField = 1; + static #staticMethod() { return 1; } + static get #staticAccessor() { return 1; } + static set #staticAccessor(v: number) {} + static accessor #staticAutoAccessor = 1; + + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return Foo.#staticField; + ~~~~~~~~~~~~~~~~ +!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldGet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. + } + static callStaticMethod() { + return Foo.#staticMethod(); + } + static useStaticAccessor() { + Foo.#staticAccessor = Foo.#staticAccessor; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldSet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. + } + static useStaticAutoAccessor() { + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; + } + static hasStaticField(x: object) { + return #staticField in x; + ~~~~~~~~~~~~ +!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldIn' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. + } + } + +==== node_modules/tslib/index.d.ts (0 errors) ==== + // Provides only the decorator helpers, deliberately omitting __classPrivateField{Get,Set,In}, to + // confirm that accessing a decorated class's static private elements still requires them. + export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; + export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; + export declare function __setFunctionName(f: any, name: any, prefix?: string): any; + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.js b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.js new file mode 100644 index 00000000000..06eb8b5520f --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.js @@ -0,0 +1,103 @@ +//// [tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.ts] //// + +//// [main.ts] +export declare var dec: any; + +// Class decorators hoist a class's static private/auto-accessor elements out of the class body, so +// accessing them still requires the classPrivateField* helpers even at targets (like es2022) that +// otherwise support private fields natively. Instance private fields are unaffected by this and stay +// fully native even in a decorated class. +@dec +export class Foo { + #instanceField = 1; + static #staticField = 1; + static #staticMethod() { return 1; } + static get #staticAccessor() { return 1; } + static set #staticAccessor(v: number) {} + static accessor #staticAutoAccessor = 1; + + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return Foo.#staticField; + } + static callStaticMethod() { + return Foo.#staticMethod(); + } + static useStaticAccessor() { + Foo.#staticAccessor = Foo.#staticAccessor; + } + static useStaticAutoAccessor() { + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; + } + static hasStaticField(x: object) { + return #staticField in x; + } +} + +//// [index.d.ts] +// Provides only the decorator helpers, deliberately omitting __classPrivateField{Get,Set,In}, to +// confirm that accessing a decorated class's static private elements still requires them. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +export declare function __setFunctionName(f: any, name: any, prefix?: string): any; + + +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Foo = void 0; +const tslib_1 = require("tslib"); +// Class decorators hoist a class's static private/auto-accessor elements out of the class body, so +// accessing them still requires the classPrivateField* helpers even at targets (like es2022) that +// otherwise support private fields natively. Instance private fields are unaffected by this and stay +// fully native even in a decorated class. +let Foo = (() => { + var _Foo_staticField, _Foo_staticMethod, _Foo_staticAccessor_get, _Foo_staticAccessor_set, _Foo_staticAutoAccessor_get, _Foo_staticAutoAccessor_set, _Foo_staticAutoAccessor_accessor_storage; + let _classDecorators = [exports.dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var Foo = class { + static { _classThis = this; } + static { tslib_1.__setFunctionName(this, "Foo"); } + static { _Foo_staticMethod = function _Foo_staticMethod() { return 1; }, _Foo_staticAccessor_get = function _Foo_staticAccessor_get() { return 1; }, _Foo_staticAccessor_set = function _Foo_staticAccessor_set(v) { }, _Foo_staticAutoAccessor_get = function _Foo_staticAutoAccessor_get() { return tslib_1.__classPrivateFieldGet(_classThis, _classThis, "f", _Foo_staticAutoAccessor_accessor_storage); }, _Foo_staticAutoAccessor_set = function _Foo_staticAutoAccessor_set(value) { tslib_1.__classPrivateFieldSet(_classThis, _classThis, value, "f", _Foo_staticAutoAccessor_accessor_storage); }; } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + tslib_1.__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + Foo = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + #instanceField = 1; + static { + _Foo_staticField = { value: 1 }; + } + static { + _Foo_staticAutoAccessor_accessor_storage = { value: 1 }; + } + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return tslib_1.__classPrivateFieldGet(Foo, _classThis, "f", _Foo_staticField); + } + static callStaticMethod() { + return tslib_1.__classPrivateFieldGet(Foo, _classThis, "m", _Foo_staticMethod).call(Foo); + } + static useStaticAccessor() { + tslib_1.__classPrivateFieldSet(Foo, _classThis, tslib_1.__classPrivateFieldGet(Foo, _classThis, "a", _Foo_staticAccessor_get), "a", _Foo_staticAccessor_set); + } + static useStaticAutoAccessor() { + tslib_1.__classPrivateFieldSet(Foo, _classThis, tslib_1.__classPrivateFieldGet(Foo, _classThis, "a", _Foo_staticAutoAccessor_get), "a", _Foo_staticAutoAccessor_set); + } + static hasStaticField(x) { + return tslib_1.__classPrivateFieldIn(_classThis, x); + } + static { + tslib_1.__runInitializers(_classThis, _classExtraInitializers); + } + }; + return Foo = _classThis; +})(); +exports.Foo = Foo; diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.symbols b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.symbols new file mode 100644 index 00000000000..45a2a7150a9 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.symbols @@ -0,0 +1,108 @@ +//// [tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.ts] //// + +=== main.ts === +export declare var dec: any; +>dec : Symbol(dec, Decl(main.ts, 0, 18)) + +// Class decorators hoist a class's static private/auto-accessor elements out of the class body, so +// accessing them still requires the classPrivateField* helpers even at targets (like es2022) that +// otherwise support private fields natively. Instance private fields are unaffected by this and stay +// fully native even in a decorated class. +@dec +>dec : Symbol(dec, Decl(main.ts, 0, 18)) + +export class Foo { +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + + #instanceField = 1; +>#instanceField : Symbol(Foo.#instanceField, Decl(main.ts, 7, 18)) + + static #staticField = 1; +>#staticField : Symbol(Foo.#staticField, Decl(main.ts, 8, 23)) + + static #staticMethod() { return 1; } +>#staticMethod : Symbol(Foo.#staticMethod, Decl(main.ts, 9, 28)) + + static get #staticAccessor() { return 1; } +>#staticAccessor : Symbol(Foo.#staticAccessor, Decl(main.ts, 10, 40), Decl(main.ts, 11, 46)) + + static set #staticAccessor(v: number) {} +>#staticAccessor : Symbol(Foo.#staticAccessor, Decl(main.ts, 10, 40), Decl(main.ts, 11, 46)) +>v : Symbol(v, Decl(main.ts, 12, 31)) + + static accessor #staticAutoAccessor = 1; +>#staticAutoAccessor : Symbol(Foo.#staticAutoAccessor, Decl(main.ts, 12, 44)) + + getInstanceField() { +>getInstanceField : Symbol(Foo.getInstanceField, Decl(main.ts, 13, 44)) + + return this.#instanceField; +>this.#instanceField : Symbol(Foo.#instanceField, Decl(main.ts, 7, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 28)) + } + static getStaticField() { +>getStaticField : Symbol(Foo.getStaticField, Decl(main.ts, 17, 5)) + + return Foo.#staticField; +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 8, 23)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + } + static callStaticMethod() { +>callStaticMethod : Symbol(Foo.callStaticMethod, Decl(main.ts, 20, 5)) + + return Foo.#staticMethod(); +>Foo.#staticMethod : Symbol(Foo.#staticMethod, Decl(main.ts, 9, 28)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + } + static useStaticAccessor() { +>useStaticAccessor : Symbol(Foo.useStaticAccessor, Decl(main.ts, 23, 5)) + + Foo.#staticAccessor = Foo.#staticAccessor; +>Foo.#staticAccessor : Symbol(Foo.#staticAccessor, Decl(main.ts, 10, 40), Decl(main.ts, 11, 46)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) +>Foo.#staticAccessor : Symbol(Foo.#staticAccessor, Decl(main.ts, 10, 40), Decl(main.ts, 11, 46)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + } + static useStaticAutoAccessor() { +>useStaticAutoAccessor : Symbol(Foo.useStaticAutoAccessor, Decl(main.ts, 26, 5)) + + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; +>Foo.#staticAutoAccessor : Symbol(Foo.#staticAutoAccessor, Decl(main.ts, 12, 44)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) +>Foo.#staticAutoAccessor : Symbol(Foo.#staticAutoAccessor, Decl(main.ts, 12, 44)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + } + static hasStaticField(x: object) { +>hasStaticField : Symbol(Foo.hasStaticField, Decl(main.ts, 29, 5)) +>x : Symbol(x, Decl(main.ts, 30, 26)) + + return #staticField in x; +>#staticField : Symbol(Foo.#staticField, Decl(main.ts, 8, 23)) +>x : Symbol(x, Decl(main.ts, 30, 26)) + } +} + +=== node_modules/tslib/index.d.ts === +// Provides only the decorator helpers, deliberately omitting __classPrivateField{Get,Set,In}, to +// confirm that accessing a decorated class's static private elements still requires them. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +>__esDecorate : Symbol(__esDecorate, Decl(index.d.ts, 0, 0)) +>ctor : Symbol(ctor, Decl(index.d.ts, 2, 37)) +>descriptorIn : Symbol(descriptorIn, Decl(index.d.ts, 2, 47)) +>decorators : Symbol(decorators, Decl(index.d.ts, 2, 66)) +>contextIn : Symbol(contextIn, Decl(index.d.ts, 2, 85)) +>initializers : Symbol(initializers, Decl(index.d.ts, 2, 101)) +>extraInitializers : Symbol(extraInitializers, Decl(index.d.ts, 2, 120)) + +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +>__runInitializers : Symbol(__runInitializers, Decl(index.d.ts, 2, 151)) +>thisArg : Symbol(thisArg, Decl(index.d.ts, 3, 42)) +>initializers : Symbol(initializers, Decl(index.d.ts, 3, 55)) +>value : Symbol(value, Decl(index.d.ts, 3, 76)) + +export declare function __setFunctionName(f: any, name: any, prefix?: string): any; +>__setFunctionName : Symbol(__setFunctionName, Decl(index.d.ts, 3, 95)) +>f : Symbol(f, Decl(index.d.ts, 4, 42)) +>name : Symbol(name, Decl(index.d.ts, 4, 49)) +>prefix : Symbol(prefix, Decl(index.d.ts, 4, 60)) + diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.types b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.types new file mode 100644 index 00000000000..c148d2bd5ca --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.types @@ -0,0 +1,117 @@ +//// [tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.ts] //// + +=== main.ts === +export declare var dec: any; +>dec : any + +// Class decorators hoist a class's static private/auto-accessor elements out of the class body, so +// accessing them still requires the classPrivateField* helpers even at targets (like es2022) that +// otherwise support private fields natively. Instance private fields are unaffected by this and stay +// fully native even in a decorated class. +@dec +>dec : any + +export class Foo { +>Foo : Foo + + #instanceField = 1; +>#instanceField : number +>1 : 1 + + static #staticField = 1; +>#staticField : number +>1 : 1 + + static #staticMethod() { return 1; } +>#staticMethod : () => number +>1 : 1 + + static get #staticAccessor() { return 1; } +>#staticAccessor : number +>1 : 1 + + static set #staticAccessor(v: number) {} +>#staticAccessor : number +>v : number + + static accessor #staticAutoAccessor = 1; +>#staticAutoAccessor : number +>1 : 1 + + getInstanceField() { +>getInstanceField : () => number + + return this.#instanceField; +>this.#instanceField : number +>this : this + } + static getStaticField() { +>getStaticField : () => number + + return Foo.#staticField; +>Foo.#staticField : number +>Foo : typeof Foo + } + static callStaticMethod() { +>callStaticMethod : () => number + + return Foo.#staticMethod(); +>Foo.#staticMethod() : number +>Foo.#staticMethod : () => number +>Foo : typeof Foo + } + static useStaticAccessor() { +>useStaticAccessor : () => void + + Foo.#staticAccessor = Foo.#staticAccessor; +>Foo.#staticAccessor = Foo.#staticAccessor : number +>Foo.#staticAccessor : number +>Foo : typeof Foo +>Foo.#staticAccessor : number +>Foo : typeof Foo + } + static useStaticAutoAccessor() { +>useStaticAutoAccessor : () => void + + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; +>Foo.#staticAutoAccessor = Foo.#staticAutoAccessor : number +>Foo.#staticAutoAccessor : number +>Foo : typeof Foo +>Foo.#staticAutoAccessor : number +>Foo : typeof Foo + } + static hasStaticField(x: object) { +>hasStaticField : (x: object) => x is typeof Foo +>x : object + + return #staticField in x; +>#staticField in x : boolean +>#staticField : any +>x : object + } +} + +=== node_modules/tslib/index.d.ts === +// Provides only the decorator helpers, deliberately omitting __classPrivateField{Get,Set,In}, to +// confirm that accessing a decorated class's static private elements still requires them. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +>__esDecorate : (ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any) => void +>ctor : any +>descriptorIn : any +>decorators : any[] +>contextIn : any +>initializers : any +>extraInitializers : any + +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +>__runInitializers : (thisArg: any, initializers: any[], value?: any) => any +>thisArg : any +>initializers : any[] +>value : any + +export declare function __setFunctionName(f: any, name: any, prefix?: string): any; +>__setFunctionName : (f: any, name: any, prefix?: string) => any +>f : any +>name : any +>prefix : string | undefined + diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.errors.txt b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.errors.txt new file mode 100644 index 00000000000..876cf138b79 --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.errors.txt @@ -0,0 +1,32 @@ +main.ts(16,16): error TS2343: This syntax requires an imported helper named '__classPrivateFieldGet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. + + +==== main.ts (1 errors) ==== + export declare var dec: any; + + // At useDefineForClassFields: false, native decorators are still lowered even at esnext (this is the + // one case where the esnext decorator transform isn't skipped by target alone - see + // newESDecoratorTransformer's skip condition), so a decorated class's static private elements still + // need the classPrivateField* helpers here too. + @dec + export class Foo { + #instanceField = 1; + static #staticField = 1; + + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return Foo.#staticField; + ~~~~~~~~~~~~~~~~ +!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldGet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'. + } + } + +==== node_modules/tslib/index.d.ts (0 errors) ==== + // Provides only the decorator helpers, deliberately omitting __classPrivateFieldGet, to confirm that + // accessing the decorated class's static private field still requires it. + export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; + export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; + export declare function __setFunctionName(f: any, name: any, prefix?: string): any; + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.js b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.js new file mode 100644 index 00000000000..bc2c3ec7a2f --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.js @@ -0,0 +1,71 @@ +//// [tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.ts] //// + +//// [main.ts] +export declare var dec: any; + +// At useDefineForClassFields: false, native decorators are still lowered even at esnext (this is the +// one case where the esnext decorator transform isn't skipped by target alone - see +// newESDecoratorTransformer's skip condition), so a decorated class's static private elements still +// need the classPrivateField* helpers here too. +@dec +export class Foo { + #instanceField = 1; + static #staticField = 1; + + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return Foo.#staticField; + } +} + +//// [index.d.ts] +// Provides only the decorator helpers, deliberately omitting __classPrivateFieldGet, to confirm that +// accessing the decorated class's static private field still requires it. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +export declare function __setFunctionName(f: any, name: any, prefix?: string): any; + + +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Foo = void 0; +const tslib_1 = require("tslib"); +// At useDefineForClassFields: false, native decorators are still lowered even at esnext (this is the +// one case where the esnext decorator transform isn't skipped by target alone - see +// newESDecoratorTransformer's skip condition), so a decorated class's static private elements still +// need the classPrivateField* helpers here too. +let Foo = (() => { + var _Foo_staticField; + let _classDecorators = [exports.dec]; + let _classDescriptor; + let _classExtraInitializers = []; + let _classThis; + var Foo = class { + static { _classThis = this; } + static { tslib_1.__setFunctionName(this, "Foo"); } + static { + const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; + tslib_1.__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); + Foo = _classThis = _classDescriptor.value; + if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); + } + #instanceField = 1; + static { + _Foo_staticField = { value: 1 }; + } + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return tslib_1.__classPrivateFieldGet(Foo, _classThis, "f", _Foo_staticField); + } + static { + tslib_1.__runInitializers(_classThis, _classExtraInitializers); + } + }; + return Foo = _classThis; +})(); +exports.Foo = Foo; diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.symbols b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.symbols new file mode 100644 index 00000000000..630451a0f4f --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.symbols @@ -0,0 +1,62 @@ +//// [tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.ts] //// + +=== main.ts === +export declare var dec: any; +>dec : Symbol(dec, Decl(main.ts, 0, 18)) + +// At useDefineForClassFields: false, native decorators are still lowered even at esnext (this is the +// one case where the esnext decorator transform isn't skipped by target alone - see +// newESDecoratorTransformer's skip condition), so a decorated class's static private elements still +// need the classPrivateField* helpers here too. +@dec +>dec : Symbol(dec, Decl(main.ts, 0, 18)) + +export class Foo { +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + + #instanceField = 1; +>#instanceField : Symbol(Foo.#instanceField, Decl(main.ts, 7, 18)) + + static #staticField = 1; +>#staticField : Symbol(Foo.#staticField, Decl(main.ts, 8, 23)) + + getInstanceField() { +>getInstanceField : Symbol(Foo.getInstanceField, Decl(main.ts, 9, 28)) + + return this.#instanceField; +>this.#instanceField : Symbol(Foo.#instanceField, Decl(main.ts, 7, 18)) +>this : Symbol(Foo, Decl(main.ts, 0, 28)) + } + static getStaticField() { +>getStaticField : Symbol(Foo.getStaticField, Decl(main.ts, 13, 5)) + + return Foo.#staticField; +>Foo.#staticField : Symbol(Foo.#staticField, Decl(main.ts, 8, 23)) +>Foo : Symbol(Foo, Decl(main.ts, 0, 28)) + } +} + +=== node_modules/tslib/index.d.ts === +// Provides only the decorator helpers, deliberately omitting __classPrivateFieldGet, to confirm that +// accessing the decorated class's static private field still requires it. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +>__esDecorate : Symbol(__esDecorate, Decl(index.d.ts, 0, 0)) +>ctor : Symbol(ctor, Decl(index.d.ts, 2, 37)) +>descriptorIn : Symbol(descriptorIn, Decl(index.d.ts, 2, 47)) +>decorators : Symbol(decorators, Decl(index.d.ts, 2, 66)) +>contextIn : Symbol(contextIn, Decl(index.d.ts, 2, 85)) +>initializers : Symbol(initializers, Decl(index.d.ts, 2, 101)) +>extraInitializers : Symbol(extraInitializers, Decl(index.d.ts, 2, 120)) + +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +>__runInitializers : Symbol(__runInitializers, Decl(index.d.ts, 2, 151)) +>thisArg : Symbol(thisArg, Decl(index.d.ts, 3, 42)) +>initializers : Symbol(initializers, Decl(index.d.ts, 3, 55)) +>value : Symbol(value, Decl(index.d.ts, 3, 76)) + +export declare function __setFunctionName(f: any, name: any, prefix?: string): any; +>__setFunctionName : Symbol(__setFunctionName, Decl(index.d.ts, 3, 95)) +>f : Symbol(f, Decl(index.d.ts, 4, 42)) +>name : Symbol(name, Decl(index.d.ts, 4, 49)) +>prefix : Symbol(prefix, Decl(index.d.ts, 4, 60)) + diff --git a/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.types b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.types new file mode 100644 index 00000000000..a9e6984f1bf --- /dev/null +++ b/testdata/baselines/reference/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.types @@ -0,0 +1,64 @@ +//// [tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.ts] //// + +=== main.ts === +export declare var dec: any; +>dec : any + +// At useDefineForClassFields: false, native decorators are still lowered even at esnext (this is the +// one case where the esnext decorator transform isn't skipped by target alone - see +// newESDecoratorTransformer's skip condition), so a decorated class's static private elements still +// need the classPrivateField* helpers here too. +@dec +>dec : any + +export class Foo { +>Foo : Foo + + #instanceField = 1; +>#instanceField : number +>1 : 1 + + static #staticField = 1; +>#staticField : number +>1 : 1 + + getInstanceField() { +>getInstanceField : () => number + + return this.#instanceField; +>this.#instanceField : number +>this : this + } + static getStaticField() { +>getStaticField : () => number + + return Foo.#staticField; +>Foo.#staticField : number +>Foo : typeof Foo + } +} + +=== node_modules/tslib/index.d.ts === +// Provides only the decorator helpers, deliberately omitting __classPrivateFieldGet, to confirm that +// accessing the decorated class's static private field still requires it. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +>__esDecorate : (ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any) => void +>ctor : any +>descriptorIn : any +>decorators : any[] +>contextIn : any +>initializers : any +>extraInitializers : any + +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +>__runInitializers : (thisArg: any, initializers: any[], value?: any) => any +>thisArg : any +>initializers : any[] +>value : any + +export declare function __setFunctionName(f: any, name: any, prefix?: string): any; +>__setFunctionName : (f: any, name: any, prefix?: string) => any +>f : any +>name : any +>prefix : string | undefined + diff --git a/testdata/tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.ts b/testdata/tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.ts new file mode 100644 index 00000000000..1a33ef6f52a --- /dev/null +++ b/testdata/tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022.ts @@ -0,0 +1,28 @@ +// @importHelpers: true +// @target: es2022 +// @module: commonjs +// @lib: esnext +// @filename: main.ts +export class Foo { + #field = true; + static #staticField = true; + #method() {} + static #staticMethod() {} + get #accessor() { return this.#field; } + set #accessor(v: boolean) { this.#field = v; } + accessor #autoAccessor = true; + static accessor #staticAutoAccessor = true; + static { + Foo.#staticField = true; + } + f() { + this.#field = this.#field; + this.#method(); + Foo.#staticField = Foo.#staticField; + Foo.#staticMethod(); + this.#accessor = this.#accessor; + this.#autoAccessor = this.#autoAccessor; + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; + #field in this; + } +} diff --git a/testdata/tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.ts b/testdata/tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.ts new file mode 100644 index 00000000000..9d65f9e9abc --- /dev/null +++ b/testdata/tests/cases/compiler/importHelpersNoHelpersForPrivateFieldsAtES2022UseDefineForClassFieldsFalse.ts @@ -0,0 +1,18 @@ +// @importHelpers: true +// @target: es2022 +// @useDefineForClassFields: false +// @module: commonjs +// @filename: main.ts +export class Foo { + #field = true; + static #staticField = true; + #method() {} + static #staticMethod() {} + f() { + this.#field = this.#field; + this.#method(); + Foo.#staticField = Foo.#staticField; + Foo.#staticMethod(); + #field in this; + } +} diff --git a/testdata/tests/cases/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.ts b/testdata/tests/cases/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.ts new file mode 100644 index 00000000000..2f4ef532634 --- /dev/null +++ b/testdata/tests/cases/compiler/importHelpersNotRequiredForDecoratedStaticPrivateElementsAtESNext.ts @@ -0,0 +1,16 @@ +// @importHelpers: true +// @target: esnext +// @module: commonjs +// @filename: main.ts +export declare var dec: any; + +// At target: esnext with the default useDefineForClassFields: true, native decorators need no +// transform at all (see newESDecoratorTransformer's skip condition), so even a decorated class's +// static private elements stay fully native and never need the classPrivateField* helpers. +@dec +export class Foo { + static #staticField = 1; + static getStaticField() { + return Foo.#staticField; + } +} diff --git a/testdata/tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.ts b/testdata/tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.ts new file mode 100644 index 00000000000..aecb8abd737 --- /dev/null +++ b/testdata/tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElements.ts @@ -0,0 +1,45 @@ +// @importHelpers: true +// @target: es2022 +// @module: commonjs +// @filename: main.ts +export declare var dec: any; + +// Class decorators hoist a class's static private/auto-accessor elements out of the class body, so +// accessing them still requires the classPrivateField* helpers even at targets (like es2022) that +// otherwise support private fields natively. Instance private fields are unaffected by this and stay +// fully native even in a decorated class. +@dec +export class Foo { + #instanceField = 1; + static #staticField = 1; + static #staticMethod() { return 1; } + static get #staticAccessor() { return 1; } + static set #staticAccessor(v: number) {} + static accessor #staticAutoAccessor = 1; + + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return Foo.#staticField; + } + static callStaticMethod() { + return Foo.#staticMethod(); + } + static useStaticAccessor() { + Foo.#staticAccessor = Foo.#staticAccessor; + } + static useStaticAutoAccessor() { + Foo.#staticAutoAccessor = Foo.#staticAutoAccessor; + } + static hasStaticField(x: object) { + return #staticField in x; + } +} + +// @filename: node_modules/tslib/index.d.ts +// Provides only the decorator helpers, deliberately omitting __classPrivateField{Get,Set,In}, to +// confirm that accessing a decorated class's static private elements still requires them. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +export declare function __setFunctionName(f: any, name: any, prefix?: string): any; diff --git a/testdata/tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.ts b/testdata/tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.ts new file mode 100644 index 00000000000..d7fb3003e50 --- /dev/null +++ b/testdata/tests/cases/compiler/importHelpersRequiredForDecoratedStaticPrivateElementsUseDefineForClassFieldsFalse.ts @@ -0,0 +1,30 @@ +// @importHelpers: true +// @target: esnext +// @useDefineForClassFields: false +// @module: commonjs +// @filename: main.ts +export declare var dec: any; + +// At useDefineForClassFields: false, native decorators are still lowered even at esnext (this is the +// one case where the esnext decorator transform isn't skipped by target alone - see +// newESDecoratorTransformer's skip condition), so a decorated class's static private elements still +// need the classPrivateField* helpers here too. +@dec +export class Foo { + #instanceField = 1; + static #staticField = 1; + + getInstanceField() { + return this.#instanceField; + } + static getStaticField() { + return Foo.#staticField; + } +} + +// @filename: node_modules/tslib/index.d.ts +// Provides only the decorator helpers, deliberately omitting __classPrivateFieldGet, to confirm that +// accessing the decorated class's static private field still requires it. +export declare function __esDecorate(ctor: any, descriptorIn: any, decorators: any[], contextIn: any, initializers: any, extraInitializers: any): void; +export declare function __runInitializers(thisArg: any, initializers: any[], value?: any): any; +export declare function __setFunctionName(f: any, name: any, prefix?: string): any;