mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Fix private name generation and missing emit for auto-accessors (#52132)
This commit is contained in:
+91
-20
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+1
@@ -14,6 +14,7 @@ class C3 extends C1 {
|
||||
|
||||
//// [autoAccessor6.js]
|
||||
class C1 {
|
||||
accessor a;
|
||||
}
|
||||
class C2 extends C1 {
|
||||
constructor() {
|
||||
|
||||
+1
-5
@@ -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; }
|
||||
}
|
||||
|
||||
+1
-4
@@ -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; }
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@ class Foo {
|
||||
|
||||
//// [classIndexer5.js]
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.#b = false;
|
||||
}
|
||||
#a;
|
||||
#b;
|
||||
#b = false;
|
||||
}
|
||||
|
||||
+2
-8
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user