From 709f5f2fc47eb9d28798f5933864d05711720dee Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Oct 2018 10:18:54 -0700 Subject: [PATCH] Handle circular mapped type instantiations for arrays and tuples --- src/compiler/checker.ts | 12 +++++++++++- src/compiler/types.ts | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 795b893f69e..4d397bcc71c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10365,7 +10365,15 @@ namespace ts { if (typeVariable) { const mappedTypeVariable = instantiateType(typeVariable, mapper); if (typeVariable !== mappedTypeVariable) { - return mapType(mappedTypeVariable, t => { + // If we are already in the process of creating an instantiation of this mapped type, + // return the error type. This situation only arises if we are instantiating the mapped + // type for an array or tuple type, as we then need to eagerly resolve the (possibly + // circular) element type(s). + if (type.instantiating) { + return errorType; + } + type.instantiating = true; + const result = mapType(mappedTypeVariable, t => { if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType) { const replacementMapper = createReplacementMapper(typeVariable, t, mapper); return isArrayType(t) ? createArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) : @@ -10375,6 +10383,8 @@ namespace ts { } return t; }); + type.instantiating = false; + return result; } } return instantiateAnonymousType(type, mapper); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3bd103579f1..5763ab3eff0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4074,6 +4074,7 @@ namespace ts { templateType?: Type; modifiersType?: Type; resolvedApparentType?: Type; + instantiating?: boolean; } export interface EvolvingArrayType extends ObjectType {