Skip to content

Commit 20a4e32

Browse files
author
Arthur Ozga
committed
parenthesization in factory
1 parent 6fd86b4 commit 20a4e32

File tree

4 files changed

+52
-68
lines changed

4 files changed

+52
-68
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,7 +2279,7 @@ namespace ts {
22792279
}
22802280

22812281
function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
2282-
const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors);
2282+
const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName);
22832283
Debug.assert(typeNode !== undefined, "should always get typenode?");
22842284
const options = { removeComments: true };
22852285
const writer = createTextWriter("");
@@ -2360,10 +2360,8 @@ namespace ts {
23602360
}
23612361

23622362
function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode {
2363-
const inElementType = context.flags & NodeBuilderFlags.InElementType;
2364-
const inFirstTypeArgument = context.flags & NodeBuilderFlags.InFirstTypeArgument;
23652363
const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias;
2366-
context.flags &= ~(NodeBuilderFlags.StateClearingFlags);
2364+
context.flags &= ~(NodeBuilderFlags.InTypeAlias);
23672365

23682366
if (!type) {
23692367
context.encounteredError = true;
@@ -2443,15 +2441,15 @@ namespace ts {
24432441
if (!inTypeAlias && type.aliasSymbol &&
24442442
isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
24452443
const name = symbolToTypeReferenceName(type.aliasSymbol);
2446-
const typeArgumentNodes = toTypeArgumentNodes(type.aliasTypeArguments, context);
2444+
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context);
24472445
return createTypeReferenceNode(name, typeArgumentNodes);
24482446
}
24492447
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
24502448
const types = type.flags & TypeFlags.Union ? formatUnionTypes((<UnionType>type).types) : (<IntersectionType>type).types;
2451-
const typeNodes = types && mapToTypeNodeArray(types, context, /*addInElementTypeFlag*/ true, /*addInFirstTypeArgumentFlag*/ false);
2449+
const typeNodes = types && mapToTypeNodeArray(types, context);
24522450
if (typeNodes && typeNodes.length > 0) {
24532451
const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes);
2454-
return inElementType ? createParenthesizedType(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode;
2452+
return unionOrIntersectionTypeNode;
24552453
}
24562454
else {
24572455
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) {
@@ -2467,15 +2465,11 @@ namespace ts {
24672465
}
24682466
if (type.flags & TypeFlags.Index) {
24692467
const indexedType = (<IndexType>type).type;
2470-
context.flags |= NodeBuilderFlags.InElementType;
24712468
const indexTypeNode = typeToTypeNodeHelper(indexedType, context);
2472-
Debug.assert(!(context.flags & NodeBuilderFlags.InElementType));
24732469
return createTypeOperatorNode(indexTypeNode);
24742470
}
24752471
if (type.flags & TypeFlags.IndexedAccess) {
2476-
context.flags |= NodeBuilderFlags.InElementType;
24772472
const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType, context);
2478-
Debug.assert(!(context.flags & NodeBuilderFlags.InElementType));
24792473
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
24802474
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
24812475
}
@@ -2561,17 +2555,14 @@ namespace ts {
25612555
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
25622556
const signature = resolved.callSignatures[0];
25632557
const signatureNode = <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context);
2564-
return shouldAddParenthesisAroundFunctionType(signature, context) ?
2565-
createParenthesizedType(signatureNode) :
2566-
signatureNode;
2558+
return signatureNode;
25672559

25682560
}
2561+
25692562
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
25702563
const signature = resolved.constructSignatures[0];
25712564
const signatureNode = <ConstructorTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context);
2572-
return shouldAddParenthesisAroundFunctionType(signature, context) ?
2573-
createParenthesizedType(signatureNode) :
2574-
signatureNode;
2565+
return signatureNode;
25752566
}
25762567
}
25772568

@@ -2583,19 +2574,6 @@ namespace ts {
25832574
return setEmitFlags(typeLiteralNode, EmitFlags.SingleLine);
25842575
}
25852576

2586-
function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) {
2587-
if (inElementType) {
2588-
return true;
2589-
}
2590-
else if (inFirstTypeArgument) {
2591-
// Add parenthesis around function type for the first type argument to avoid ambiguity
2592-
const typeParameters = callSignature.target && (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature) ?
2593-
callSignature.target.typeParameters : callSignature.typeParameters;
2594-
return typeParameters && typeParameters.length !== 0;
2595-
}
2596-
return false;
2597-
}
2598-
25992577
function createTypeQueryNodeFromSymbol(symbol: Symbol, symbolFlags: SymbolFlags) {
26002578
const entityName = symbolToName(symbol, context, symbolFlags, /*expectsIdentifier*/ false);
26012579
return createTypeQueryNode(entityName);
@@ -2615,15 +2593,13 @@ namespace ts {
26152593
return createTypeReferenceNode("Array", [typeArgumentNode]);
26162594
}
26172595

2618-
context.flags |= NodeBuilderFlags.InElementType;
26192596
const elementType = typeToTypeNodeHelper(typeArguments[0], context);
2620-
Debug.assert(!(context.flags & NodeBuilderFlags.InElementType));
2621-
26222597
return createArrayTypeNode(elementType);
26232598
}
26242599
else if (type.target.objectFlags & ObjectFlags.Tuple) {
26252600
if (typeArguments.length > 0) {
2626-
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ false);
2601+
const slice = typeArguments.slice(0, getTypeReferenceArity(type));
2602+
const tupleConstituentNodes = slice && mapToTypeNodeArray(slice, context);
26272603
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
26282604
return createTupleTypeNode(tupleConstituentNodes);
26292605
}
@@ -2649,7 +2625,8 @@ namespace ts {
26492625
// When type parameters are their own type arguments for the whole group (i.e. we have
26502626
// the default outer type arguments), we don't show the group.
26512627
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
2652-
const typeArgumentNodes = createNodeArray(toTypeArgumentNodes(typeArguments.slice(start, i), context));
2628+
const slice = typeArguments.slice(start, i);
2629+
const typeArgumentNodes = slice && createNodeArray(mapToTypeNodeArray(slice, context));
26532630
const namePart = symbolToTypeReferenceName(parent);
26542631
(namePart.kind === SyntaxKind.Identifier ? <Identifier>namePart : namePart.right).typeArguments = typeArgumentNodes;
26552632

@@ -2680,7 +2657,7 @@ namespace ts {
26802657
if (some(typeArguments)) {
26812658
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
26822659
const slice = typeArguments && typeArguments.slice(i, typeParameterCount);
2683-
typeArgumentNodes = toTypeArgumentNodes(slice, context);
2660+
typeArgumentNodes = slice && mapToTypeNodeArray(slice, context);
26842661
}
26852662

26862663
if (typeArgumentNodes) {
@@ -2763,28 +2740,17 @@ namespace ts {
27632740
}
27642741
}
27652742

2766-
function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext, addInElementTypeFlag: boolean, addInFirstTypeArgumentFlag: boolean): TypeNode[] {
2743+
function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext): TypeNode[] {
27672744
const result = [];
2768-
Debug.assert(!(context.flags & NodeBuilderFlags.InElementType), "should be unset at the beginning of the helper");
27692745
for (let i = 0; i < types.length; ++i) {
27702746
const type = types[i];
2771-
if (addInElementTypeFlag) {
2772-
context.flags |= NodeBuilderFlags.InElementType;
2773-
}
2774-
if (i === 0 && addInFirstTypeArgumentFlag) {
2775-
context.flags |= NodeBuilderFlags.InFirstTypeArgument;
2776-
}
27772747
const typeNode = typeToTypeNodeHelper(type, context);
27782748
if (typeNode) {
27792749
result.push(typeNode);
27802750
}
27812751
}
2782-
Debug.assert(!(context.flags & NodeBuilderFlags.InElementType), "should be unset at the end of the helper");
2783-
return result;
2784-
}
27852752

2786-
function toTypeArgumentNodes(typeArguments: Type[], context: NodeBuilderContext) {
2787-
return typeArguments && mapToTypeNodeArray(typeArguments, context, /*addInElementTypeFlag*/ false, /*addInFirstTypeArgumentFlag*/ true);
2753+
return result;
27882754
}
27892755

27902756
function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration {
@@ -2909,7 +2875,7 @@ namespace ts {
29092875
Debug.assert(chain && 0 <= index && index < chain.length);
29102876
const symbol = chain[index];
29112877
let typeParameterNodes: TypeNode[] | undefined;
2912-
if (index > 0) {
2878+
if (context.flags & NodeBuilderFlags.WriteTypeParametersInQualifiedName && index > 0) {
29132879
const parentSymbol = chain[index - 1];
29142880
let typeParameters: TypeParameter[];
29152881
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
@@ -2921,11 +2887,9 @@ namespace ts {
29212887
typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
29222888
}
29232889
}
2890+
29242891
if (typeParameters && typeParameters.length > 0) {
2925-
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowTypeParameterInQualifiedName)) {
2926-
context.encounteredError = true;
2927-
}
2928-
typeParameterNodes = toTypeArgumentNodes(typeParameters, context);
2892+
typeParameterNodes = mapToTypeNodeArray(typeParameters, context);
29292893
}
29302894
}
29312895

src/compiler/factory.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ namespace ts {
506506
export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: TypeNode[] | undefined) {
507507
const node = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode;
508508
node.typeName = asName(typeName);
509-
node.typeArguments = asNodeArray(typeArguments);
509+
node.typeArguments = typeArguments && parenthesizeTypeParameters(typeArguments);
510510
return node;
511511
}
512512

@@ -559,7 +559,7 @@ namespace ts {
559559

560560
export function createArrayTypeNode(elementType: TypeNode) {
561561
const node = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode;
562-
node.elementType = elementType;
562+
node.elementType = parenthesizeElementTypeMember(elementType);
563563
return node;
564564
}
565565

@@ -599,7 +599,7 @@ namespace ts {
599599

600600
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]) {
601601
const node = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode;
602-
node.types = createNodeArray(types);
602+
node.types = parenthesizeElementTypeMembers(types);
603603
return node;
604604
}
605605

@@ -628,7 +628,7 @@ namespace ts {
628628
export function createTypeOperatorNode(type: TypeNode) {
629629
const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
630630
node.operator = SyntaxKind.KeyOfKeyword;
631-
node.type = type;
631+
node.type = parenthesizeElementTypeMember(type);
632632
return node;
633633
}
634634

@@ -638,7 +638,7 @@ namespace ts {
638638

639639
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
640640
const node = createSynthesizedNode(SyntaxKind.IndexedAccessType) as IndexedAccessTypeNode;
641-
node.objectType = objectType;
641+
node.objectType = parenthesizeElementTypeMember(objectType);
642642
node.indexType = indexType;
643643
return node;
644644
}
@@ -3595,19 +3595,34 @@ namespace ts {
35953595
return expression;
35963596
}
35973597

3598-
function parenthesizeElementTypeMember(member: TypeNode) {
3598+
export function parenthesizeElementTypeMember(member: TypeNode) {
35993599
switch (member.kind) {
36003600
case SyntaxKind.UnionType:
36013601
case SyntaxKind.IntersectionType:
36023602
case SyntaxKind.FunctionType:
36033603
case SyntaxKind.ConstructorType:
36043604
return createParenthesizedType(member);
36053605
}
3606+
return member;
36063607
}
3607-
function parenthesizeElementTypeMembers(members: NodeArray<TypeNode>) {
3608+
3609+
export function parenthesizeElementTypeMembers(members: TypeNode[]) {
3610+
// TODO: does this lose `originalNode` ptr?
36083611
return createNodeArray(members.map(parenthesizeElementTypeMember));
36093612
}
36103613

3614+
export function parenthesizeTypeParameters(typeParameters: TypeNode[]) {
3615+
if (typeParameters && typeParameters.length > 0) {
3616+
const nodeArray = createNodeArray(typeParameters);
3617+
const firstEntry = nodeArray[0];
3618+
if (isFunctionOrConstructor(firstEntry) && firstEntry.typeParameters) {
3619+
nodeArray[0] = createParenthesizedType(firstEntry);
3620+
}
3621+
3622+
return nodeArray;
3623+
}
3624+
}
3625+
36113626
/**
36123627
* Clones a series of not-emitted expressions with a new inner expression.
36133628
*

src/compiler/types.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,25 +2590,20 @@ namespace ts {
25902590
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
25912591
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
25922592
SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type.
2593+
WriteTypeParametersInQualifiedName = 1 << 9,
25932594

25942595
// Error handling
25952596
AllowThisInObjectLiteral = 1 << 10,
25962597
AllowQualifedNameInPlaceOfIdentifier = 1 << 11,
2597-
AllowTypeParameterInQualifiedName = 1 << 12,
25982598
AllowAnonymousIdentifier = 1 << 13,
25992599
AllowEmptyUnionOrIntersection = 1 << 14,
26002600
AllowEmptyTuple = 1 << 15,
26012601

2602-
ignoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowTypeParameterInQualifiedName | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple,
2602+
ignoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple,
26032603

26042604
// State
26052605
inObjectTypeLiteral = 1 << 20,
2606-
InElementType = 1 << 21, // Writing an array or union element type
2607-
InFirstTypeArgument = 1 << 22, // Writing first type argument of the instantiated type
26082606
InTypeAlias = 1 << 23, // Writing type in type alias declaration
2609-
2610-
/** Flags that should not be passed on to sub-nodes of the current node being built. */
2611-
StateClearingFlags = InElementType | InFirstTypeArgument | InTypeAlias
26122607
}
26132608

26142609
export interface SymbolDisplayBuilder {

src/compiler/utilities.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,16 @@ namespace ts {
881881
return false;
882882
}
883883

884+
export function isFunctionOrConstructor(node: Node): node is FunctionTypeNode | ConstructorTypeNode {
885+
switch (node.kind) {
886+
case SyntaxKind.FunctionType:
887+
case SyntaxKind.ConstructorType:
888+
return true;
889+
}
890+
891+
return false;
892+
}
893+
884894
export function introducesArgumentsExoticObject(node: Node) {
885895
switch (node.kind) {
886896
case SyntaxKind.MethodDeclaration:

0 commit comments

Comments
 (0)