Clean up pushTypeResolution

This commit is contained in:
Jason Freeman 2015-07-17 17:01:37 -07:00
parent c0b3835b19
commit 3b78377cf0
2 changed files with 53 additions and 38 deletions

View file

@ -159,9 +159,9 @@ namespace ts {
let emitAwaiter = false; let emitAwaiter = false;
let emitGenerator = false; let emitGenerator = false;
let resolutionTargets: Object[] = []; let resolutionTargets: TypeSystemEntity[] = [];
let resolutionResults: boolean[] = []; let resolutionResults: boolean[] = [];
let resolutionKinds: TypeSystemObjectKind[] = []; let resolutionPropertyNames: TypeSystemPropertyName[] = [];
let mergedSymbols: Symbol[] = []; let mergedSymbols: Symbol[] = [];
let symbolLinks: SymbolLinks[] = []; let symbolLinks: SymbolLinks[] = [];
@ -202,11 +202,11 @@ namespace ts {
let assignableRelation: Map<RelationComparisonResult> = {}; let assignableRelation: Map<RelationComparisonResult> = {};
let identityRelation: Map<RelationComparisonResult> = {}; let identityRelation: Map<RelationComparisonResult> = {};
enum TypeSystemObjectKind { enum TypeSystemPropertyName {
Symbol,
Type, Type,
SymbolLinks, ResolvedBaseConstructorType,
Signature DeclaredType,
ResolvedReturnType
} }
initializeTypeChecker(); initializeTypeChecker();
@ -2185,45 +2185,58 @@ namespace ts {
} }
} }
// Push an entry on the type resolution stack. If an entry with the given target is not already on the stack, /**
// a new entry with that target and an associated result value of true is pushed on the stack, and the value * Push an entry on the type resolution stack. If an entry with the given target and the given property name
// true is returned. Otherwise, a circularity has occurred and the result values of the existing entry and * is already on the stack, and no entries in between already have a type, then a circularity has occurred.
// all entries pushed after it are changed to false, and the value false is returned. The target object provides * In this case, the result values of the existing entry and all entries pushed after it are changed to false,
// a unique identity for a particular type resolution result: Symbol instances are used to track resolution of * and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned.
// SymbolLinks.type, SymbolLinks instances are used to track resolution of SymbolLinks.declaredType, and * In order to see if the same query has already been done before, the target object and the propertyName both
// Signature instances are used to track resolution of Signature.resolvedReturnType. * must match the one passed in.
function pushTypeResolution(target: Object, flags: TypeSystemObjectKind): boolean { *
let count = resolutionTargets.length; * @param target The symbol, type, or signature whose type is being queried
let i = count - 1; * @param propertyName The property name that should be used to query the target for its type
let foundGoodType = false; */
while (i >= 0 && !(foundGoodType = !!hasType(resolutionTargets[i], resolutionKinds[i])) && resolutionTargets[i] !== target) { function pushTypeResolution(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean {
i--; let resolutionCycleStartIndex = findResolutionCycleStartIndex(target, propertyName);
} if (resolutionCycleStartIndex >= 0) {
if (i >= 0 && !foundGoodType) { // A cycle was found
do { let { length } = resolutionTargets;
resolutionResults[i++] = false; for (let i = resolutionCycleStartIndex; i < length; i++) {
resolutionResults[i] = false;
} }
while (i < count);
return false; return false;
} }
resolutionTargets.push(target); resolutionTargets.push(target);
resolutionResults.push(true); resolutionResults.push(true);
resolutionKinds.push(flags); resolutionPropertyNames.push(propertyName);
return true; return true;
} }
function hasType(target: Object, flags: TypeSystemObjectKind): Type { function findResolutionCycleStartIndex(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): number {
if (flags === TypeSystemObjectKind.Symbol) { for (let i = resolutionTargets.length - 1; i >= 0; i--) {
if (hasType(resolutionTargets[i], resolutionPropertyNames[i])) {
return -1;
}
if (resolutionTargets[i] === target && resolutionPropertyNames[i] === propertyName) {
return i;
}
}
return -1;
}
function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): Type {
if (propertyName === TypeSystemPropertyName.Type) {
return getSymbolLinks(<Symbol>target).type; return getSymbolLinks(<Symbol>target).type;
} }
else if (flags === TypeSystemObjectKind.Type) { else if (propertyName === TypeSystemPropertyName.DeclaredType) {
return getSymbolLinks(<Symbol>target).declaredType;
}
else if (propertyName === TypeSystemPropertyName.ResolvedBaseConstructorType) {
Debug.assert(!!((<Type>target).flags & TypeFlags.Class)); Debug.assert(!!((<Type>target).flags & TypeFlags.Class));
return (<InterfaceType>target).resolvedBaseConstructorType; return (<InterfaceType>target).resolvedBaseConstructorType;
} }
else if (flags === TypeSystemObjectKind.SymbolLinks) { else if (propertyName === TypeSystemPropertyName.ResolvedReturnType) {
return (<SymbolLinks>target).declaredType;
}
else if (flags === TypeSystemObjectKind.Signature) {
return (<Signature>target).resolvedReturnType; return (<Signature>target).resolvedReturnType;
} }
@ -2234,7 +2247,7 @@ namespace ts {
// be true if no circularities were detected, or false if a circularity was found. // be true if no circularities were detected, or false if a circularity was found.
function popTypeResolution(): boolean { function popTypeResolution(): boolean {
resolutionTargets.pop(); resolutionTargets.pop();
resolutionKinds.pop(); resolutionPropertyNames.pop();
return resolutionResults.pop(); return resolutionResults.pop();
} }
@ -2497,7 +2510,7 @@ namespace ts {
return links.type = checkExpression((<ExportAssignment>declaration).expression); return links.type = checkExpression((<ExportAssignment>declaration).expression);
} }
// Handle variable, parameter or property // Handle variable, parameter or property
if (!pushTypeResolution(symbol, TypeSystemObjectKind.Symbol)) { if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return unknownType; return unknownType;
} }
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true); let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
@ -2538,7 +2551,7 @@ namespace ts {
function getTypeOfAccessors(symbol: Symbol): Type { function getTypeOfAccessors(symbol: Symbol): Type {
let links = getSymbolLinks(symbol); let links = getSymbolLinks(symbol);
if (!links.type) { if (!links.type) {
if (!pushTypeResolution(symbol, TypeSystemObjectKind.Symbol)) { if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return unknownType; return unknownType;
} }
let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); let getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
@ -2754,7 +2767,7 @@ namespace ts {
if (!baseTypeNode) { if (!baseTypeNode) {
return type.resolvedBaseConstructorType = undefinedType; return type.resolvedBaseConstructorType = undefinedType;
} }
if (!pushTypeResolution(type, TypeSystemObjectKind.Type)) { if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) {
return unknownType; return unknownType;
} }
let baseConstructorType = checkExpression(baseTypeNode.expression); let baseConstructorType = checkExpression(baseTypeNode.expression);
@ -2881,7 +2894,7 @@ namespace ts {
if (!links.declaredType) { if (!links.declaredType) {
// Note that we use the links object as the target here because the symbol object is used as the unique // Note that we use the links object as the target here because the symbol object is used as the unique
// identity for resolution of the 'type' property in SymbolLinks. // identity for resolution of the 'type' property in SymbolLinks.
if (!pushTypeResolution(links, TypeSystemObjectKind.SymbolLinks)) { if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) {
return unknownType; return unknownType;
} }
let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
@ -3568,7 +3581,7 @@ namespace ts {
function getReturnTypeOfSignature(signature: Signature): Type { function getReturnTypeOfSignature(signature: Signature): Type {
if (!signature.resolvedReturnType) { if (!signature.resolvedReturnType) {
if (!pushTypeResolution(signature, TypeSystemObjectKind.Signature)) { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) {
return unknownType; return unknownType;
} }
let type: Type; let type: Type;

View file

@ -1904,6 +1904,8 @@ namespace ts {
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
} }
export type TypeSystemEntity = Symbol | Type | Signature;
export const enum IndexKind { export const enum IndexKind {
String, String,
Number, Number,