From de8597ca8c31eec0e7c5e08bff149db8832fa978 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 May 2015 16:30:50 -0700 Subject: [PATCH] Add cache to instantiateType function to break cycles --- src/compiler/checker.ts | 14 ++++++++++++++ src/compiler/types.ts | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9bd0d6475fe..e49deba6032 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3866,6 +3866,19 @@ module ts { } function instantiateAnonymousType(type: ObjectType, mapper: TypeMapper): ObjectType { + // If this type has already been instantiated using this mapper, returned the cached result. This guards against + // infinite instantiations of cyclic types, e.g. "var x: { a: T, b: typeof x };" + if (mapper.mappings) { + for (let mapping of mapper.mappings) { + if (mapping.type === type) { + return mapping.result; + } + } + } + else { + mapper.mappings = []; + } + // Instantiate the given type using the given mapper and cache the result let result = createObjectType(TypeFlags.Anonymous, type.symbol); result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol); result.members = createSymbolTable(result.properties); @@ -3875,6 +3888,7 @@ module ts { let numberIndexType = getIndexTypeOfType(type, IndexKind.Number); if (stringIndexType) result.stringIndexType = instantiateType(stringIndexType, mapper); if (numberIndexType) result.numberIndexType = instantiateType(numberIndexType, mapper); + mapper.mappings.push({ type, result }); return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 86e680ca8b0..0f810c9fe61 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1586,9 +1586,15 @@ module ts { Number, } + export interface TypeMapping { + type: Type; + result: Type; + } + /* @internal */ export interface TypeMapper { (t: TypeParameter): Type; + mappings?: TypeMapping[]; // Type mapping cache } /* @internal */