mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-22 16:52:14 -06:00
Avoid resolving objects in getTypeFacts when caller doesn't need that info (#55459)
This commit is contained in:
parent
98d7e0b936
commit
91c0d7ff9b
@ -10651,7 +10651,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
parentType = getNonNullableType(parentType);
|
||||
}
|
||||
// Filter `undefined` from the type we check against if the parent has an initializer and that initializer is not possibly `undefined`
|
||||
else if (strictNullChecks && pattern.parent.initializer && !(getTypeFacts(getTypeOfInitializer(pattern.parent.initializer)) & TypeFacts.EQUndefined)) {
|
||||
else if (strictNullChecks && pattern.parent.initializer && !(hasTypeFacts(getTypeOfInitializer(pattern.parent.initializer), TypeFacts.EQUndefined))) {
|
||||
parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined);
|
||||
}
|
||||
|
||||
@ -10710,7 +10710,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) {
|
||||
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
|
||||
// undefined from the final type.
|
||||
return strictNullChecks && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type;
|
||||
return strictNullChecks && !(hasTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal), TypeFacts.IsUndefined)) ? getNonUndefinedType(type) : type;
|
||||
}
|
||||
return widenTypeInferredFromInitializer(declaration, getUnionType([getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], UnionReduction.Subtype));
|
||||
}
|
||||
@ -20332,7 +20332,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
|
||||
const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType));
|
||||
const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
|
||||
(getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull);
|
||||
getTypeFacts(sourceType, TypeFacts.IsUndefinedOrNull) === getTypeFacts(targetType, TypeFacts.IsUndefinedOrNull);
|
||||
let related = callbacks ?
|
||||
compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
|
||||
!(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
|
||||
@ -23894,7 +23894,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function removeDefinitelyFalsyTypes(type: Type): Type {
|
||||
return filterType(type, t => !!(getTypeFacts(t) & TypeFacts.Truthy));
|
||||
return filterType(type, t => hasTypeFacts(t, TypeFacts.Truthy));
|
||||
}
|
||||
|
||||
function extractDefinitelyFalsyTypes(type: Type): Type {
|
||||
@ -26141,7 +26141,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType));
|
||||
}
|
||||
|
||||
function getTypeFacts(type: Type): TypeFacts {
|
||||
function getTypeFacts(type: Type, mask: TypeFacts): TypeFacts {
|
||||
return getTypeFactsWorker(type, mask) & mask;
|
||||
}
|
||||
|
||||
function hasTypeFacts(type: Type, mask: TypeFacts): boolean {
|
||||
return getTypeFacts(type, mask) !== 0;
|
||||
}
|
||||
|
||||
function getTypeFactsWorker(type: Type, callerOnlyNeeds: TypeFacts): TypeFacts {
|
||||
if (type.flags & (TypeFlags.Intersection | TypeFlags.Instantiable)) {
|
||||
type = getBaseConstraintOfType(type) || unknownType;
|
||||
}
|
||||
@ -26182,6 +26190,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
(type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts;
|
||||
}
|
||||
if (flags & TypeFlags.Object) {
|
||||
const possibleFacts = strictNullChecks
|
||||
? TypeFacts.EmptyObjectStrictFacts | TypeFacts.FunctionStrictFacts | TypeFacts.ObjectStrictFacts
|
||||
: TypeFacts.EmptyObjectFacts | TypeFacts.FunctionFacts | TypeFacts.ObjectFacts;
|
||||
|
||||
if ((callerOnlyNeeds & possibleFacts) === 0) {
|
||||
// If the caller doesn't care about any of the facts that we could possibly produce,
|
||||
// return zero so we can skip resolving members.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ?
|
||||
strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts :
|
||||
isFunctionObjectType(type as ObjectType) ?
|
||||
@ -26207,15 +26225,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return TypeFacts.None;
|
||||
}
|
||||
if (flags & TypeFlags.Union) {
|
||||
return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None);
|
||||
return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFactsWorker(t, callerOnlyNeeds), TypeFacts.None);
|
||||
}
|
||||
if (flags & TypeFlags.Intersection) {
|
||||
return getIntersectionTypeFacts(type as IntersectionType);
|
||||
return getIntersectionTypeFacts(type as IntersectionType, callerOnlyNeeds);
|
||||
}
|
||||
return TypeFacts.UnknownFacts;
|
||||
}
|
||||
|
||||
function getIntersectionTypeFacts(type: IntersectionType): TypeFacts {
|
||||
function getIntersectionTypeFacts(type: IntersectionType, callerOnlyNeeds: TypeFacts): TypeFacts {
|
||||
// When an intersection contains a primitive type we ignore object type constituents as they are
|
||||
// presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type.
|
||||
const ignoreObjects = maybeTypeOfKind(type, TypeFlags.Primitive);
|
||||
@ -26225,7 +26243,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
let andedFacts = TypeFacts.All;
|
||||
for (const t of type.types) {
|
||||
if (!(ignoreObjects && t.flags & TypeFlags.Object)) {
|
||||
const f = getTypeFacts(t);
|
||||
const f = getTypeFactsWorker(t, callerOnlyNeeds);
|
||||
oredFacts |= f;
|
||||
andedFacts &= f;
|
||||
}
|
||||
@ -26234,7 +26252,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function getTypeWithFacts(type: Type, include: TypeFacts) {
|
||||
return filterType(type, t => (getTypeFacts(t) & include) !== 0);
|
||||
return filterType(type, t => hasTypeFacts(t, include));
|
||||
}
|
||||
|
||||
// This function is similar to getTypeWithFacts, except that in strictNullChecks mode it replaces type
|
||||
@ -26245,12 +26263,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (strictNullChecks) {
|
||||
switch (facts) {
|
||||
case TypeFacts.NEUndefined:
|
||||
return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefined ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQNull && !maybeTypeOfKind(reduced, TypeFlags.Null) ? getUnionType([emptyObjectType, nullType]) : emptyObjectType]) : t);
|
||||
return mapType(reduced, t => hasTypeFacts(t, TypeFacts.EQUndefined) ? getIntersectionType([t, hasTypeFacts(t, TypeFacts.EQNull) && !maybeTypeOfKind(reduced, TypeFlags.Null) ? getUnionType([emptyObjectType, nullType]) : emptyObjectType]) : t);
|
||||
case TypeFacts.NENull:
|
||||
return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQNull ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQUndefined && !maybeTypeOfKind(reduced, TypeFlags.Undefined) ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType]) : t);
|
||||
return mapType(reduced, t => hasTypeFacts(t, TypeFacts.EQNull) ? getIntersectionType([t, hasTypeFacts(t, TypeFacts.EQUndefined) && !maybeTypeOfKind(reduced, TypeFlags.Undefined) ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType]) : t);
|
||||
case TypeFacts.NEUndefinedOrNull:
|
||||
case TypeFacts.Truthy:
|
||||
return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefinedOrNull ? getGlobalNonNullableTypeInstantiation(t) : t);
|
||||
return mapType(reduced, t => hasTypeFacts(t, TypeFacts.EQUndefinedOrNull) ? getGlobalNonNullableTypeInstantiation(t) : t);
|
||||
}
|
||||
}
|
||||
return reduced;
|
||||
@ -27818,14 +27836,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// the constituent based on its type facts. We use the strict subtype relation because it treats `object`
|
||||
// as a subtype of `{}`, and we need the type facts check because function types are subtypes of `object`,
|
||||
// but are classified as "function" according to `typeof`.
|
||||
isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? getTypeFacts(t) & facts ? t : neverType :
|
||||
isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? hasTypeFacts(t, facts) ? t : neverType :
|
||||
// We next check if the consituent is a supertype of the implied type. If so, we substitute the implied
|
||||
// type. This handles top types like `unknown` and `{}`, and supertypes like `{ toString(): string }`.
|
||||
isTypeSubtypeOf(impliedType, t) ? impliedType :
|
||||
// Neither the constituent nor the implied type is a subtype of the other, however their domains may still
|
||||
// overlap. For example, an unconstrained type parameter and type `string`. If the type facts indicate
|
||||
// possible overlap, we form an intersection. Otherwise, we eliminate the constituent.
|
||||
getTypeFacts(t) & facts ? getIntersectionType([t, impliedType]) :
|
||||
hasTypeFacts(t, facts) ? getIntersectionType([t, impliedType]) :
|
||||
neverType);
|
||||
}
|
||||
|
||||
@ -27840,7 +27858,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (hasDefaultClause) {
|
||||
// In the default clause we filter constituents down to those that are not-equal to all handled cases.
|
||||
const notEqualFacts = getNotEqualFactsFromTypeofSwitch(clauseStart, clauseEnd, witnesses);
|
||||
return filterType(type, t => (getTypeFacts(t) & notEqualFacts) === notEqualFacts);
|
||||
return filterType(type, t => getTypeFacts(t, notEqualFacts) === notEqualFacts);
|
||||
}
|
||||
// In the non-default cause we create a union of the type narrowed by each of the listed cases.
|
||||
const clauseWitnesses = witnesses.slice(clauseStart, clauseEnd);
|
||||
@ -28023,7 +28041,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
if (
|
||||
strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) &&
|
||||
!(getTypeFacts(predicate.type) & TypeFacts.EQUndefined)
|
||||
!(hasTypeFacts(predicate.type, TypeFacts.EQUndefined))
|
||||
) {
|
||||
type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull);
|
||||
}
|
||||
@ -28184,7 +28202,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return true;
|
||||
}
|
||||
|
||||
const containsUndefined = !!(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined);
|
||||
const containsUndefined = !!(hasTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal), TypeFacts.IsUndefined));
|
||||
|
||||
if (!popTypeResolution()) {
|
||||
reportCircularityError(declaration.symbol);
|
||||
@ -28202,7 +28220,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const removeUndefined = strictNullChecks &&
|
||||
declaration.kind === SyntaxKind.Parameter &&
|
||||
declaration.initializer &&
|
||||
getTypeFacts(declaredType) & TypeFacts.IsUndefined &&
|
||||
hasTypeFacts(declaredType, TypeFacts.IsUndefined) &&
|
||||
!parameterInitializerContainsUndefined(declaration);
|
||||
|
||||
return removeUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
|
||||
@ -31781,7 +31799,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function isNullableType(type: Type) {
|
||||
return !!(getTypeFacts(type) & TypeFacts.IsUndefinedOrNull);
|
||||
return hasTypeFacts(type, TypeFacts.IsUndefinedOrNull);
|
||||
}
|
||||
|
||||
function getNonNullableTypeIfNeeded(type: Type) {
|
||||
@ -31845,7 +31863,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
error(node, Diagnostics.Object_is_of_type_unknown);
|
||||
return errorType;
|
||||
}
|
||||
const facts = getTypeFacts(type);
|
||||
const facts = getTypeFacts(type, TypeFacts.IsUndefinedOrNull);
|
||||
if (facts & TypeFacts.IsUndefinedOrNull) {
|
||||
reportError(node, facts);
|
||||
const t = getNonNullableType(type);
|
||||
@ -36307,7 +36325,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return (TypeFacts.AllTypeofNE & notEqualFacts) === TypeFacts.AllTypeofNE;
|
||||
}
|
||||
// A missing not-equal flag indicates that the type wasn't handled by some case.
|
||||
return !someType(operandConstraint, t => (getTypeFacts(t) & notEqualFacts) === notEqualFacts);
|
||||
return !someType(operandConstraint, t => getTypeFacts(t, notEqualFacts) === notEqualFacts);
|
||||
}
|
||||
const type = checkExpressionCached(node.expression);
|
||||
if (!isLiteralType(type)) {
|
||||
@ -36725,7 +36743,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (
|
||||
strictNullChecks &&
|
||||
!(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) &&
|
||||
!(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getTypeFacts(type) & TypeFacts.IsUndefined)
|
||||
!(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : hasTypeFacts(type, TypeFacts.IsUndefined))
|
||||
) {
|
||||
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional);
|
||||
}
|
||||
@ -36871,7 +36889,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return getUnaryResultType(operandType);
|
||||
case SyntaxKind.ExclamationToken:
|
||||
checkTruthinessOfType(operandType, node.operand);
|
||||
const facts = getTypeFacts(operandType) & (TypeFacts.Truthy | TypeFacts.Falsy);
|
||||
const facts = getTypeFacts(operandType, TypeFacts.Truthy | TypeFacts.Falsy);
|
||||
return facts === TypeFacts.Truthy ? falseType :
|
||||
facts === TypeFacts.Falsy ? trueType :
|
||||
booleanType;
|
||||
@ -37162,7 +37180,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// undefined from the final type.
|
||||
if (
|
||||
strictNullChecks &&
|
||||
!(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined)
|
||||
!(hasTypeFacts(checkExpression(prop.objectAssignmentInitializer), TypeFacts.IsUndefined))
|
||||
) {
|
||||
sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined);
|
||||
}
|
||||
@ -37638,7 +37656,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return checkInExpression(left, right, leftType, rightType);
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken: {
|
||||
const resultType = getTypeFacts(leftType) & TypeFacts.Truthy ?
|
||||
const resultType = hasTypeFacts(leftType, TypeFacts.Truthy) ?
|
||||
getUnionType([extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), rightType]) :
|
||||
leftType;
|
||||
if (operator === SyntaxKind.AmpersandAmpersandEqualsToken) {
|
||||
@ -37648,7 +37666,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
case SyntaxKind.BarBarToken:
|
||||
case SyntaxKind.BarBarEqualsToken: {
|
||||
const resultType = getTypeFacts(leftType) & TypeFacts.Falsy ?
|
||||
const resultType = hasTypeFacts(leftType, TypeFacts.Falsy) ?
|
||||
getUnionType([getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], UnionReduction.Subtype) :
|
||||
leftType;
|
||||
if (operator === SyntaxKind.BarBarEqualsToken) {
|
||||
@ -37658,7 +37676,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
case SyntaxKind.QuestionQuestionToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken: {
|
||||
const resultType = getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ?
|
||||
const resultType = hasTypeFacts(leftType, TypeFacts.EQUndefinedOrNull) ?
|
||||
getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) :
|
||||
leftType;
|
||||
if (operator === SyntaxKind.QuestionQuestionEqualsToken) {
|
||||
@ -41917,7 +41935,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
const type = location === condExpr ? condType : checkTruthinessExpression(location);
|
||||
const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression);
|
||||
if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return;
|
||||
if (!hasTypeFacts(type, TypeFacts.Truthy) || isPropertyExpressionCast) return;
|
||||
|
||||
// While it technically should be invalid for any known-truthy value
|
||||
// to be tested, we de-scope to functions and Promises unreferenced in
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user