From ed497c414930452958961cf30a8cb1c7601dbb22 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 30 Sep 2019 08:54:02 -0700 Subject: [PATCH] Properly handle recursive type references in type inference --- src/compiler/checker.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0731ccbf04c..61cf45c6c15 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17021,7 +17021,7 @@ namespace ts { function couldContainTypeVariables(type: Type): boolean { const objectFlags = getObjectFlags(type); return !!(type.flags & TypeFlags.Instantiable || - objectFlags & ObjectFlags.Reference && forEach(getTypeArguments(type), couldContainTypeVariables) || + objectFlags & ObjectFlags.Reference && ((type).node || forEach(getTypeArguments(type), couldContainTypeVariables)) || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || objectFlags & ObjectFlags.Mapped || type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && couldUnionOrIntersectionContainTypeVariables(type)); @@ -17318,7 +17318,8 @@ namespace ts { } } if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( - (source).target === (target).target || isArrayType(source) && isArrayType(target))) { + (source).target === (target).target || isArrayType(source) && isArrayType(target)) && + !((source).node && (target).node)) { // If source and target are references to the same generic type, infer from type arguments inferFromTypeArguments(getTypeArguments(source), getTypeArguments(target), getVariances((source).target)); } @@ -17599,6 +17600,12 @@ namespace ts { } function inferFromObjectTypesWorker(source: Type, target: Type) { + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( + (source).target === (target).target || isArrayType(source) && isArrayType(target))) { + // If source and target are references to the same generic type, infer from type arguments + inferFromTypeArguments(getTypeArguments(source), getTypeArguments(target), getVariances((source).target)); + return; + } if (isGenericMappedType(source) && isGenericMappedType(target)) { // The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer // from S to T and from X to Y.