@@ -1256,8 +1256,8 @@ export const enum SignatureCheckMode {
1256
1256
1257
1257
const enum IntersectionState {
1258
1258
None = 0,
1259
- Source = 1 << 0,
1260
- Target = 1 << 1,
1259
+ Source = 1 << 0, // Source type is a constituent of an outer intersection
1260
+ Target = 1 << 1, // Target type is a constituent of an outer intersection
1261
1261
}
1262
1262
1263
1263
const enum RecursionFlags {
@@ -19978,7 +19978,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19978
19978
let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid
19979
19979
let lastSkippedInfo: [Type, Type] | undefined;
19980
19980
let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] | undefined;
19981
- let inPropertyCheck = false;
19982
19981
19983
19982
Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
19984
19983
@@ -20950,18 +20949,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20950
20949
// function foo<T extends object>(x: { a?: string }, y: T & { a: boolean }) {
20951
20950
// x = y; // Mismatched property in source intersection
20952
20951
// }
20953
- //
20954
- // We suppress recursive intersection property checks because they can generate lots of work when relating
20955
- // recursive intersections that are structurally similar but not exactly identical. See #37854.
20956
- if (result && !inPropertyCheck && (
20952
+ if (result && !(intersectionState & IntersectionState.Target) && (
20957
20953
target.flags & TypeFlags.Intersection && !isGenericObjectType(target) && source.flags & (TypeFlags.Object | TypeFlags.Intersection) ||
20958
20954
isNonGenericObjectType(target) && !isArrayOrTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) {
20959
- inPropertyCheck = true;
20960
20955
result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None);
20961
20956
if (result && isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) {
20962
20957
result &= indexSignaturesRelatedTo(source, target, /*sourceIsPrimitive*/ false, reportErrors, IntersectionState.None);
20963
20958
}
20964
- inPropertyCheck = false;
20965
20959
}
20966
20960
}
20967
20961
if (result) {
@@ -21471,9 +21465,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21471
21465
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo && !sourceIsPrimitive;
21472
21466
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, intersectionState);
21473
21467
if (result) {
21474
- result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors);
21468
+ result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors, intersectionState );
21475
21469
if (result) {
21476
- result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors);
21470
+ result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors, intersectionState );
21477
21471
if (result) {
21478
21472
result &= indexSignaturesRelatedTo(source, target, sourceIsPrimitive, reportStructuralErrors, intersectionState);
21479
21473
}
@@ -21646,9 +21640,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21646
21640
for (const type of matchingTypes) {
21647
21641
result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties, IntersectionState.None);
21648
21642
if (result) {
21649
- result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false);
21643
+ result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false, IntersectionState.None );
21650
21644
if (result) {
21651
- result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false);
21645
+ result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false, IntersectionState.None );
21652
21646
if (result && !(isTupleType(source) && isTupleType(type))) {
21653
21647
// Comparing numeric index types when both `source` and `type` are tuples is unnecessary as the
21654
21648
// element types should be sufficiently covered by `propertiesRelatedTo`. It also causes problems
@@ -21984,7 +21978,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21984
21978
return result;
21985
21979
}
21986
21980
21987
- function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean): Ternary {
21981
+ function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean, intersectionState: IntersectionState ): Ternary {
21988
21982
if (relation === identityRelation) {
21989
21983
return signaturesIdenticalTo(source, target, kind);
21990
21984
}
@@ -22029,7 +22023,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22029
22023
// of the much more expensive N * M comparison matrix we explore below. We erase type parameters
22030
22024
// as they are known to always be the same.
22031
22025
for (let i = 0; i < targetSignatures.length; i++) {
22032
- const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
22026
+ const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
22033
22027
if (!related) {
22034
22028
return Ternary.False;
22035
22029
}
@@ -22045,7 +22039,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22045
22039
const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
22046
22040
const sourceSignature = first(sourceSignatures);
22047
22041
const targetSignature = first(targetSignatures);
22048
- result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, incompatibleReporter(sourceSignature, targetSignature));
22042
+ result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, intersectionState, incompatibleReporter(sourceSignature, targetSignature));
22049
22043
if (!result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags) &&
22050
22044
(targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor)) {
22051
22045
const constructSignatureToString = (signature: Signature) =>
@@ -22061,7 +22055,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22061
22055
// Only elaborate errors from the first failure
22062
22056
let shouldElaborateErrors = reportErrors;
22063
22057
for (const s of sourceSignatures) {
22064
- const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, incompatibleReporter(s, t));
22058
+ const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, intersectionState, incompatibleReporter(s, t));
22065
22059
if (related) {
22066
22060
result &= related;
22067
22061
resetErrorInfo(saveErrorInfo);
@@ -22111,9 +22105,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22111
22105
/**
22112
22106
* See signatureAssignableTo, compareSignaturesIdentical
22113
22107
*/
22114
- function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
22108
+ function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, intersectionState: IntersectionState, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
22115
22109
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
22116
22110
relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper);
22111
+ function isRelatedToWorker(source: Type, target: Type, reportErrors?: boolean) {
22112
+ return isRelatedTo(source, target, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
22113
+ }
22117
22114
}
22118
22115
22119
22116
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
@@ -22159,7 +22156,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22159
22156
}
22160
22157
for (const info of getIndexInfosOfType(source)) {
22161
22158
if (isApplicableIndexType(info.keyType, keyType)) {
22162
- const related = indexInfoRelatedTo(info, targetInfo, reportErrors);
22159
+ const related = indexInfoRelatedTo(info, targetInfo, reportErrors, intersectionState );
22163
22160
if (!related) {
22164
22161
return Ternary.False;
22165
22162
}
@@ -22169,8 +22166,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22169
22166
return result;
22170
22167
}
22171
22168
22172
- function indexInfoRelatedTo(sourceInfo: IndexInfo, targetInfo: IndexInfo, reportErrors: boolean) {
22173
- const related = isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both, reportErrors);
22169
+ function indexInfoRelatedTo(sourceInfo: IndexInfo, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState ) {
22170
+ const related = isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState );
22174
22171
if (!related && reportErrors) {
22175
22172
if (sourceInfo.keyType === targetInfo.keyType) {
22176
22173
reportError(Diagnostics._0_index_signatures_are_incompatible, typeToString(sourceInfo.keyType));
@@ -22204,7 +22201,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22204
22201
function typeRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
22205
22202
const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType);
22206
22203
if (sourceInfo) {
22207
- return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors);
22204
+ return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors, intersectionState );
22208
22205
}
22209
22206
if (!(intersectionState & IntersectionState.Source) && isObjectTypeWithInferableIndex(source)) {
22210
22207
// Intersection constituents are never considered to have an inferred index signature
0 commit comments