Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 384d546

Browse filesBrowse files
author
Arthur Ozga
committed
Basic parens handling and stubbed TypeFormatFlags
1 parent d0f3716 commit 384d546
Copy full SHA for 384d546

6 files changed

+107-25Lines changed: 107 additions & 25 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+60-14Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,8 +2287,16 @@ namespace ts {
22872287
interface NodeBuilderContext {
22882288
readonly enclosingDeclaration: Node | undefined;
22892289
readonly flags: NodeBuilderFlags | undefined;
2290+
2291+
// State
22902292
encounteredError: boolean;
22912293
inObjectTypeLiteral: boolean;
2294+
// TODO: needed for part of parens handling
2295+
InElementType: boolean; // Writing an array or union element type
2296+
// TODO: ???
2297+
InFirstTypeArgument: boolean; // Writing first type argument of the instantiated type
2298+
// TODO: ???
2299+
InTypeAlias: boolean; // Writing type in type alias declaration
22922300
checkAlias: boolean;
22932301
symbolStack: Symbol[] | undefined;
22942302
}
@@ -2299,18 +2307,28 @@ namespace ts {
22992307
flags,
23002308
encounteredError: false,
23012309
inObjectTypeLiteral: false,
2310+
InElementType: false,
2311+
InFirstTypeArgument: false,
2312+
InTypeAlias: false,
23022313
checkAlias: true,
23032314
symbolStack: undefined
23042315
};
23052316
}
23062317

23072318
function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode {
2319+
const InElementType = context.InElementType;
2320+
// TODO: why doesn't tts unset the flag?
2321+
context.InElementType = false;
2322+
2323+
// TODO: should be assert?
23082324
if (!type) {
23092325
context.encounteredError = true;
23102326
// TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)?
23112327
return undefined;
23122328
}
23132329

2330+
2331+
23142332
if (type.flags & TypeFlags.Any) {
23152333
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
23162334
}
@@ -2390,16 +2408,17 @@ namespace ts {
23902408

23912409
if (context.checkAlias && type.aliasSymbol) {
23922410
const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context);
2393-
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments);
2411+
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false);
23942412
return createTypeReferenceNode(name, typeArgumentNodes);
23952413
}
23962414
context.checkAlias = false;
23972415

2398-
if (type.flags & TypeFlags.Union) {
2399-
const formattedUnionTypes = formatUnionTypes((<UnionType>type).types);
2400-
const unionTypeNodes = formattedUnionTypes && mapToTypeNodeArray(formattedUnionTypes);
2401-
if (unionTypeNodes && unionTypeNodes.length > 0) {
2402-
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, unionTypeNodes);
2416+
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
2417+
const types = type.flags & TypeFlags.Union ? formatUnionTypes((<UnionType>type).types) : (<IntersectionType>type).types;
2418+
const typeNodes = types && mapToTypeNodeArray(types, /*addInElementTypeFlag*/ true);
2419+
if (typeNodes && typeNodes.length > 0) {
2420+
const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes);
2421+
return InElementType ? createParenthesizedTypeNode(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode;
24032422
}
24042423
else {
24052424
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) {
@@ -2409,10 +2428,6 @@ namespace ts {
24092428
}
24102429
}
24112430

2412-
if (type.flags & TypeFlags.Intersection) {
2413-
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types));
2414-
}
2415-
24162431
if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
24172432
Debug.assert(!!(type.flags & TypeFlags.Object));
24182433
// The type is an object literal type.
@@ -2421,25 +2436,33 @@ namespace ts {
24212436

24222437
if (type.flags & TypeFlags.Index) {
24232438
const indexedType = (<IndexType>type).type;
2439+
context.InElementType = <boolean>true;
24242440
const indexTypeNode = typeToTypeNodeHelper(indexedType, context);
2441+
Debug.assert(context.InElementType === false);
24252442
return createTypeOperatorNode(indexTypeNode);
24262443
}
2444+
24272445
if (type.flags & TypeFlags.IndexedAccess) {
2446+
context.InElementType = <boolean>true;
24282447
const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType, context);
2448+
Debug.assert(context.InElementType === false);
24292449
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
24302450
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
24312451
}
24322452

24332453
Debug.fail("Should be unreachable.");
24342454

2435-
function mapToTypeNodeArray(types: Type[]): TypeNode[] {
2455+
function mapToTypeNodeArray(types: Type[], addInElementTypeFlag: boolean): TypeNode[] {
24362456
const result = [];
2457+
Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper");
24372458
for (const type of types) {
2459+
context.InElementType = addInElementTypeFlag;
24382460
const typeNode = typeToTypeNodeHelper(type, context);
24392461
if (typeNode) {
24402462
result.push(typeNode);
24412463
}
24422464
}
2465+
Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper");
24432466
return result;
24442467
}
24452468

@@ -2523,6 +2546,7 @@ namespace ts {
25232546

25242547
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
25252548
const signature = resolved.callSignatures[0];
2549+
shouldAddParenthesisAroundFunctionType(signature, context);
25262550
return <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context);
25272551
}
25282552
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
@@ -2538,6 +2562,20 @@ namespace ts {
25382562
return createTypeLiteralNode(members);
25392563
}
25402564

2565+
2566+
function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) {
2567+
if (context.InElementType) {
2568+
return true;
2569+
}
2570+
else if (context.InFirstTypeArgument) {
2571+
// Add parenthesis around function type for the first type argument to avoid ambiguity
2572+
const typeParameters = callSignature.target && (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature) ?
2573+
callSignature.target.typeParameters : callSignature.typeParameters;
2574+
return typeParameters && typeParameters.length !== 0;
2575+
}
2576+
return false;
2577+
}
2578+
25412579
function createTypeQueryNodeFromSymbol(symbol: Symbol) {
25422580
const entityName = symbolToName(symbol, /*expectsIdentifier*/ false, context);
25432581
return createTypeQueryNode(entityName);
@@ -2546,12 +2584,14 @@ namespace ts {
25462584
function typeReferenceToTypeNode(type: TypeReference) {
25472585
const typeArguments: Type[] = type.typeArguments || emptyArray;
25482586
if (type.target === globalArrayType) {
2587+
context.InElementType = true;
25492588
const elementType = typeToTypeNodeHelper(typeArguments[0], context);
2589+
context.InElementType = false;
25502590
return createArrayTypeNode(elementType);
25512591
}
25522592
else if (type.target.objectFlags & ObjectFlags.Tuple) {
25532593
if (typeArguments.length > 0) {
2554-
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)));
2594+
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), /*addInElementTypeFlag*/ false);
25552595
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
25562596
return createTupleTypeNode(tupleConstituentNodes);
25572597
}
@@ -2566,6 +2606,7 @@ namespace ts {
25662606
let i = 0;
25672607
let qualifiedName: QualifiedName | undefined = undefined;
25682608
if (outerTypeParameters) {
2609+
let inFirstTypeArgument = true;
25692610
const length = outerTypeParameters.length;
25702611
while (i < length) {
25712612
// Find group of type arguments for type parameters with the same declaring container.
@@ -2577,6 +2618,7 @@ namespace ts {
25772618
// When type parameters are their own type arguments for the whole group (i.e. we have
25782619
// the default outer type arguments), we don't show the group.
25792620
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
2621+
// inFirstTypeArgument???
25802622
const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, context);
25812623
if (!qualifiedName) {
25822624
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined);
@@ -2587,6 +2629,7 @@ namespace ts {
25872629
qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined);
25882630
}
25892631
}
2632+
inFirstTypeArgument = false;
25902633
}
25912634
}
25922635
let entityName: EntityName = undefined;
@@ -2600,7 +2643,7 @@ namespace ts {
26002643
entityName = nameIdentifier;
26012644
}
26022645
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
2603-
const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i)) : undefined;
2646+
const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i), /*addInElementTypeFlag*/ false) : undefined;
26042647
return createTypeReferenceNode(entityName, typeArgumentNodes);
26052648
}
26062649
}
@@ -2695,7 +2738,7 @@ namespace ts {
26952738
const returnType = getReturnTypeOfSignature(signature);
26962739
returnTypeNode = returnType && typeToTypeNodeHelper(returnType, context);
26972740
}
2698-
if(context.flags & NodeBuilderFlags.suppressAnyReturnType) {
2741+
if(context.flags & NodeBuilderFlags.SuppressAnyReturnType) {
26992742
if(returnTypeNode && returnTypeNode.kind === SyntaxKind.AnyKeyword) {
27002743
returnTypeNode = undefined;
27012744
}
@@ -2733,6 +2776,8 @@ namespace ts {
27332776
return parameterNode;
27342777
}
27352778

2779+
// TODO: add meaning: SymbolFlags argument.
2780+
// TODO: add SymbolFormatFlags?? Yes to add outer type parameters. Defer UseOnlyExternalAliasing until a separate symbolbuilder PR.
27362781
function symbolToName(symbol: Symbol, expectsIdentifier: true, context: NodeBuilderContext): Identifier;
27372782
function symbolToName(symbol: Symbol, expectsIdentifier: false, context: NodeBuilderContext): EntityName;
27382783
function symbolToName(symbol: Symbol, expectsIdentifier: boolean, context: NodeBuilderContext): EntityName {
@@ -2826,6 +2871,7 @@ namespace ts {
28262871
}
28272872
}
28282873
}
2874+
28292875
function getNameOfSymbol(symbol: Symbol, context: NodeBuilderContext): string {
28302876
const declaration = firstOrUndefined(symbol.declarations);
28312877
if (declaration) {
Collapse file

‎src/compiler/emitter.ts‎

Copy file name to clipboardExpand all lines: src/compiler/emitter.ts
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2947,8 +2947,9 @@ namespace ts {
29472947
// Precomputed Formats
29482948
Modifiers = SingleLine | SpaceBetweenSiblings,
29492949
HeritageClauses = SingleLine | SpaceBetweenSiblings,
2950-
SingleLineTypeLiteralMembers = SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented,
2950+
SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented,
29512951
MultiLineTypeLiteralMembers = MultiLine | Indented,
2952+
29522953
TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented,
29532954
UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine,
29542955
IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
Collapse file

‎src/compiler/factory.ts‎

Copy file name to clipboardExpand all lines: src/compiler/factory.ts
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,18 @@ namespace ts {
393393
: node;
394394
}
395395

396+
export function createParenthesizedTypeNode(type: TypeNode) {
397+
const parenthesizedTypeNode = createSynthesizedNode(SyntaxKind.ParenthesizedType) as ParenthesizedTypeNode;
398+
parenthesizedTypeNode.type = type;
399+
return parenthesizedTypeNode;
400+
}
401+
402+
export function updateParenthesizedTypeNode(node: ParenthesizedTypeNode, type: TypeNode) {
403+
return node.type !== type
404+
? updateNode(createParenthesizedTypeNode(type), node)
405+
: node;
406+
}
407+
396408
export function createTypeLiteralNode(members: TypeElement[]) {
397409
const typeLiteralNode = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode;
398410
typeLiteralNode.members = createNodeArray(members);
Collapse file

‎src/compiler/types.ts‎

Copy file name to clipboardExpand all lines: src/compiler/types.ts
+30-8Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2559,14 +2559,36 @@ namespace ts {
25592559

25602560
export enum NodeBuilderFlags {
25612561
None = 0,
2562-
allowThisInObjectLiteral = 1 << 0,
2563-
allowQualifedNameInPlaceOfIdentifier = 1 << 1,
2564-
allowTypeParameterInQualifiedName = 1 << 2,
2565-
allowAnonymousIdentifier = 1 << 3,
2566-
allowEmptyUnionOrIntersection = 1 << 4,
2567-
allowEmptyTuple = 1 << 5,
2568-
suppressAnyReturnType = 1 << 6,
2569-
ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple
2562+
// Options
2563+
NoTruncation = 1 << 0, // Don't truncate result
2564+
// TODO: part of emit.
2565+
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
2566+
// TODO: part of emit.
2567+
UseTypeOfFunction = 1 << 2, // Write typeof instead of function type literal
2568+
// TODO: part of emit.
2569+
WriteArrowStyleSignature = 1 << 3, // Write arrow style signature
2570+
// TODO: turn it into a failing type reference?
2571+
WriteOwnNameForAnyLike = 1 << 4, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc)
2572+
// TODO
2573+
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
2574+
// TODO
2575+
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
2576+
// TODO
2577+
UseTypeAliasValue = 1 << 7, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
2578+
SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type.
2579+
// TODO
2580+
AddUndefined = 1 << 9, // Add undefined to types of initialized, non-optional parameters
2581+
2582+
// Error handling
2583+
allowThisInObjectLiteral = 1 << 10,
2584+
allowQualifedNameInPlaceOfIdentifier = 1 << 11,
2585+
allowTypeParameterInQualifiedName = 1 << 12,
2586+
allowAnonymousIdentifier = 1 << 13,
2587+
allowEmptyUnionOrIntersection = 1 << 14,
2588+
allowEmptyTuple = 1 << 15,
2589+
2590+
ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple,
2591+
25702592
}
25712593

25722594
export interface SymbolDisplayBuilder {
Collapse file

‎src/compiler/visitor.ts‎

Copy file name to clipboardExpand all lines: src/compiler/visitor.ts
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ namespace ts {
322322
nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
323323

324324
case SyntaxKind.ParenthesizedType:
325-
throw Debug.fail("not implemented.");
325+
return updateParenthesizedTypeNode(<ParenthesizedTypeNode>node,
326+
visitNode((<ParenthesizedTypeNode>node).type, visitor, isTypeNode));
326327

327328
case SyntaxKind.TypeOperator:
328329
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
Collapse file

‎src/services/codefixes/helpers.ts‎

Copy file name to clipboardExpand all lines: src/services/codefixes/helpers.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ namespace ts.codefix {
130130
}
131131

132132
function signatureToMethodDeclaration(signature: Signature, enclosingDeclaration: Node, body?: Block) {
133-
const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.suppressAnyReturnType);
133+
const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.SuppressAnyReturnType);
134134
if (signatureDeclaration) {
135135
signatureDeclaration.decorators = undefined;
136136
signatureDeclaration.modifiers = modifiers;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.