Optimize eagerly calculating CouldContainTypeVariables during object type instantiation (#54538)

This commit is contained in:
Wesley Wigham
2023-06-06 14:14:49 -07:00
committed by GitHub
parent 3c4c060dff
commit 3cfd6d2b87

View File

@@ -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;
}