Skip to content

Commit 21cfc89

Browse files
committed
Move Identifier.typeArguments to EmitNode
1 parent fdb5dc5 commit 21cfc89

File tree

8 files changed

+64
-46
lines changed

8 files changed

+64
-46
lines changed

src/compiler/checker.ts

+34-17
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ import {
272272
getFirstIdentifier,
273273
getFunctionFlags,
274274
getHostSignatureFromJSDoc,
275+
getIdentifierTypeArguments,
275276
getImmediatelyInvokedFunctionExpression,
276277
getInitializerOfBinaryExpression,
277278
getInterfaceBaseTypeNodes,
@@ -893,6 +894,7 @@ import {
893894
SetAccessorDeclaration,
894895
setCommentRange,
895896
setEmitFlags,
897+
setIdentifierTypeArguments,
896898
setNodeFlags,
897899
setOriginalNode,
898900
setParent,
@@ -6792,12 +6794,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
67926794
let qualifier = root.qualifier;
67936795
if (qualifier) {
67946796
if (isIdentifier(qualifier)) {
6795-
qualifier = factory.updateIdentifier(qualifier, typeArguments);
6797+
if (typeArguments !== getIdentifierTypeArguments(qualifier)) {
6798+
qualifier = setIdentifierTypeArguments(factory.cloneNode(qualifier), typeArguments);
6799+
}
67966800
}
67976801
else {
6798-
qualifier = factory.updateQualifiedName(qualifier,
6799-
qualifier.left,
6800-
factory.updateIdentifier(qualifier.right, typeArguments));
6802+
if (typeArguments !== getIdentifierTypeArguments(qualifier.right)) {
6803+
qualifier = factory.updateQualifiedName(qualifier,
6804+
qualifier.left,
6805+
setIdentifierTypeArguments(factory.cloneNode(qualifier.right), typeArguments));
6806+
}
68016807
}
68026808
}
68036809
typeArguments = ref.typeArguments;
@@ -6819,12 +6825,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
68196825
let typeArguments = root.typeArguments;
68206826
let typeName = root.typeName;
68216827
if (isIdentifier(typeName)) {
6822-
typeName = factory.updateIdentifier(typeName, typeArguments);
6828+
if (typeArguments !== getIdentifierTypeArguments(typeName)) {
6829+
typeName = setIdentifierTypeArguments(factory.cloneNode(typeName), typeArguments);
6830+
}
68236831
}
68246832
else {
6825-
typeName = factory.updateQualifiedName(typeName,
6826-
typeName.left,
6827-
factory.updateIdentifier(typeName.right, typeArguments));
6833+
if (typeArguments !== getIdentifierTypeArguments(typeName.right)) {
6834+
typeName = factory.updateQualifiedName(typeName,
6835+
typeName.left,
6836+
setIdentifierTypeArguments(factory.cloneNode(typeName.right), typeArguments));
6837+
}
68286838
}
68296839
typeArguments = ref.typeArguments;
68306840
// then move qualifiers
@@ -7542,7 +7552,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
75427552
if (!nonRootParts || isEntityName(nonRootParts)) {
75437553
if (nonRootParts) {
75447554
const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right;
7545-
lastId.typeArguments = undefined;
7555+
setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined);
75467556
}
75477557
return factory.createImportTypeNode(lit, assertion, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf);
75487558
}
@@ -7562,8 +7572,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
75627572
}
75637573
else {
75647574
const lastId = isIdentifier(entityName) ? entityName : entityName.right;
7565-
const lastTypeArgs = lastId.typeArguments;
7566-
lastId.typeArguments = undefined;
7575+
const lastTypeArgs = getIdentifierTypeArguments(lastId);
7576+
setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined);
75677577
return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray<TypeNode>);
75687578
}
75697579

@@ -7617,7 +7627,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
76177627
}
76187628
}
76197629

7620-
const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
7630+
const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping);
7631+
if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
76217632
identifier.symbol = symbol;
76227633

76237634
if (index > stopper) {
@@ -7662,7 +7673,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
76627673
text = `${rawtext}_${i}`;
76637674
}
76647675
if (text !== rawtext) {
7665-
result = factory.createIdentifier(text, result.typeArguments);
7676+
const typeArguments = getIdentifierTypeArguments(result);
7677+
result = factory.createIdentifier(text);
7678+
setIdentifierTypeArguments(result, typeArguments);
76667679
}
76677680
// avoiding iterations of the above loop turns out to be worth it when `i` starts to get large, so we cache the max
76687681
// `i` we've used thus far, to save work later
@@ -7697,7 +7710,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
76977710
context.flags ^= NodeBuilderFlags.InInitialEntityName;
76987711
}
76997712

7700-
const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
7713+
const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping);
7714+
if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
77017715
identifier.symbol = symbol;
77027716

77037717
return index > 0 ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier;
@@ -7726,7 +7740,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
77267740
return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context));
77277741
}
77287742
if (index === 0 || canUsePropertyAccess(symbolName, languageVersion)) {
7729-
const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
7743+
const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping);
7744+
if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
77307745
identifier.symbol = symbol;
77317746

77327747
return index > 0 ? factory.createPropertyAccessExpression(createExpressionFromSymbolChain(chain, index - 1), identifier) : identifier;
@@ -7744,8 +7759,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
77447759
expression = factory.createNumericLiteral(+symbolName);
77457760
}
77467761
if (!expression) {
7747-
expression = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
7748-
(expression as Identifier).symbol = symbol;
7762+
const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping);
7763+
if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
7764+
identifier.symbol = symbol;
7765+
expression = identifier;
77497766
}
77507767
return factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression);
77517768
}

src/compiler/emitter.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ import {
148148
getEmitModuleKind,
149149
getExternalHelpersModuleName,
150150
getExternalModuleName,
151+
getIdentifierTypeArguments,
151152
getLeadingCommentRanges,
152153
getLineAndCharacterOfPosition,
153154
getLinesBetweenPositionAndNextNonWhitespaceCharacter,
@@ -2478,7 +2479,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
24782479
function emitIdentifier(node: Identifier) {
24792480
const writeText = node.symbol ? writeSymbol : write;
24802481
writeText(getTextOfNode(node, /*includeTrivia*/ false), node.symbol);
2481-
emitList(node, node.typeArguments, ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments
2482+
emitList(node, getIdentifierTypeArguments(node), ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments
24822483
}
24832484

24842485
//

src/compiler/factory/emitNode.ts

+14
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import {
88
EmitNode,
99
getParseTreeNode,
1010
getSourceFileOfNode,
11+
Identifier,
1112
isParseTreeNode,
1213
Node,
14+
NodeArray,
1315
orderedRemoveItem,
1416
SnippetElement,
1517
some,
@@ -19,6 +21,7 @@ import {
1921
SynthesizedComment,
2022
TextRange,
2123
TypeNode,
24+
TypeParameterDeclaration,
2225
} from "../_namespaces/ts";
2326

2427
/**
@@ -318,3 +321,14 @@ export function setTypeNode<T extends Node>(node: T, type: TypeNode): T {
318321
export function getTypeNode<T extends Node>(node: T): TypeNode | undefined {
319322
return node.emitNode?.typeNode;
320323
}
324+
325+
/** @internal */
326+
export function setIdentifierTypeArguments<T extends Identifier>(node: T, typeArguments: NodeArray<TypeNode | TypeParameterDeclaration> | undefined) {
327+
getOrCreateEmitNode(node).identifierTypeArguments = typeArguments;
328+
return node;
329+
}
330+
331+
/** @internal */
332+
export function getIdentifierTypeArguments(node: Identifier): NodeArray<TypeNode | TypeParameterDeclaration> | undefined {
333+
return node.emitNode?.identifierTypeArguments;
334+
}

src/compiler/factory/nodeFactory.ts

+7-12
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ import {
116116
getCommentRange,
117117
getElementsOfBindingOrAssignmentPattern,
118118
getEmitFlags,
119+
getIdentifierTypeArguments,
119120
getJSDocTypeAliasName,
120121
getLineAndCharacterOfPosition,
121122
getNameOfDeclaration,
@@ -390,6 +391,7 @@ import {
390391
SetAccessorDeclaration,
391392
setEachParent,
392393
setEmitFlags,
394+
setIdentifierTypeArguments,
393395
setParent,
394396
setTextRange,
395397
setTextRangePosWidth,
@@ -532,7 +534,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
532534
createRegularExpressionLiteral,
533535
createLiteralLikeNode,
534536
createIdentifier,
535-
updateIdentifier,
536537
createTempVariable,
537538
createLoopVariable,
538539
createUniqueName,
@@ -1155,7 +1156,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
11551156
node.originalKeywordKind = originalKeywordKind;
11561157
node.escapedText = escapedText;
11571158
node.autoGenerate = undefined;
1158-
node.typeArguments = undefined;
11591159
node.hasExtendedUnicodeEscape = undefined;
11601160
node.jsDoc = undefined; // initialized by parser (JsDocContainer)
11611161
node.jsDocCache = undefined; // initialized by parser (JsDocContainer)
@@ -1177,7 +1177,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
11771177
}
11781178

11791179
// @api
1180-
function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier {
1180+
function createIdentifier(text: string, originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier {
11811181
if (originalKeywordKind === undefined && text) {
11821182
originalKeywordKind = stringToToken(text);
11831183
}
@@ -1186,7 +1186,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
11861186
}
11871187

11881188
const node = createBaseIdentifier(escapeLeadingUnderscores(text), originalKeywordKind);
1189-
node.typeArguments = asNodeArray(typeArguments);
11901189
node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape;
11911190

11921191
// NOTE: we do not include transform flags of typeArguments in an identifier as they do not contribute to transformations
@@ -1200,13 +1199,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
12001199
return node;
12011200
}
12021201

1203-
// @api
1204-
function updateIdentifier(node: Identifier, typeArguments?: NodeArray<TypeNode | TypeParameterDeclaration> | undefined): Identifier {
1205-
return node.typeArguments !== typeArguments
1206-
? update(createIdentifier(idText(node), typeArguments), node)
1207-
: node;
1208-
}
1209-
12101202
// @api
12111203
function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean, prefix?: string | GeneratedNamePart, suffix?: string): GeneratedIdentifier {
12121204
let flags = GeneratedIdentifierFlags.Auto;
@@ -6389,14 +6381,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
63896381
function cloneIdentifier(node: Identifier): Identifier {
63906382
const clone = createBaseIdentifier(node.escapedText, node.originalKeywordKind);
63916383
clone.flags |= node.flags & ~NodeFlags.Synthesized;
6392-
clone.typeArguments = node.typeArguments;
63936384
clone.hasExtendedUnicodeEscape = node.hasExtendedUnicodeEscape;
63946385
clone.jsDoc = node.jsDoc;
63956386
clone.jsDocCache = node.jsDocCache;
63966387
clone.flowNode = node.flowNode;
63976388
clone.symbol = node.symbol;
63986389
clone.transformFlags = node.transformFlags;
63996390
setOriginalNode(clone, node);
6391+
6392+
// clone type arguments for emitter/typeWriter
6393+
const typeArguments = getIdentifierTypeArguments(node);
6394+
if (typeArguments) setIdentifierTypeArguments(clone, typeArguments);
64006395
return clone;
64016396
}
64026397

src/compiler/parser.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -2547,7 +2547,7 @@ namespace Parser {
25472547

25482548
const pos = getNodePos();
25492549
const result =
2550-
kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) :
2550+
kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*originalKeywordKind*/ undefined) :
25512551
isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) :
25522552
kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) :
25532553
kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) :
@@ -2576,7 +2576,7 @@ namespace Parser {
25762576
const text = internIdentifier(scanner.getTokenValue());
25772577
const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape();
25782578
nextTokenWithoutCheck();
2579-
return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos);
2579+
return finishNode(factory.createIdentifier(text, originalKeywordKind, hasExtendedUnicodeEscape), pos);
25802580
}
25812581

25822582
if (token() === SyntaxKind.PrivateIdentifier) {
@@ -9477,7 +9477,7 @@ namespace Parser {
94779477
const end = scanner.getTextPos();
94789478
const originalKeywordKind = token();
94799479
const text = internIdentifier(scanner.getTokenValue());
9480-
const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end);
9480+
const result = finishNode(factory.createIdentifier(text, originalKeywordKind), pos, end);
94819481
nextTokenJSDoc();
94829482
return result;
94839483
}

src/compiler/types.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,6 @@ export type ForEachChildNodes =
10081008
/** @internal */
10091009
export type VisitEachChildNodes =
10101010
| HasChildren
1011-
| Identifier
10121011
;
10131012

10141013
/** @internal */
@@ -1682,9 +1681,8 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain
16821681
/** @internal */ readonly autoGenerate: AutoGenerateInfo | undefined; // Used for auto-generated identifiers.
16831682
/** @internal */ generatedImportReference?: ImportSpecifier; // Reference to the generated import specifier this identifier refers to
16841683
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
1685-
/** @internal */ typeArguments?: NodeArray<TypeNode | TypeParameterDeclaration>; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help.
16861684
/** @internal */ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id.<T>
1687-
/**@internal*/ hasExtendedUnicodeEscape?: boolean;
1685+
/** @internal */ hasExtendedUnicodeEscape?: boolean;
16881686
}
16891687

16901688
// Transient identifier node (marked by id === -1)
@@ -7828,6 +7826,7 @@ export interface EmitNode {
78287826
startsOnNewLine?: boolean; // If the node should begin on a new line
78297827
snippetElement?: SnippetElement; // Snippet element of the node
78307828
typeNode?: TypeNode; // VariableDeclaration type
7829+
identifierTypeArguments?: NodeArray<TypeNode | TypeParameterDeclaration>; // Only defined on synthesized identifiers. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help.
78317830
}
78327831

78337832
/** @internal */
@@ -8126,8 +8125,7 @@ export interface NodeFactory {
81268125
//
81278126

81288127
createIdentifier(text: string): Identifier;
8129-
/** @internal */ createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures
8130-
/** @internal */ updateIdentifier(node: Identifier, typeArguments: NodeArray<TypeNode | TypeParameterDeclaration> | undefined): Identifier;
8128+
/** @internal */ createIdentifier(text: string, originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures
81318129

81328130
/**
81338131
* Create a unique temporary variable.

src/compiler/visitorPublic.ts

-7
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ import {
8080
isToken,
8181
isTypeElement,
8282
isTypeNode,
83-
isTypeNodeOrTypeParameterDeclaration,
8483
isTypeParameterDeclaration,
8584
isVariableDeclaration,
8685
isVariableDeclarationList,
@@ -513,7 +512,6 @@ type VisitEachChildFunction<T extends Node> = (node: T, visitor: Visitor, contex
513512
// This looks something like:
514513
//
515514
// {
516-
// [SyntaxKind.Identifier]: VisitEachChildFunction<Identifier>;
517515
// [SyntaxKind.QualifiedName]: VisitEachChildFunction<QualifiedName>;
518516
// [SyntaxKind.ComputedPropertyName]: VisitEachChildFunction<ComputedPropertyName>;
519517
// ...
@@ -525,11 +523,6 @@ type VisitEachChildTable = { [TNode in VisitEachChildNodes as TNode["kind"]]: Vi
525523
// NOTE: Before you can add a new method to `visitEachChildTable`, you must first ensure the `Node` subtype you
526524
// wish to add is defined in the `HasChildren` union in types.ts.
527525
const visitEachChildTable: VisitEachChildTable = {
528-
[SyntaxKind.Identifier]: function visitEachChildOfIdentifier(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) {
529-
return context.factory.updateIdentifier(node,
530-
nodesVisitor(node.typeArguments, visitor, isTypeNodeOrTypeParameterDeclaration));
531-
},
532-
533526
[SyntaxKind.QualifiedName]: function visitEachChildOfQualifiedName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) {
534527
return context.factory.updateQualifiedName(node,
535528
nodeVisitor(node.left, visitor, isEntityName),

0 commit comments

Comments
 (0)