Skip to content

Commit 90fb764

Browse files
authored
Fix private name generation and missing emit for auto-accessors (#52132)
1 parent f1ff0de commit 90fb764

19 files changed

+723
-106
lines changed

src/compiler/emitter.ts

+91-20
Original file line numberDiff line numberDiff line change
@@ -1365,8 +1365,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
13651365
let privateNameTempFlags: TempFlags; // TempFlags for the current name generation scope.
13661366
let tempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes.
13671367
let tempFlags: TempFlags; // TempFlags for the current name generation scope.
1368-
let reservedNamesStack: Set<string>[]; // Stack of TempFlags reserved in enclosing name generation scopes.
1369-
let reservedNames: Set<string>; // TempFlags to reserve in nested name generation scopes.
1368+
let reservedNamesStack: (Set<string> | undefined)[]; // Stack of reserved names in enclosing name generation scopes.
1369+
let reservedNames: Set<string> | undefined; // Names reserved in nested name generation scopes.
1370+
let reservedPrivateNamesStack: (Set<string> | undefined)[]; // Stack of reserved member names in enclosing name generation scopes.
1371+
let reservedPrivateNames: Set<string> | undefined; // Member names reserved in nested name generation scopes.
13701372
let preserveSourceNewlines = printerOptions.preserveSourceNewlines; // Can be overridden inside nodes with the `IgnoreSourceNewlines` emit flag.
13711373
let nextListElementPos: number | undefined; // See comment in `getLeadingLineTerminatorCount`.
13721374

@@ -1658,6 +1660,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
16581660
tempFlagsStack = [];
16591661
tempFlags = TempFlags.Auto;
16601662
reservedNamesStack = [];
1663+
reservedNames = undefined;
1664+
reservedPrivateNamesStack = [];
1665+
reservedPrivateNames = undefined;
16611666
currentSourceFile = undefined;
16621667
currentLineMap = undefined;
16631668
detachedCommentsInfo = undefined;
@@ -2501,9 +2506,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
25012506
}
25022507

25032508
function emitComputedPropertyName(node: ComputedPropertyName) {
2509+
const savedPrivateNameTempFlags = privateNameTempFlags;
2510+
const savedReservedMemberNames = reservedPrivateNames;
2511+
popPrivateNameGenerationScope();
25042512
writePunctuation("[");
25052513
emitExpression(node.expression, parenthesizer.parenthesizeExpressionOfComputedPropertyName);
25062514
writePunctuation("]");
2515+
pushPrivateNameGenerationScope(savedPrivateNameTempFlags, savedReservedMemberNames);
25072516
}
25082517

25092518
//
@@ -2723,10 +2732,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
27232732
}
27242733

27252734
function emitTypeLiteral(node: TypeLiteralNode) {
2735+
// Type literals don't have private names, but we need to push a new scope so that
2736+
// we can step out of it when emitting a computed property.
2737+
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
2738+
27262739
writePunctuation("{");
27272740
const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers;
27282741
emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty);
27292742
writePunctuation("}");
2743+
2744+
popPrivateNameGenerationScope();
27302745
}
27312746

27322747
function emitArrayType(node: ArrayTypeNode) {
@@ -2943,6 +2958,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
29432958
}
29442959

29452960
function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
2961+
// Object literals don't have private names, but we need to push a new scope so that
2962+
// we can step out of it when emitting a computed property.
2963+
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
29462964
forEach(node.properties, generateMemberNames);
29472965

29482966
const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
@@ -2957,6 +2975,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
29572975
if (indentedFlag) {
29582976
decreaseIndent();
29592977
}
2978+
2979+
popPrivateNameGenerationScope();
29602980
}
29612981

29622982
function emitPropertyAccessExpression(node: PropertyAccessExpression) {
@@ -3763,6 +3783,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
37633783
}
37643784

37653785
function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) {
3786+
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
3787+
37663788
forEach(node.members, generateMemberNames);
37673789

37683790
emitDecoratorsAndModifiers(node, node.modifiers);
@@ -3788,9 +3810,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
37883810
if (indentedFlag) {
37893811
decreaseIndent();
37903812
}
3813+
3814+
popPrivateNameGenerationScope();
37913815
}
37923816

37933817
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
3818+
// Interfaces don't have private names, but we need to push a new scope so that
3819+
// we can step out of it when emitting a computed property.
3820+
pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined);
3821+
37943822
emitModifiers(node, node.modifiers);
37953823
writeKeyword("interface");
37963824
writeSpace();
@@ -3801,6 +3829,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
38013829
writePunctuation("{");
38023830
emitList(node, node.members, ListFormat.InterfaceMembers);
38033831
writePunctuation("}");
3832+
3833+
popPrivateNameGenerationScope();
38043834
}
38053835

38063836
function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
@@ -5486,8 +5516,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
54865516
}
54875517
tempFlagsStack.push(tempFlags);
54885518
tempFlags = TempFlags.Auto;
5489-
privateNameTempFlagsStack.push(privateNameTempFlags);
5490-
privateNameTempFlags = TempFlags.Auto;
54915519
formattedNameTempFlagsStack.push(formattedNameTempFlags);
54925520
formattedNameTempFlags = undefined;
54935521
reservedNamesStack.push(reservedNames);
@@ -5501,9 +5529,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
55015529
return;
55025530
}
55035531
tempFlags = tempFlagsStack.pop()!;
5504-
privateNameTempFlags = privateNameTempFlagsStack.pop()!;
55055532
formattedNameTempFlags = formattedNameTempFlagsStack.pop();
5506-
reservedNames = reservedNamesStack.pop()!;
5533+
reservedNames = reservedNamesStack.pop();
55075534
}
55085535

55095536
function reserveNameInNestedScopes(name: string) {
@@ -5513,6 +5540,31 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
55135540
reservedNames.add(name);
55145541
}
55155542

5543+
/**
5544+
* Push a new member name generation scope.
5545+
*/
5546+
function pushPrivateNameGenerationScope(newPrivateNameTempFlags: TempFlags, newReservedMemberNames: Set<string> | undefined) {
5547+
privateNameTempFlagsStack.push(privateNameTempFlags);
5548+
privateNameTempFlags = newPrivateNameTempFlags;
5549+
reservedPrivateNamesStack.push(reservedNames);
5550+
reservedPrivateNames = newReservedMemberNames;
5551+
}
5552+
5553+
/**
5554+
* Pop the current member name generation scope.
5555+
*/
5556+
function popPrivateNameGenerationScope() {
5557+
privateNameTempFlags = privateNameTempFlagsStack.pop()!;
5558+
reservedPrivateNames = reservedPrivateNamesStack.pop();
5559+
}
5560+
5561+
function reservePrivateNameInNestedScopes(name: string) {
5562+
if (!reservedPrivateNames || reservedPrivateNames === lastOrUndefined(reservedPrivateNamesStack)) {
5563+
reservedPrivateNames = new Set();
5564+
}
5565+
reservedPrivateNames.add(name);
5566+
}
5567+
55165568
function generateNames(node: Node | undefined) {
55175569
if (!node) return;
55185570
switch (node.kind) {
@@ -5650,16 +5702,23 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
56505702
* Returns a value indicating whether a name is unique globally, within the current file,
56515703
* or within the NameGenerator.
56525704
*/
5653-
function isUniqueName(name: string): boolean {
5654-
return isFileLevelUniqueName(name)
5655-
&& !generatedNames.has(name)
5656-
&& !(reservedNames && reservedNames.has(name));
5705+
function isUniqueName(name: string, privateName: boolean): boolean {
5706+
return isFileLevelUniqueName(name, privateName)
5707+
&& !isReservedName(name, privateName)
5708+
&& !generatedNames.has(name);
5709+
}
5710+
5711+
function isReservedName(name: string, privateName: boolean): boolean {
5712+
return privateName ? !!reservedPrivateNames?.has(name) : !!reservedNames?.has(name);
56575713
}
56585714

56595715
/**
56605716
* Returns a value indicating whether a name is unique globally or within the current file.
5717+
*
5718+
* @param _isPrivate (unused) this parameter exists to avoid an unnecessary adaptor frame in v8
5719+
* when `isfileLevelUniqueName` is passed as a callback to `makeUniqueName`.
56615720
*/
5662-
function isFileLevelUniqueName(name: string) {
5721+
function isFileLevelUniqueName(name: string, _isPrivate: boolean) {
56635722
return currentSourceFile ? ts.isFileLevelUniqueName(currentSourceFile, name, hasGlobalName) : true;
56645723
}
56655724

@@ -5722,9 +5781,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
57225781
if (flags && !(tempFlags & flags)) {
57235782
const name = flags === TempFlags._i ? "_i" : "_n";
57245783
const fullName = formatGeneratedName(privateName, prefix, name, suffix);
5725-
if (isUniqueName(fullName)) {
5784+
if (isUniqueName(fullName, privateName)) {
57265785
tempFlags |= flags;
5727-
if (reservedInNestedScopes) {
5786+
if (privateName) {
5787+
reservePrivateNameInNestedScopes(fullName);
5788+
}
5789+
else if (reservedInNestedScopes) {
57285790
reserveNameInNestedScopes(fullName);
57295791
}
57305792
setTempFlags(key, tempFlags);
@@ -5741,8 +5803,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
57415803
? "_" + String.fromCharCode(CharacterCodes.a + count)
57425804
: "_" + (count - 26);
57435805
const fullName = formatGeneratedName(privateName, prefix, name, suffix);
5744-
if (isUniqueName(fullName)) {
5745-
if (reservedInNestedScopes) {
5806+
if (isUniqueName(fullName, privateName)) {
5807+
if (privateName) {
5808+
reservePrivateNameInNestedScopes(fullName);
5809+
}
5810+
else if (reservedInNestedScopes) {
57465811
reserveNameInNestedScopes(fullName);
57475812
}
57485813
setTempFlags(key, tempFlags);
@@ -5759,7 +5824,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
57595824
* makeUniqueName are guaranteed to never conflict.
57605825
* If `optimistic` is set, the first instance will use 'baseName' verbatim instead of 'baseName_1'
57615826
*/
5762-
function makeUniqueName(baseName: string, checkFn: (name: string) => boolean = isUniqueName, optimistic: boolean, scoped: boolean, privateName: boolean, prefix: string, suffix: string): string {
5827+
function makeUniqueName(baseName: string, checkFn: (name: string, privateName: boolean) => boolean = isUniqueName, optimistic: boolean, scoped: boolean, privateName: boolean, prefix: string, suffix: string): string {
57635828
if (baseName.length > 0 && baseName.charCodeAt(0) === CharacterCodes.hash) {
57645829
baseName = baseName.slice(1);
57655830
}
@@ -5768,8 +5833,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
57685833
}
57695834
if (optimistic) {
57705835
const fullName = formatGeneratedName(privateName, prefix, baseName, suffix);
5771-
if (checkFn(fullName)) {
5772-
if (scoped) {
5836+
if (checkFn(fullName, privateName)) {
5837+
if (privateName) {
5838+
reservePrivateNameInNestedScopes(fullName);
5839+
}
5840+
else if (scoped) {
57735841
reserveNameInNestedScopes(fullName);
57745842
}
57755843
else {
@@ -5785,8 +5853,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
57855853
let i = 1;
57865854
while (true) {
57875855
const fullName = formatGeneratedName(privateName, prefix, baseName + i, suffix);
5788-
if (checkFn(fullName)) {
5789-
if (scoped) {
5856+
if (checkFn(fullName, privateName)) {
5857+
if (privateName) {
5858+
reservePrivateNameInNestedScopes(fullName);
5859+
}
5860+
else if (scoped) {
57905861
reserveNameInNestedScopes(fullName);
57915862
}
57925863
else {

src/compiler/parser.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,6 @@ namespace Parser {
14541454
let currentToken: SyntaxKind;
14551455
let nodeCount: number;
14561456
let identifiers: Map<string, string>;
1457-
let privateIdentifiers: Map<string, string>;
14581457
let identifierCount: number;
14591458

14601459
let parsingContext: ParsingContext;
@@ -1681,7 +1680,6 @@ namespace Parser {
16811680
parseDiagnostics = [];
16821681
parsingContext = 0;
16831682
identifiers = new Map<string, string>();
1684-
privateIdentifiers = new Map<string, string>();
16851683
identifierCount = 0;
16861684
nodeCount = 0;
16871685
sourceFlags = 0;
@@ -2661,17 +2659,9 @@ namespace Parser {
26612659
return finishNode(factory.createComputedPropertyName(expression), pos);
26622660
}
26632661

2664-
function internPrivateIdentifier(text: string): string {
2665-
let privateIdentifier = privateIdentifiers.get(text);
2666-
if (privateIdentifier === undefined) {
2667-
privateIdentifiers.set(text, privateIdentifier = text);
2668-
}
2669-
return privateIdentifier;
2670-
}
2671-
26722662
function parsePrivateIdentifier(): PrivateIdentifier {
26732663
const pos = getNodePos();
2674-
const node = factory.createPrivateIdentifier(internPrivateIdentifier(scanner.getTokenValue()));
2664+
const node = factory.createPrivateIdentifier(internIdentifier(scanner.getTokenValue()));
26752665
nextToken();
26762666
return finishNode(node, pos);
26772667
}

0 commit comments

Comments
 (0)