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