Skip to content

Commit 3b78377

Browse files
committed
Clean up pushTypeResolution
1 parent c0b3835 commit 3b78377

File tree

2 files changed

+53
-38
lines changed

2 files changed

+53
-38
lines changed

src/compiler/checker.ts

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ namespace ts {
159159
let emitAwaiter = false;
160160
let emitGenerator = false;
161161

162-
let resolutionTargets: Object[] = [];
162+
let resolutionTargets: TypeSystemEntity[] = [];
163163
let resolutionResults: boolean[] = [];
164-
let resolutionKinds: TypeSystemObjectKind[] = [];
164+
let resolutionPropertyNames: TypeSystemPropertyName[] = [];
165165

166166
let mergedSymbols: Symbol[] = [];
167167
let symbolLinks: SymbolLinks[] = [];
@@ -202,11 +202,11 @@ namespace ts {
202202
let assignableRelation: Map<RelationComparisonResult> = {};
203203
let identityRelation: Map<RelationComparisonResult> = {};
204204

205-
enum TypeSystemObjectKind {
206-
Symbol,
205+
enum TypeSystemPropertyName {
207206
Type,
208-
SymbolLinks,
209-
Signature
207+
ResolvedBaseConstructorType,
208+
DeclaredType,
209+
ResolvedReturnType
210210
}
211211

212212
initializeTypeChecker();
@@ -2185,45 +2185,58 @@ namespace ts {
21852185
}
21862186
}
21872187

2188-
// Push an entry on the type resolution stack. If an entry with the given target is not already on the stack,
2189-
// a new entry with that target and an associated result value of true is pushed on the stack, and the value
2190-
// true is returned. Otherwise, a circularity has occurred and the result values of the existing entry and
2191-
// all entries pushed after it are changed to false, and the value false is returned. The target object provides
2192-
// a unique identity for a particular type resolution result: Symbol instances are used to track resolution of
2193-
// SymbolLinks.type, SymbolLinks instances are used to track resolution of SymbolLinks.declaredType, and
2194-
// Signature instances are used to track resolution of Signature.resolvedReturnType.
2195-
function pushTypeResolution(target: Object, flags: TypeSystemObjectKind): boolean {
2196-
let count = resolutionTargets.length;
2197-
let i = count - 1;
2198-
let foundGoodType = false;
2199-
while (i >= 0 && !(foundGoodType = !!hasType(resolutionTargets[i], resolutionKinds[i])) && resolutionTargets[i] !== target) {
2200-
i--;
2201-
}
2202-
if (i >= 0 && !foundGoodType) {
2203-
do {
2204-
resolutionResults[i++] = false;
2188+
/**
2189+
* Push an entry on the type resolution stack. If an entry with the given target and the given property name
2190+
* is already on the stack, and no entries in between already have a type, then a circularity has occurred.
2191+
* In this case, the result values of the existing entry and all entries pushed after it are changed to false,
2192+
* and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned.
2193+
* In order to see if the same query has already been done before, the target object and the propertyName both
2194+
* must match the one passed in.
2195+
*
2196+
* @param target The symbol, type, or signature whose type is being queried
2197+
* @param propertyName The property name that should be used to query the target for its type
2198+
*/
2199+
function pushTypeResolution(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean {
2200+
let resolutionCycleStartIndex = findResolutionCycleStartIndex(target, propertyName);
2201+
if (resolutionCycleStartIndex >= 0) {
2202+
// A cycle was found
2203+
let { length } = resolutionTargets;
2204+
for (let i = resolutionCycleStartIndex; i < length; i++) {
2205+
resolutionResults[i] = false;
22052206
}
2206-
while (i < count);
22072207
return false;
22082208
}
22092209
resolutionTargets.push(target);
22102210
resolutionResults.push(true);
2211-
resolutionKinds.push(flags);
2211+
resolutionPropertyNames.push(propertyName);
22122212
return true;
22132213
}
22142214

2215-
function hasType(target: Object, flags: TypeSystemObjectKind): Type {
2216-
if (flags === TypeSystemObjectKind.Symbol) {
2215+
function findResolutionCycleStartIndex(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): number {
2216+
for (let i = resolutionTargets.length - 1; i >= 0; i--) {
2217+
if (hasType(resolutionTargets[i], resolutionPropertyNames[i])) {
2218+
return -1;
2219+
}
2220+
if (resolutionTargets[i] === target && resolutionPropertyNames[i] === propertyName) {
2221+
return i;
2222+
}
2223+
}
2224+
2225+
return -1;
2226+
}
2227+
2228+
function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): Type {
2229+
if (propertyName === TypeSystemPropertyName.Type) {
22172230
return getSymbolLinks(<Symbol>target).type;
22182231
}
2219-
else if (flags === TypeSystemObjectKind.Type) {
2232+
else if (propertyName === TypeSystemPropertyName.DeclaredType) {
2233+
return getSymbolLinks(<Symbol>target).declaredType;
2234+
}
2235+
else if (propertyName === TypeSystemPropertyName.ResolvedBaseConstructorType) {
22202236
Debug.assert(!!((<Type>target).flags & TypeFlags.Class));
22212237
return (<InterfaceType>target).resolvedBaseConstructorType;
22222238
}
2223-
else if (flags === TypeSystemObjectKind.SymbolLinks) {
2224-
return (<SymbolLinks>target).declaredType;
2225-
}
2226-
else if (flags === TypeSystemObjectKind.Signature) {
2239+
else if (propertyName === TypeSystemPropertyName.ResolvedReturnType) {
22272240
return (<Signature>target).resolvedReturnType;
22282241
}
22292242

@@ -2234,7 +2247,7 @@ namespace ts {
22342247
// be true if no circularities were detected, or false if a circularity was found.
22352248
function popTypeResolution(): boolean {
22362249
resolutionTargets.pop();
2237-
resolutionKinds.pop();
2250+
resolutionPropertyNames.pop();
22382251
return resolutionResults.pop();
22392252
}
22402253

@@ -2497,7 +2510,7 @@ namespace ts {
24972510
return links.type = checkExpression((<ExportAssignment>declaration).expression);
24982511
}
24992512
// Handle variable, parameter or property
2500-
if (!pushTypeResolution(symbol, TypeSystemObjectKind.Symbol)) {
2513+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
25012514
return unknownType;
25022515
}
25032516
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
@@ -2538,7 +2551,7 @@ namespace ts {
25382551
function getTypeOfAccessors(symbol: Symbol): Type {
25392552
let links = getSymbolLinks(symbol);
25402553
if (!links.type) {
2541-
if (!pushTypeResolution(symbol, TypeSystemObjectKind.Symbol)) {
2554+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
25422555
return unknownType;
25432556
}
25442557
let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
@@ -2754,7 +2767,7 @@ namespace ts {
27542767
if (!baseTypeNode) {
27552768
return type.resolvedBaseConstructorType = undefinedType;
27562769
}
2757-
if (!pushTypeResolution(type, TypeSystemObjectKind.Type)) {
2770+
if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) {
27582771
return unknownType;
27592772
}
27602773
let baseConstructorType = checkExpression(baseTypeNode.expression);
@@ -2881,7 +2894,7 @@ namespace ts {
28812894
if (!links.declaredType) {
28822895
// Note that we use the links object as the target here because the symbol object is used as the unique
28832896
// identity for resolution of the 'type' property in SymbolLinks.
2884-
if (!pushTypeResolution(links, TypeSystemObjectKind.SymbolLinks)) {
2897+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) {
28852898
return unknownType;
28862899
}
28872900
let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
@@ -3568,7 +3581,7 @@ namespace ts {
35683581

35693582
function getReturnTypeOfSignature(signature: Signature): Type {
35703583
if (!signature.resolvedReturnType) {
3571-
if (!pushTypeResolution(signature, TypeSystemObjectKind.Signature)) {
3584+
if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) {
35723585
return unknownType;
35733586
}
35743587
let type: Type;

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,8 @@ namespace ts {
19041904
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
19051905
}
19061906

1907+
export type TypeSystemEntity = Symbol | Type | Signature;
1908+
19071909
export const enum IndexKind {
19081910
String,
19091911
Number,

0 commit comments

Comments
 (0)