diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 153cc6fb644a4..8e148c857e86e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5585,7 +5585,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags = ObjectFlags.None): IntrinsicType { const type = createType(kind) as IntrinsicType; type.intrinsicName = intrinsicName; - type.objectFlags = objectFlags; + type.objectFlags = objectFlags | ObjectFlags.CouldContainTypeVariablesComputed | ObjectFlags.IsGenericTypeComputed | ObjectFlags.IsUnknownLikeUnionComputed | ObjectFlags.IsNeverIntersectionComputed; return type; } @@ -18798,17 +18798,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type as DeferredTypeReference).target, (type as DeferredTypeReference).node, newMapper, newAliasSymbol, newAliasTypeArguments) : target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) : instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); - // If none of the type arguments for the outer type parameters contain type variables, it follows - // that the instantiated type doesn't reference type variables. - if (result.flags & TypeFlags.ObjectFlagsType && !((result as ObjectFlagsType).objectFlags & ObjectFlags.CouldContainTypeVariablesComputed)) { - const resultCouldContainTypeVariables = some(typeArguments, couldContainTypeVariables); - // The above check may have caused the result's objectFlags to update if the result is referenced via typeArguments. - if (!((result as ObjectFlagsType).objectFlags & ObjectFlags.CouldContainTypeVariablesComputed)) { - (result as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | - (resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariables : 0); + target.instantiations.set(id, result); // Set cached result early in case we recursively invoke instantiation while eagerly computing type variable visibility below + const resultObjectFlags = getObjectFlags(result); + if (result.flags & TypeFlags.ObjectFlagsType && !(resultObjectFlags & ObjectFlags.CouldContainTypeVariablesComputed)) { + const resultCouldContainTypeVariables = some(typeArguments, couldContainTypeVariables); // one of the input type arguments might be or contain the result + if (!(getObjectFlags(result) & ObjectFlags.CouldContainTypeVariablesComputed)) { + // if `result` is one of the object types we tried to make (it may not be, due to how `instantiateMappedType` works), we can carry forward the type variable containment check from the input type arguments + if (resultObjectFlags & (ObjectFlags.Mapped | ObjectFlags.Anonymous | ObjectFlags.Reference)) { + (result as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariables : 0); + } + // If none of the type arguments for the outer type parameters contain type variables, it follows + // that the instantiated type doesn't reference type variables. + // Intrinsics have `CouldContainTypeVariablesComputed` pre-set, so this should only cover unions and intersections resulting from `instantiateMappedType` + else { + (result as ObjectFlagsType).objectFlags |= !resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariablesComputed : 0; + } } } - target.instantiations.set(id, result); } return result; }