Skip to content

Commit ac6018a

Browse files
author
Arthur Ozga
committed
type arguments in qualified names
1 parent 41452a5 commit ac6018a

File tree

2 files changed

+60
-26
lines changed

2 files changed

+60
-26
lines changed

src/compiler/checker.ts

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2448,9 +2448,10 @@ namespace ts {
24482448

24492449
if (!inTypeAlias && type.aliasSymbol &&
24502450
isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
2451-
const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context);
2452-
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true);
2451+
const name = symbolToTypeReferenceName(type.aliasSymbol);
2452+
const typeArgumentNodes = toTypeArgumentNodes(type.aliasTypeArguments, context);
24532453
return createTypeReferenceNode(name, typeArgumentNodes);
2454+
// return symbolToTypeReferenceIdentifier(type.aliasSymbol, type.aliasTypeArguments);
24542455
}
24552456

24562457
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
@@ -2614,6 +2615,13 @@ namespace ts {
26142615
return createTypeQueryNode(entityName);
26152616
}
26162617

2618+
function symbolToTypeReferenceName(symbol: Symbol) {
2619+
// Unnamed function expressions and arrow functions have reserved names that we don't want to display
2620+
const entityName = symbol.flags & SymbolFlags.Class || !isReservedMemberName(symbol.name) ? symbolToName(symbol, /*expectsIdentifier*/ false, SymbolFlags.Type, context) : createIdentifier("");
2621+
// TODO: assert no type args?
2622+
return entityName;
2623+
}
2624+
26172625
function typeReferenceToTypeNode(type: TypeReference) {
26182626
const typeArguments: Type[] = type.typeArguments || emptyArray;
26192627
if (type.target === globalArrayType) {
@@ -2641,7 +2649,7 @@ namespace ts {
26412649
else {
26422650
const outerTypeParameters = type.target.outerTypeParameters;
26432651
let i = 0;
2644-
let qualifiedName: QualifiedName | undefined = undefined;
2652+
let qualifiedName: QualifiedName | undefined;
26452653
if (outerTypeParameters) {
26462654
let inFirstTypeArgument = true;
26472655
const length = outerTypeParameters.length;
@@ -2655,46 +2663,68 @@ namespace ts {
26552663
// When type parameters are their own type arguments for the whole group (i.e. we have
26562664
// the default outer type arguments), we don't show the group.
26572665
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
2658-
const qualifiedNamePartTypeArguments = typeArguments.slice(start,i);
2659-
const qualifiedNamePartTypeArgumentNodes = qualifiedNamePartTypeArguments && createNodeArray(mapToTypeNodeArray(qualifiedNamePartTypeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true));
2660-
const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, SymbolFlags.Type, context);
2661-
qualifiedNamePart.typeArguments = qualifiedNamePartTypeArgumentNodes;
2666+
const typeArgumentNodes = createNodeArray(toTypeArgumentNodes(typeArguments.slice(start, i), context));
2667+
const namePart = symbolToTypeReferenceName(parent);
2668+
(namePart.kind === SyntaxKind.Identifier ? <Identifier>namePart : namePart.right).typeArguments = typeArgumentNodes;
26622669

2663-
if (!qualifiedName) {
2664-
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined);
2665-
}
2666-
else {
2670+
if (qualifiedName) {
26672671
Debug.assert(!qualifiedName.right);
2668-
qualifiedName.right = qualifiedNamePart;
2672+
qualifiedName = addToQualifiedNameMissingRightIdentifier(qualifiedName, namePart);
26692673
qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined);
26702674
}
2675+
else {
2676+
qualifiedName = createQualifiedName(namePart, /*right*/ undefined);
2677+
}
26712678
}
26722679
inFirstTypeArgument = false;
26732680
}
26742681
}
2682+
26752683
let entityName: EntityName = undefined;
2676-
const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true, SymbolFlags.Type, context);
2684+
const nameIdentifier = symbolToTypeReferenceName(type.symbol);
26772685
if (qualifiedName) {
26782686
Debug.assert(!qualifiedName.right);
2679-
qualifiedName.right = nameIdentifier;
2687+
qualifiedName = addToQualifiedNameMissingRightIdentifier(qualifiedName, nameIdentifier);
26802688
entityName = qualifiedName;
26812689
}
26822690
else {
26832691
entityName = nameIdentifier;
26842692
}
2685-
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
26862693

26872694
let typeArgumentNodes: TypeNode[] | undefined;
26882695
if (some(typeArguments)) {
2689-
const slice = typeArguments.slice(i, typeParameterCount - i);
2690-
context.InFirstTypeArgument = true;
2691-
typeArgumentNodes = mapToTypeNodeArray(slice, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true);
2696+
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
2697+
const slice = typeArguments && typeArguments.slice(i, typeParameterCount);
2698+
typeArgumentNodes = toTypeArgumentNodes(slice, context);
2699+
}
2700+
2701+
if (typeArgumentNodes) {
2702+
const lastIdentifier = entityName.kind === SyntaxKind.Identifier ? <Identifier>entityName : entityName.right;
2703+
lastIdentifier.typeArguments = undefined;
26922704
}
26932705

26942706
return createTypeReferenceNode(entityName, typeArgumentNodes);
26952707
}
26962708
}
26972709

2710+
function addToQualifiedNameMissingRightIdentifier(left: QualifiedName, right: Identifier | QualifiedName) {
2711+
Debug.assert(left.right === undefined);
2712+
2713+
if (right.kind === SyntaxKind.Identifier) {
2714+
left.right = right;
2715+
return left;
2716+
}
2717+
2718+
let rightPart = right;
2719+
while (rightPart.left.kind !== SyntaxKind.Identifier) {
2720+
rightPart = rightPart.left;
2721+
}
2722+
2723+
left.right = <Identifier>rightPart.left;
2724+
rightPart.left = left;
2725+
return right;
2726+
}
2727+
26982728
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] {
26992729
const typeElements: TypeElement[] = [];
27002730
for (const signature of resolvedType.callSignatures) {
@@ -2754,7 +2784,7 @@ namespace ts {
27542784
const result = [];
27552785
Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper");
27562786
for (let i = 0; i < types.length; ++i) {
2757-
let type = types[i]
2787+
const type = types[i];
27582788
context.InElementType = addInElementTypeFlag;
27592789
if (i === 0) {
27602790
context.InFirstTypeArgument = addInFirstTypeArgumentFlag;
@@ -2768,6 +2798,10 @@ namespace ts {
27682798
return result;
27692799
}
27702800

2801+
function toTypeArgumentNodes(typeArguments: Type[], context: NodeBuilderContext) {
2802+
return typeArguments && mapToTypeNodeArray(typeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true);
2803+
}
2804+
27712805
function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration {
27722806
const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword);
27732807
const name = getNameFromIndexInfo(indexInfo) || "x";
@@ -2913,7 +2947,7 @@ namespace ts {
29132947
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowTypeParameterInQualifiedName)) {
29142948
context.encounteredError = true;
29152949
}
2916-
typeParameterNodes = typeParameters && mapToTypeNodeArray(typeParameters, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true);
2950+
typeParameterNodes = toTypeArgumentNodes(typeParameters, context);
29172951
}
29182952
}
29192953

src/compiler/types.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -570,12 +570,12 @@ namespace ts {
570570

571571
export interface Identifier extends PrimaryExpression {
572572
kind: SyntaxKind.Identifier;
573-
text: string; // Text of identifier (with escapes converted to characters)
574-
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
575-
/*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier.
576-
/*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name.
577-
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
578-
/*@internal*/ typeArguments: NodeArray<TypeNode>; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics.
573+
text: string; // Text of identifier (with escapes converted to characters)
574+
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
575+
/*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier.
576+
/*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name.
577+
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
578+
/*@internal*/ typeArguments?: NodeArray<TypeNode>; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics.
579579
}
580580

581581
// Transient identifier node (marked by id === -1)

0 commit comments

Comments
 (0)