Fix private name generation and missing emit for auto-accessors (#52132)

This commit is contained in:
Ron Buckton
2023-01-06 21:08:51 -05:00
committed by GitHub
parent f1ff0de943
commit 90fb764a0f
19 changed files with 723 additions and 106 deletions
+91 -20
View File
@@ -1365,8 +1365,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
let privateNameTempFlags: TempFlags; // TempFlags for the current name generation scope.
let tempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes.
let tempFlags: TempFlags; // TempFlags for the current name generation scope.
let reservedNamesStack: Set<string>[]; // Stack of TempFlags reserved in enclosing name generation scopes.
let reservedNames: Set<string>; // TempFlags to reserve in nested name generation scopes.
let reservedNamesStack: (Set<string> | undefined)[]; // Stack of reserved names in enclosing name generation scopes.
let reservedNames: Set<string> | undefined; // Names reserved in nested name generation scopes.
let reservedPrivateNamesStack: (Set<string> | undefined)[]; // Stack of reserved member names in enclosing name generation scopes.
let reservedPrivateNames: Set<string> | undefined; // Member names reserved in nested name generation scopes.
let preserveSourceNewlines = printerOptions.preserveSourceNewlines; // Can be overridden inside nodes with the `IgnoreSourceNewlines` emit flag.
let nextListElementPos: number | undefined; // See comment in `getLeadingLineTerminatorCount`.
@@ -1658,6 +1660,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
tempFlagsStack = [];
tempFlags = TempFlags.Auto;
reservedNamesStack = [];
reservedNames = undefined;
reservedPrivateNamesStack = [];
reservedPrivateNames = undefined;
currentSourceFile = undefined;
currentLineMap = undefined;
detachedCommentsInfo = undefined;
@@ -2501,9 +2506,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
function emitComputedPropertyName(node: ComputedPropertyName) {
const savedPrivateNameTempFlags = privateNameTempFlags;
const savedReservedMemberNames = reservedPrivateNames;
popPrivateNameGenerationScope();
writePunctuation("[");
emitExpression(node.expression, parenthesizer.parenthesizeExpressionOfComputedPropertyName);
writePunctuation("]");
pushPrivateNameGenerationScope(savedPrivateNameTempFlags, savedReservedMemberNames);
}
//
@@ -2723,10 +2732,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
function emitTypeLiteral(node: TypeLiteralNode) {
// Type literals don't have private names, but we need to push a new scope so that
// we can step out of it when emitting a computed property.
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
writePunctuation("{");
const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers;
emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty);
writePunctuation("}");
popPrivateNameGenerationScope();
}
function emitArrayType(node: ArrayTypeNode) {
@@ -2943,6 +2958,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
// Object literals don't have private names, but we need to push a new scope so that
// we can step out of it when emitting a computed property.
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
forEach(node.properties, generateMemberNames);
const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
@@ -2957,6 +2975,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
if (indentedFlag) {
decreaseIndent();
}
popPrivateNameGenerationScope();
}
function emitPropertyAccessExpression(node: PropertyAccessExpression) {
@@ -3763,6 +3783,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) {
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
forEach(node.members, generateMemberNames);
emitDecoratorsAndModifiers(node, node.modifiers);
@@ -3788,9 +3810,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
if (indentedFlag) {
decreaseIndent();
}
popPrivateNameGenerationScope();
}
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
// Interfaces don't have private names, but we need to push a new scope so that
// we can step out of it when emitting a computed property.
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
emitModifiers(node, node.modifiers);
writeKeyword("interface");
writeSpace();
@@ -3801,6 +3829,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
writePunctuation("{");
emitList(node, node.members, ListFormat.InterfaceMembers);
writePunctuation("}");
popPrivateNameGenerationScope();
}
function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
@@ -5486,8 +5516,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
tempFlagsStack.push(tempFlags);
tempFlags = TempFlags.Auto;
privateNameTempFlagsStack.push(privateNameTempFlags);
privateNameTempFlags = TempFlags.Auto;
formattedNameTempFlagsStack.push(formattedNameTempFlags);
formattedNameTempFlags = undefined;
reservedNamesStack.push(reservedNames);
@@ -5501,9 +5529,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
return;
}
tempFlags = tempFlagsStack.pop()!;
privateNameTempFlags = privateNameTempFlagsStack.pop()!;
formattedNameTempFlags = formattedNameTempFlagsStack.pop();
reservedNames = reservedNamesStack.pop()!;
reservedNames = reservedNamesStack.pop();
}
function reserveNameInNestedScopes(name: string) {
@@ -5513,6 +5540,31 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
reservedNames.add(name);
}
/**
* Push a new member name generation scope.
*/
function pushPrivateNameGenerationScope(newPrivateNameTempFlags: TempFlags, newReservedMemberNames: Set<string> | undefined) {
privateNameTempFlagsStack.push(privateNameTempFlags);
privateNameTempFlags = newPrivateNameTempFlags;
reservedPrivateNamesStack.push(reservedNames);
reservedPrivateNames = newReservedMemberNames;
}
/**
* Pop the current member name generation scope.
*/
function popPrivateNameGenerationScope() {
privateNameTempFlags = privateNameTempFlagsStack.pop()!;
reservedPrivateNames = reservedPrivateNamesStack.pop();
}
function reservePrivateNameInNestedScopes(name: string) {
if (!reservedPrivateNames || reservedPrivateNames === lastOrUndefined(reservedPrivateNamesStack)) {
reservedPrivateNames = new Set();
}
reservedPrivateNames.add(name);
}
function generateNames(node: Node | undefined) {
if (!node) return;
switch (node.kind) {
@@ -5650,16 +5702,23 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
* Returns a value indicating whether a name is unique globally, within the current file,
* or within the NameGenerator.
*/
function isUniqueName(name: string): boolean {
return isFileLevelUniqueName(name)
&& !generatedNames.has(name)
&& !(reservedNames && reservedNames.has(name));
function isUniqueName(name: string, privateName: boolean): boolean {
return isFileLevelUniqueName(name, privateName)
&& !isReservedName(name, privateName)
&& !generatedNames.has(name);
}
function isReservedName(name: string, privateName: boolean): boolean {
return privateName ? !!reservedPrivateNames?.has(name) : !!reservedNames?.has(name);
}
/**
* Returns a value indicating whether a name is unique globally or within the current file.
*
* @param _isPrivate (unused) this parameter exists to avoid an unnecessary adaptor frame in v8
* when `isfileLevelUniqueName` is passed as a callback to `makeUniqueName`.
*/
function isFileLevelUniqueName(name: string) {
function isFileLevelUniqueName(name: string, _isPrivate: boolean) {
return currentSourceFile ? ts.isFileLevelUniqueName(currentSourceFile, name, hasGlobalName) : true;
}
@@ -5722,9 +5781,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
if (flags && !(tempFlags & flags)) {
const name = flags === TempFlags._i ? "_i" : "_n";
const fullName = formatGeneratedName(privateName, prefix, name, suffix);
if (isUniqueName(fullName)) {
if (isUniqueName(fullName, privateName)) {
tempFlags |= flags;
if (reservedInNestedScopes) {
if (privateName) {
reservePrivateNameInNestedScopes(fullName);
}
else if (reservedInNestedScopes) {
reserveNameInNestedScopes(fullName);
}
setTempFlags(key, tempFlags);
@@ -5741,8 +5803,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
? "_" + String.fromCharCode(CharacterCodes.a + count)
: "_" + (count - 26);
const fullName = formatGeneratedName(privateName, prefix, name, suffix);
if (isUniqueName(fullName)) {
if (reservedInNestedScopes) {
if (isUniqueName(fullName, privateName)) {
if (privateName) {
reservePrivateNameInNestedScopes(fullName);
}
else if (reservedInNestedScopes) {
reserveNameInNestedScopes(fullName);
}
setTempFlags(key, tempFlags);
@@ -5759,7 +5824,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
* makeUniqueName are guaranteed to never conflict.
* If `optimistic` is set, the first instance will use 'baseName' verbatim instead of 'baseName_1'
*/
function makeUniqueName(baseName: string, checkFn: (name: string) => boolean = isUniqueName, optimistic: boolean, scoped: boolean, privateName: boolean, prefix: string, suffix: string): string {
function makeUniqueName(baseName: string, checkFn: (name: string, privateName: boolean) => boolean = isUniqueName, optimistic: boolean, scoped: boolean, privateName: boolean, prefix: string, suffix: string): string {
if (baseName.length > 0 && baseName.charCodeAt(0) === CharacterCodes.hash) {
baseName = baseName.slice(1);
}
@@ -5768,8 +5833,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
if (optimistic) {
const fullName = formatGeneratedName(privateName, prefix, baseName, suffix);
if (checkFn(fullName)) {
if (scoped) {
if (checkFn(fullName, privateName)) {
if (privateName) {
reservePrivateNameInNestedScopes(fullName);
}
else if (scoped) {
reserveNameInNestedScopes(fullName);
}
else {
@@ -5785,8 +5853,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
let i = 1;
while (true) {
const fullName = formatGeneratedName(privateName, prefix, baseName + i, suffix);
if (checkFn(fullName)) {
if (scoped) {
if (checkFn(fullName, privateName)) {
if (privateName) {
reservePrivateNameInNestedScopes(fullName);
}
else if (scoped) {
reserveNameInNestedScopes(fullName);
}
else {
+1 -11
View File
@@ -1454,7 +1454,6 @@ namespace Parser {
let currentToken: SyntaxKind;
let nodeCount: number;
let identifiers: Map<string, string>;
let privateIdentifiers: Map<string, string>;
let identifierCount: number;
let parsingContext: ParsingContext;
@@ -1681,7 +1680,6 @@ namespace Parser {
parseDiagnostics = [];
parsingContext = 0;
identifiers = new Map<string, string>();
privateIdentifiers = new Map<string, string>();
identifierCount = 0;
nodeCount = 0;
sourceFlags = 0;
@@ -2661,17 +2659,9 @@ namespace Parser {
return finishNode(factory.createComputedPropertyName(expression), pos);
}
function internPrivateIdentifier(text: string): string {
let privateIdentifier = privateIdentifiers.get(text);
if (privateIdentifier === undefined) {
privateIdentifiers.set(text, privateIdentifier = text);
}
return privateIdentifier;
}
function parsePrivateIdentifier(): PrivateIdentifier {
const pos = getNodePos();
const node = factory.createPrivateIdentifier(internPrivateIdentifier(scanner.getTokenValue()));
const node = factory.createPrivateIdentifier(internIdentifier(scanner.getTokenValue()));
nextToken();
return finishNode(node, pos);
}
+62 -32
View File
@@ -155,6 +155,7 @@ import {
SuperProperty,
SyntaxKind,
TaggedTemplateExpression,
Ternary,
ThisExpression,
TransformationContext,
TransformFlags,
@@ -293,6 +294,7 @@ const enum ClassFacts {
NeedsClassConstructorReference = 1 << 1,
NeedsClassSuperReference = 1 << 2,
NeedsSubstitutionForThisInClassStaticField = 1 << 3,
WillHoistInitializersToConstructor = 1 << 4,
}
/**
@@ -328,8 +330,12 @@ export function transformClassFields(context: TransformationContext): (x: Source
// We need to transform private members and class static blocks when target < ES2022.
const shouldTransformPrivateElementsOrClassStaticBlocks = languageVersion < ScriptTarget.ES2022;
// We need to transform `accessor` fields when target < ESNext
const shouldTransformAutoAccessors = languageVersion < ScriptTarget.ESNext;
// We need to transform `accessor` fields when target < ESNext.
// We may need to transform `accessor` fields when `useDefineForClassFields: false`
const shouldTransformAutoAccessors =
languageVersion < ScriptTarget.ESNext ? Ternary.True :
!useDefineForClassFields ? Ternary.Maybe :
Ternary.False;
// We need to transform `this` in a static initializer into a reference to the class
// when target < ES2022 since the assignment will be moved outside of the class body.
@@ -342,7 +348,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
const shouldTransformAnything =
shouldTransformInitializers ||
shouldTransformPrivateElementsOrClassStaticBlocks ||
shouldTransformAutoAccessors;
shouldTransformAutoAccessors === Ternary.True;
const previousOnSubstituteNode = context.onSubstituteNode;
context.onSubstituteNode = onSubstituteNode;
@@ -394,7 +400,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
switch (node.kind) {
case SyntaxKind.AccessorKeyword:
return shouldTransformAutoAccessors ? undefined : node;
return shouldTransformAutoAccessorsInCurrentClass() ? undefined : node;
case SyntaxKind.ClassDeclaration:
return visitClassDeclaration(node as ClassDeclaration);
case SyntaxKind.ClassExpression:
@@ -730,7 +736,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
return info.isValid ? undefined : node;
}
if (shouldTransformInitializersUsingSet && !isStatic(node)) {
if (shouldTransformInitializersUsingSet && !isStatic(node) && currentClassLexicalEnvironment && currentClassLexicalEnvironment.facts & ClassFacts.WillHoistInitializersToConstructor) {
// If we are transforming initializers using Set semantics we will elide the initializer as it will
// be moved to the constructor to preserve evaluation order next to public instance fields. We don't
// need to do this transformation for private static fields since public static fields can be
@@ -749,7 +755,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
}
function transformPublicFieldInitializer(node: PropertyDeclaration) {
if (shouldTransformInitializers) {
if (shouldTransformInitializers && !isAutoAccessorPropertyDeclaration(node)) {
// Create a temporary variable to store a computed property name (if necessary).
// If it's not inlineable, then we emit an expression after the class which assigns
// the property name to the temporary variable.
@@ -791,10 +797,16 @@ export function transformClassFields(context: TransformationContext): (x: Source
transformPublicFieldInitializer(node);
}
function shouldTransformAutoAccessorsInCurrentClass() {
return shouldTransformAutoAccessors === Ternary.True ||
shouldTransformAutoAccessors === Ternary.Maybe &&
!!currentClassLexicalEnvironment && !!(currentClassLexicalEnvironment.facts & ClassFacts.WillHoistInitializersToConstructor);
}
function visitPropertyDeclaration(node: PropertyDeclaration) {
// If this is an auto-accessor, we defer to `transformAutoAccessor`. That function
// will in turn call `transformFieldInitializer` as needed.
if (shouldTransformAutoAccessors && isAutoAccessorPropertyDeclaration(node)) {
if (shouldTransformAutoAccessorsInCurrentClass() && isAutoAccessorPropertyDeclaration(node)) {
return transformAutoAccessor(node);
}
@@ -1289,25 +1301,54 @@ export function transformClassFields(context: TransformationContext): (x: Source
if (isClassDeclaration(original) && classOrConstructorParameterIsDecorated(original)) {
facts |= ClassFacts.ClassWasDecorated;
}
let containsPublicInstanceFields = false;
let containsInitializedPublicInstanceFields = false;
let containsInstancePrivateElements = false;
let containsInstanceAutoAccessors = false;
for (const member of node.members) {
if (!isStatic(member)) continue;
if (member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) && shouldTransformPrivateElementsOrClassStaticBlocks) {
facts |= ClassFacts.NeedsClassConstructorReference;
}
if (isPropertyDeclaration(member) || isClassStaticBlockDeclaration(member)) {
if (shouldTransformThisInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalThis) {
facts |= ClassFacts.NeedsSubstitutionForThisInClassStaticField;
if (!(facts & ClassFacts.ClassWasDecorated)) {
facts |= ClassFacts.NeedsClassConstructorReference;
if (isStatic(member)) {
if (member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) && shouldTransformPrivateElementsOrClassStaticBlocks) {
facts |= ClassFacts.NeedsClassConstructorReference;
}
if (isPropertyDeclaration(member) || isClassStaticBlockDeclaration(member)) {
if (shouldTransformThisInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalThis) {
facts |= ClassFacts.NeedsSubstitutionForThisInClassStaticField;
if (!(facts & ClassFacts.ClassWasDecorated)) {
facts |= ClassFacts.NeedsClassConstructorReference;
}
}
if (shouldTransformSuperInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalSuper) {
if (!(facts & ClassFacts.ClassWasDecorated)) {
facts |= ClassFacts.NeedsClassConstructorReference | ClassFacts.NeedsClassSuperReference;
}
}
}
if (shouldTransformSuperInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalSuper) {
if (!(facts & ClassFacts.ClassWasDecorated)) {
facts |= ClassFacts.NeedsClassConstructorReference | ClassFacts.NeedsClassSuperReference;
}
}
else if (!hasAbstractModifier(getOriginalNode(member))) {
if (isAutoAccessorPropertyDeclaration(member)) {
containsInstanceAutoAccessors = true;
containsInstancePrivateElements ||= isPrivateIdentifierClassElementDeclaration(member);
}
else if (isPrivateIdentifierClassElementDeclaration(member)) {
containsInstancePrivateElements = true;
}
else if (isPropertyDeclaration(member)) {
containsPublicInstanceFields = true;
containsInitializedPublicInstanceFields ||= !!member.initializer;
}
}
}
const willHoistInitializersToConstructor =
shouldTransformInitializersUsingDefine && containsPublicInstanceFields ||
shouldTransformInitializersUsingSet && containsInitializedPublicInstanceFields ||
shouldTransformPrivateElementsOrClassStaticBlocks && containsInstancePrivateElements ||
shouldTransformPrivateElementsOrClassStaticBlocks && containsInstanceAutoAccessors && shouldTransformAutoAccessors === Ternary.True;
if (willHoistInitializersToConstructor) {
facts |= ClassFacts.WillHoistInitializersToConstructor;
}
return facts;
}
@@ -1632,20 +1673,9 @@ export function transformClassFields(context: TransformationContext): (x: Source
);
}
function isClassElementThatRequiresConstructorStatement(member: ClassElement) {
if (isStatic(member) || hasAbstractModifier(getOriginalNode(member))) {
return false;
}
return shouldTransformInitializersUsingDefine && isPropertyDeclaration(member) ||
shouldTransformInitializersUsingSet && isInitializedProperty(member) ||
shouldTransformPrivateElementsOrClassStaticBlocks && isPrivateIdentifierClassElementDeclaration(member) ||
shouldTransformPrivateElementsOrClassStaticBlocks && shouldTransformAutoAccessors && isAutoAccessorPropertyDeclaration(member);
}
function transformConstructor(constructor: ConstructorDeclaration | undefined, container: ClassDeclaration | ClassExpression) {
constructor = visitNode(constructor, visitor, isConstructorDeclaration);
if (!some(container.members, isClassElementThatRequiresConstructorStatement)) {
if (!currentClassLexicalEnvironment || !(currentClassLexicalEnvironment.facts & ClassFacts.WillHoistInitializersToConstructor)) {
return constructor;
}
@@ -0,0 +1,65 @@
//// [autoAccessor10.ts]
class C1 {
accessor a0 = 1;
}
class C2 {
#a1_accessor_storage = 1;
accessor a1 = 2;
}
class C3 {
static #a2_accessor_storage = 1;
static {
class C3_Inner {
accessor a2 = 2;
static {
#a2_accessor_storage in C3;
}
}
}
}
class C4_1 {
static accessor a3 = 1;
}
class C4_2 {
static accessor a3 = 1;
}
//// [autoAccessor10.js]
class C1 {
#a0_accessor_storage = 1;
get a0() { return this.#a0_accessor_storage; }
set a0(value) { this.#a0_accessor_storage = value; }
}
class C2 {
#a1_accessor_storage = 1;
#a1_1_accessor_storage = 2;
get a1() { return this.#a1_1_accessor_storage; }
set a1(value) { this.#a1_1_accessor_storage = value; }
}
class C3 {
static #a2_accessor_storage = 1;
static {
class C3_Inner {
#a2_1_accessor_storage = 2;
get a2() { return this.#a2_1_accessor_storage; }
set a2(value) { this.#a2_1_accessor_storage = value; }
static {
#a2_accessor_storage in C3;
}
}
}
}
class C4_1 {
static #a3_accessor_storage = 1;
static get a3() { return this.#a3_accessor_storage; }
static set a3(value) { this.#a3_accessor_storage = value; }
}
class C4_2 {
static #a3_accessor_storage = 1;
static get a3() { return this.#a3_accessor_storage; }
static set a3(value) { this.#a3_accessor_storage = value; }
}
@@ -0,0 +1,53 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessor10.ts ===
class C1 {
>C1 : Symbol(C1, Decl(autoAccessor10.ts, 0, 0))
accessor a0 = 1;
>a0 : Symbol(C1.a0, Decl(autoAccessor10.ts, 0, 10))
}
class C2 {
>C2 : Symbol(C2, Decl(autoAccessor10.ts, 2, 1))
#a1_accessor_storage = 1;
>#a1_accessor_storage : Symbol(C2.#a1_accessor_storage, Decl(autoAccessor10.ts, 4, 10))
accessor a1 = 2;
>a1 : Symbol(C2.a1, Decl(autoAccessor10.ts, 5, 29))
}
class C3 {
>C3 : Symbol(C3, Decl(autoAccessor10.ts, 7, 1))
static #a2_accessor_storage = 1;
>#a2_accessor_storage : Symbol(C3.#a2_accessor_storage, Decl(autoAccessor10.ts, 9, 10))
static {
class C3_Inner {
>C3_Inner : Symbol(C3_Inner, Decl(autoAccessor10.ts, 11, 12))
accessor a2 = 2;
>a2 : Symbol(C3_Inner.a2, Decl(autoAccessor10.ts, 12, 24))
static {
#a2_accessor_storage in C3;
>#a2_accessor_storage : Symbol(C3.#a2_accessor_storage, Decl(autoAccessor10.ts, 9, 10))
>C3 : Symbol(C3, Decl(autoAccessor10.ts, 7, 1))
}
}
}
}
class C4_1 {
>C4_1 : Symbol(C4_1, Decl(autoAccessor10.ts, 19, 1))
static accessor a3 = 1;
>a3 : Symbol(C4_1.a3, Decl(autoAccessor10.ts, 21, 12))
}
class C4_2 {
>C4_2 : Symbol(C4_2, Decl(autoAccessor10.ts, 23, 1))
static accessor a3 = 1;
>a3 : Symbol(C4_2.a3, Decl(autoAccessor10.ts, 25, 12))
}
@@ -0,0 +1,61 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessor10.ts ===
class C1 {
>C1 : C1
accessor a0 = 1;
>a0 : number
>1 : 1
}
class C2 {
>C2 : C2
#a1_accessor_storage = 1;
>#a1_accessor_storage : number
>1 : 1
accessor a1 = 2;
>a1 : number
>2 : 2
}
class C3 {
>C3 : C3
static #a2_accessor_storage = 1;
>#a2_accessor_storage : number
>1 : 1
static {
class C3_Inner {
>C3_Inner : C3_Inner
accessor a2 = 2;
>a2 : number
>2 : 2
static {
#a2_accessor_storage in C3;
>#a2_accessor_storage in C3 : boolean
>#a2_accessor_storage : any
>C3 : typeof C3
}
}
}
}
class C4_1 {
>C4_1 : C4_1
static accessor a3 = 1;
>a3 : number
>1 : 1
}
class C4_2 {
>C4_2 : C4_2
static accessor a3 = 1;
>a3 : number
>1 : 1
}
@@ -14,6 +14,7 @@ class C3 extends C1 {
//// [autoAccessor6.js]
class C1 {
accessor a;
}
class C2 extends C1 {
constructor() {
@@ -16,11 +16,7 @@ class C3 extends C1 {
class C1 {
}
class C2 extends C1 {
constructor() {
super(...arguments);
this.#a_accessor_storage = 1;
}
#a_accessor_storage;
#a_accessor_storage = 1;
get a() { return this.#a_accessor_storage; }
set a(value) { this.#a_accessor_storage = value; }
}
@@ -16,10 +16,7 @@ class C3 extends C1 {
class C1 {
}
class C2 extends C1 {
constructor() {
super(...arguments);
this.#a_1 = 1;
}
accessor a = 1;
}
class C3 extends C1 {
get a() { return 1; }
+102
View File
@@ -0,0 +1,102 @@
//// [autoAccessor9.ts]
// Auto-accessors do not use Set semantics themselves, so do not need to be transformed if there are no other
// initializers that need to be transformed:
class C1 {
accessor x = 1;
}
// If there are other field initializers to transform, we must transform auto-accessors so that we can preserve
// initialization order:
class C2 {
x = 1;
accessor y = 2;
z = 3;
}
// Private field initializers also do not use Set semantics, so they do not force an auto-accessor transformation:
class C3 {
#x = 1;
accessor y = 2;
}
// However, we still need to hoist private field initializers to the constructor if we need to preserve initialization
// order:
class C4 {
x = 1;
#y = 2;
z = 3;
}
class C5 {
#x = 1;
accessor y = 2;
z = 3;
}
// Static accessors aren't affected:
class C6 {
static accessor x = 1;
}
// Static accessors aren't affected:
class C7 {
static x = 1;
static accessor y = 2;
static z = 3;
}
//// [autoAccessor9.js]
// Auto-accessors do not use Set semantics themselves, so do not need to be transformed if there are no other
// initializers that need to be transformed:
class C1 {
accessor x = 1;
}
// If there are other field initializers to transform, we must transform auto-accessors so that we can preserve
// initialization order:
class C2 {
constructor() {
this.x = 1;
this.#y_accessor_storage = 2;
this.z = 3;
}
#y_accessor_storage;
get y() { return this.#y_accessor_storage; }
set y(value) { this.#y_accessor_storage = value; }
}
// Private field initializers also do not use Set semantics, so they do not force an auto-accessor transformation:
class C3 {
#x = 1;
accessor y = 2;
}
// However, we still need to hoist private field initializers to the constructor if we need to preserve initialization
// order:
class C4 {
constructor() {
this.x = 1;
this.#y = 2;
this.z = 3;
}
#y;
}
class C5 {
constructor() {
this.#x = 1;
this.#y_accessor_storage = 2;
this.z = 3;
}
#x;
#y_accessor_storage;
get y() { return this.#y_accessor_storage; }
set y(value) { this.#y_accessor_storage = value; }
}
// Static accessors aren't affected:
class C6 {
static accessor x = 1;
}
// Static accessors aren't affected:
class C7 {
static { this.x = 1; }
static accessor y = 2;
static { this.z = 3; }
}
@@ -0,0 +1,86 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessor9.ts ===
// Auto-accessors do not use Set semantics themselves, so do not need to be transformed if there are no other
// initializers that need to be transformed:
class C1 {
>C1 : Symbol(C1, Decl(autoAccessor9.ts, 0, 0))
accessor x = 1;
>x : Symbol(C1.x, Decl(autoAccessor9.ts, 2, 10))
}
// If there are other field initializers to transform, we must transform auto-accessors so that we can preserve
// initialization order:
class C2 {
>C2 : Symbol(C2, Decl(autoAccessor9.ts, 4, 1))
x = 1;
>x : Symbol(C2.x, Decl(autoAccessor9.ts, 8, 10))
accessor y = 2;
>y : Symbol(C2.y, Decl(autoAccessor9.ts, 9, 10))
z = 3;
>z : Symbol(C2.z, Decl(autoAccessor9.ts, 10, 19))
}
// Private field initializers also do not use Set semantics, so they do not force an auto-accessor transformation:
class C3 {
>C3 : Symbol(C3, Decl(autoAccessor9.ts, 12, 1))
#x = 1;
>#x : Symbol(C3.#x, Decl(autoAccessor9.ts, 15, 10))
accessor y = 2;
>y : Symbol(C3.y, Decl(autoAccessor9.ts, 16, 11))
}
// However, we still need to hoist private field initializers to the constructor if we need to preserve initialization
// order:
class C4 {
>C4 : Symbol(C4, Decl(autoAccessor9.ts, 18, 1))
x = 1;
>x : Symbol(C4.x, Decl(autoAccessor9.ts, 22, 10))
#y = 2;
>#y : Symbol(C4.#y, Decl(autoAccessor9.ts, 23, 10))
z = 3;
>z : Symbol(C4.z, Decl(autoAccessor9.ts, 24, 11))
}
class C5 {
>C5 : Symbol(C5, Decl(autoAccessor9.ts, 26, 1))
#x = 1;
>#x : Symbol(C5.#x, Decl(autoAccessor9.ts, 28, 10))
accessor y = 2;
>y : Symbol(C5.y, Decl(autoAccessor9.ts, 29, 11))
z = 3;
>z : Symbol(C5.z, Decl(autoAccessor9.ts, 30, 19))
}
// Static accessors aren't affected:
class C6 {
>C6 : Symbol(C6, Decl(autoAccessor9.ts, 32, 1))
static accessor x = 1;
>x : Symbol(C6.x, Decl(autoAccessor9.ts, 35, 10))
}
// Static accessors aren't affected:
class C7 {
>C7 : Symbol(C7, Decl(autoAccessor9.ts, 37, 1))
static x = 1;
>x : Symbol(C7.x, Decl(autoAccessor9.ts, 40, 10))
static accessor y = 2;
>y : Symbol(C7.y, Decl(autoAccessor9.ts, 41, 17))
static z = 3;
>z : Symbol(C7.z, Decl(autoAccessor9.ts, 42, 26))
}
@@ -0,0 +1,102 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/autoAccessor9.ts ===
// Auto-accessors do not use Set semantics themselves, so do not need to be transformed if there are no other
// initializers that need to be transformed:
class C1 {
>C1 : C1
accessor x = 1;
>x : number
>1 : 1
}
// If there are other field initializers to transform, we must transform auto-accessors so that we can preserve
// initialization order:
class C2 {
>C2 : C2
x = 1;
>x : number
>1 : 1
accessor y = 2;
>y : number
>2 : 2
z = 3;
>z : number
>3 : 3
}
// Private field initializers also do not use Set semantics, so they do not force an auto-accessor transformation:
class C3 {
>C3 : C3
#x = 1;
>#x : number
>1 : 1
accessor y = 2;
>y : number
>2 : 2
}
// However, we still need to hoist private field initializers to the constructor if we need to preserve initialization
// order:
class C4 {
>C4 : C4
x = 1;
>x : number
>1 : 1
#y = 2;
>#y : number
>2 : 2
z = 3;
>z : number
>3 : 3
}
class C5 {
>C5 : C5
#x = 1;
>#x : number
>1 : 1
accessor y = 2;
>y : number
>2 : 2
z = 3;
>z : number
>3 : 3
}
// Static accessors aren't affected:
class C6 {
>C6 : C6
static accessor x = 1;
>x : number
>1 : 1
}
// Static accessors aren't affected:
class C7 {
>C7 : C7
static x = 1;
>x : number
>1 : 1
static accessor y = 2;
>y : number
>2 : 2
static z = 3;
>z : number
>3 : 3
}
@@ -40,10 +40,10 @@ __decorate([
dec
], C1, "b", null);
class C2 {
#a_1_accessor_storage;
get #a() { return this.#a_1_accessor_storage; }
set #a(value) { this.#a_1_accessor_storage = value; }
static #b_1_accessor_storage;
static get #b() { return this.#b_1_accessor_storage; }
static set #b(value) { this.#b_1_accessor_storage = value; }
#a_accessor_storage;
get #a() { return this.#a_accessor_storage; }
set #a(value) { this.#a_accessor_storage = value; }
static #b_accessor_storage;
static get #b() { return this.#b_accessor_storage; }
static set #b(value) { this.#b_accessor_storage = value; }
}
+1 -4
View File
@@ -9,9 +9,6 @@ class Foo {
//// [classIndexer5.js]
class Foo {
constructor() {
this.#b = false;
}
#a;
#b;
#b = false;
}
@@ -54,16 +54,10 @@ class TestNonStatics {
//// [privateNameWhenNotUseDefineForClassFieldsInEsNext.js]
"use strict";
class TestWithStatics {
constructor() {
this.#prop = 0;
}
#prop;
#prop = 0;
static { this.dd = new TestWithStatics().#prop; } // OK
static { this["X_ z_ zz"] = class Inner {
constructor() {
this.#foo = 10;
}
#foo;
#foo = 10;
m() {
new TestWithStatics().#prop; // OK
}
@@ -27,14 +27,11 @@ class Foo2 {
//// [privateNamesAssertion.js]
"use strict";
class Foo {
constructor() {
this.#p1 = (v) => {
if (typeof v !== "string") {
throw new Error();
}
};
}
#p1;
#p1 = (v) => {
if (typeof v !== "string") {
throw new Error();
}
};
m1(v) {
this.#p1(v);
v;
@@ -27,14 +27,11 @@ class Foo2 {
//// [privateNamesAssertion.js]
"use strict";
class Foo {
constructor() {
this.#p1 = (v) => {
if (typeof v !== "string") {
throw new Error();
}
};
}
#p1;
#p1 = (v) => {
if (typeof v !== "string") {
throw new Error();
}
};
m1(v) {
this.#p1(v);
v;
@@ -0,0 +1,30 @@
// @target: es2022
class C1 {
accessor a0 = 1;
}
class C2 {
#a1_accessor_storage = 1;
accessor a1 = 2;
}
class C3 {
static #a2_accessor_storage = 1;
static {
class C3_Inner {
accessor a2 = 2;
static {
#a2_accessor_storage in C3;
}
}
}
}
class C4_1 {
static accessor a3 = 1;
}
class C4_2 {
static accessor a3 = 1;
}
@@ -0,0 +1,48 @@
// @target: esnext
// @useDefineForClassFields: false
// Auto-accessors do not use Set semantics themselves, so do not need to be transformed if there are no other
// initializers that need to be transformed:
class C1 {
accessor x = 1;
}
// If there are other field initializers to transform, we must transform auto-accessors so that we can preserve
// initialization order:
class C2 {
x = 1;
accessor y = 2;
z = 3;
}
// Private field initializers also do not use Set semantics, so they do not force an auto-accessor transformation:
class C3 {
#x = 1;
accessor y = 2;
}
// However, we still need to hoist private field initializers to the constructor if we need to preserve initialization
// order:
class C4 {
x = 1;
#y = 2;
z = 3;
}
class C5 {
#x = 1;
accessor y = 2;
z = 3;
}
// Static accessors aren't affected:
class C6 {
static accessor x = 1;
}
// Static accessors aren't affected:
class C7 {
static x = 1;
static accessor y = 2;
static z = 3;
}