From 48588b622e50d2e90ea8aae1f856e9483f2c476b Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 16 Jul 2015 18:17:28 -0700 Subject: [PATCH] Only consider a type resolution sequence a cycle if none of the items in the sequence have types --- src/compiler/checker.ts | 49 ++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d0c5667a340..9211437b42f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -161,6 +161,7 @@ namespace ts { let resolutionTargets: Object[] = []; let resolutionResults: boolean[] = []; + let resolutionKinds: TypeSystemObjectKind[] = []; let mergedSymbols: Symbol[] = []; let symbolLinks: SymbolLinks[] = []; @@ -201,6 +202,13 @@ namespace ts { let assignableRelation: Map = {}; let identityRelation: Map = {}; + enum TypeSystemObjectKind { + Symbol, + Type, + SymbolLinks, + Signature + } + initializeTypeChecker(); return checker; @@ -2184,13 +2192,14 @@ namespace ts { // 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): boolean { - let i = 0; + function pushTypeResolution(target: Object, flags: TypeSystemObjectKind): boolean { let count = resolutionTargets.length; - while (i < count && resolutionTargets[i] !== target) { - i++; + let i = count - 1; + let foundGoodType = false; + while (i >= 0 && !(foundGoodType = !!hasType(resolutionTargets[i], resolutionKinds[i])) && resolutionTargets[i] !== target) { + i--; } - if (i < count) { + if (i >= 0 && !foundGoodType) { do { resolutionResults[i++] = false; } @@ -2199,13 +2208,33 @@ namespace ts { } resolutionTargets.push(target); resolutionResults.push(true); + resolutionKinds.push(flags); return true; } + function hasType(target: Object, flags: TypeSystemObjectKind): Type { + if (flags === TypeSystemObjectKind.Symbol) { + return getSymbolLinks(target).type; + } + else if (flags === TypeSystemObjectKind.Type) { + Debug.assert(!!((target).flags & TypeFlags.Class)); + return (target).resolvedBaseConstructorType; + } + else if (flags === TypeSystemObjectKind.SymbolLinks) { + return (target).declaredType; + } + else if (flags === TypeSystemObjectKind.Signature) { + return (target).resolvedReturnType; + } + + Debug.fail("Unhandled TypeSystemObjectKind"); + } + // Pop an entry from the type resolution stack and return its associated result value. The result value will // be true if no circularities were detected, or false if a circularity was found. function popTypeResolution(): boolean { resolutionTargets.pop(); + resolutionKinds.pop(); return resolutionResults.pop(); } @@ -2468,7 +2497,7 @@ namespace ts { return links.type = checkExpression((declaration).expression); } // Handle variable, parameter or property - if (!pushTypeResolution(symbol)) { + if (!pushTypeResolution(symbol, TypeSystemObjectKind.Symbol)) { return unknownType; } let type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); @@ -2509,7 +2538,7 @@ namespace ts { function getTypeOfAccessors(symbol: Symbol): Type { let links = getSymbolLinks(symbol); if (!links.type) { - if (!pushTypeResolution(symbol)) { + if (!pushTypeResolution(symbol, TypeSystemObjectKind.Symbol)) { return unknownType; } let getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); @@ -2725,7 +2754,7 @@ namespace ts { if (!baseTypeNode) { return type.resolvedBaseConstructorType = undefinedType; } - if (!pushTypeResolution(type)) { + if (!pushTypeResolution(type, TypeSystemObjectKind.Type)) { return unknownType; } let baseConstructorType = checkExpression(baseTypeNode.expression); @@ -2852,7 +2881,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)) { + if (!pushTypeResolution(links, TypeSystemObjectKind.SymbolLinks)) { return unknownType; } let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); @@ -3539,7 +3568,7 @@ namespace ts { function getReturnTypeOfSignature(signature: Signature): Type { if (!signature.resolvedReturnType) { - if (!pushTypeResolution(signature)) { + if (!pushTypeResolution(signature, TypeSystemObjectKind.Signature)) { return unknownType; } let type: Type;