Skip to content

Commit f47e7b2

Browse files
committed
Consistently propagate intersectionState in relations
1 parent 700452d commit f47e7b2

File tree

1 file changed

+19
-22
lines changed

1 file changed

+19
-22
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,8 +1256,8 @@ export const enum SignatureCheckMode {
12561256

12571257
const enum IntersectionState {
12581258
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
12611261
}
12621262

12631263
const enum RecursionFlags {
@@ -19978,7 +19978,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1997819978
let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid
1997919979
let lastSkippedInfo: [Type, Type] | undefined;
1998019980
let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] | undefined;
19981-
let inPropertyCheck = false;
1998219981

1998319982
Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
1998419983

@@ -20950,18 +20949,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2095020949
// function foo<T extends object>(x: { a?: string }, y: T & { a: boolean }) {
2095120950
// x = y; // Mismatched property in source intersection
2095220951
// }
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) && (
2095720953
target.flags & TypeFlags.Intersection && !isGenericObjectType(target) && source.flags & (TypeFlags.Object | TypeFlags.Intersection) ||
2095820954
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;
2096020955
result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None);
2096120956
if (result && isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) {
2096220957
result &= indexSignaturesRelatedTo(source, target, /*sourceIsPrimitive*/ false, reportErrors, IntersectionState.None);
2096320958
}
20964-
inPropertyCheck = false;
2096520959
}
2096620960
}
2096720961
if (result) {
@@ -21471,9 +21465,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2147121465
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo && !sourceIsPrimitive;
2147221466
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, intersectionState);
2147321467
if (result) {
21474-
result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors);
21468+
result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors, intersectionState);
2147521469
if (result) {
21476-
result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors);
21470+
result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors, intersectionState);
2147721471
if (result) {
2147821472
result &= indexSignaturesRelatedTo(source, target, sourceIsPrimitive, reportStructuralErrors, intersectionState);
2147921473
}
@@ -21646,9 +21640,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2164621640
for (const type of matchingTypes) {
2164721641
result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties, IntersectionState.None);
2164821642
if (result) {
21649-
result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false);
21643+
result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false, IntersectionState.None);
2165021644
if (result) {
21651-
result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false);
21645+
result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false, IntersectionState.None);
2165221646
if (result && !(isTupleType(source) && isTupleType(type))) {
2165321647
// Comparing numeric index types when both `source` and `type` are tuples is unnecessary as the
2165421648
// element types should be sufficiently covered by `propertiesRelatedTo`. It also causes problems
@@ -21984,7 +21978,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2198421978
return result;
2198521979
}
2198621980

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 {
2198821982
if (relation === identityRelation) {
2198921983
return signaturesIdenticalTo(source, target, kind);
2199021984
}
@@ -22029,7 +22023,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2202922023
// of the much more expensive N * M comparison matrix we explore below. We erase type parameters
2203022024
// as they are known to always be the same.
2203122025
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]));
2203322027
if (!related) {
2203422028
return Ternary.False;
2203522029
}
@@ -22045,7 +22039,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2204522039
const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
2204622040
const sourceSignature = first(sourceSignatures);
2204722041
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));
2204922043
if (!result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags) &&
2205022044
(targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor)) {
2205122045
const constructSignatureToString = (signature: Signature) =>
@@ -22061,7 +22055,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2206122055
// Only elaborate errors from the first failure
2206222056
let shouldElaborateErrors = reportErrors;
2206322057
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));
2206522059
if (related) {
2206622060
result &= related;
2206722061
resetErrorInfo(saveErrorInfo);
@@ -22111,9 +22105,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2211122105
/**
2211222106
* See signatureAssignableTo, compareSignaturesIdentical
2211322107
*/
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 {
2211522109
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
2211622110
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+
}
2211722114
}
2211822115

2211922116
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
@@ -22159,7 +22156,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2215922156
}
2216022157
for (const info of getIndexInfosOfType(source)) {
2216122158
if (isApplicableIndexType(info.keyType, keyType)) {
22162-
const related = indexInfoRelatedTo(info, targetInfo, reportErrors);
22159+
const related = indexInfoRelatedTo(info, targetInfo, reportErrors, intersectionState);
2216322160
if (!related) {
2216422161
return Ternary.False;
2216522162
}
@@ -22169,8 +22166,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2216922166
return result;
2217022167
}
2217122168

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);
2217422171
if (!related && reportErrors) {
2217522172
if (sourceInfo.keyType === targetInfo.keyType) {
2217622173
reportError(Diagnostics._0_index_signatures_are_incompatible, typeToString(sourceInfo.keyType));
@@ -22204,7 +22201,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2220422201
function typeRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
2220522202
const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType);
2220622203
if (sourceInfo) {
22207-
return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors);
22204+
return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors, intersectionState);
2220822205
}
2220922206
if (!(intersectionState & IntersectionState.Source) && isObjectTypeWithInferableIndex(source)) {
2221022207
// Intersection constituents are never considered to have an inferred index signature

0 commit comments

Comments
 (0)