@@ -18342,47 +18342,43 @@ namespace ts {
1834218342
1834318343                traceUnionsOrIntersectionsTooLarge(source, target);
1834418344
18345-                 let result = Ternary.False;
18346-                 const saveErrorInfo = captureErrorCalculationState();
18347- 
1834818345                if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) {
1834918346                    const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 && !(target.flags & TypeFlags.Union) ||
1835018347                        target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 && !(source.flags & TypeFlags.StructuredOrInstantiable);
18351-                     if (skipCaching) {
18352-                         result = unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState);
18348+                     let result = skipCaching ?
18349+                         unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) :
18350+                         recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags);
18351+                     // For certain combinations involving intersections and optional, excess, or mismatched properties we need
18352+                     // an extra property check where the intersection is viewed as a single object. The following are motivating
18353+                     // examples that all should be errors, but aren't without this extra property check:
18354+                     //
18355+                     //   let obj: { a: { x: string } } & { c: number } = { a: { x: 'hello', y: 2 }, c: 5 };  // Nested excess property
18356+                     //
18357+                     //   declare let wrong: { a: { y: string } };
18358+                     //   let weak: { a?: { x?: number } } & { c?: string } = wrong;  // Nested weak object type
18359+                     //
18360+                     //   function foo<T extends object>(x: { a?: string }, y: T & { a: boolean }) {
18361+                     //     x = y;  // Mismatched property in source intersection
18362+                     //   }
18363+                     //
18364+                     // We suppress recursive intersection property checks because they can generate lots of work when relating
18365+                     // recursive intersections that are structurally similar but not exactly identical. See #37854.
18366+                     if (result && !inPropertyCheck && (
18367+                         target.flags & TypeFlags.Intersection && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks) ||
18368+                         isNonGenericObjectType(target) && !isArrayType(target) && !isTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) {
18369+                         inPropertyCheck = true;
18370+                         result &= recursiveTypeRelatedTo(source, target, reportErrors, IntersectionState.PropertyCheck, recursionFlags);
18371+                         inPropertyCheck = false;
1835318372                    }
18354-                     else  if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags) ) {
18355-                         resetErrorInfo(saveErrorInfo) ;
18373+                     if (result) {
18374+                         return result ;
1835618375                    }
1835718376                }
1835818377
18359-                 // For certain combinations involving intersections and optional, excess, or mismatched properties we need
18360-                 // an extra property check where the intersection is viewed as a single object. The following are motivating
18361-                 // examples that all should be errors, but aren't without this extra property check:
18362-                 //
18363-                 //   let obj: { a: { x: string } } & { c: number } = { a: { x: 'hello', y: 2 }, c: 5 };  // Nested excess property
18364-                 //
18365-                 //   declare let wrong: { a: { y: string } };
18366-                 //   let weak: { a?: { x?: number } } & { c?: string } = wrong;  // Nested weak object type
18367-                 //
18368-                 //   function foo<T extends object>(x: { a?: string }, y: T & { a: boolean }) {
18369-                 //     x = y;  // Mismatched property in source intersection
18370-                 //   }
18371-                 //
18372-                 // We suppress recursive intersection property checks because they can generate lots of work when relating
18373-                 // recursive intersections that are structurally similar but not exactly identical. See #37854.
18374-                 if (result && !inPropertyCheck && (
18375-                     target.flags & TypeFlags.Intersection && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks) ||
18376-                     isNonGenericObjectType(target) && !isArrayType(target) && !isTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) {
18377-                     inPropertyCheck = true;
18378-                     result &= recursiveTypeRelatedTo(source, target, reportErrors, IntersectionState.PropertyCheck, recursionFlags);
18379-                     inPropertyCheck = false;
18380-                 }
18381- 
18382-                 if (!result && reportErrors) {
18378+                 if (reportErrors) {
1838318379                    reportErrorResults(originalSource, originalTarget, source, target, headMessage);
1838418380                }
18385-                 return result ;
18381+                 return Ternary.False ;
1838618382            }
1838718383
1838818384            function reportErrorResults(originalSource: Type, originalTarget: Type, source: Type, target: Type, headMessage: DiagnosticMessage | undefined) {
@@ -19946,7 +19942,6 @@ namespace ts {
1994619942                }
1994719943
1994819944                let result = Ternary.True;
19949-                 const saveErrorInfo = captureErrorCalculationState();
1995019945                const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn;
1995119946                const sourceObjectFlags = getObjectFlags(source);
1995219947                const targetObjectFlags = getObjectFlags(target);
@@ -19985,6 +19980,7 @@ namespace ts {
1998519980                }
1998619981                else {
1998719982                    outer: for (const t of targetSignatures) {
19983+                         const saveErrorInfo = captureErrorCalculationState();
1998819984                        // Only elaborate errors from the first failure
1998919985                        let shouldElaborateErrors = reportErrors;
1999019986                        for (const s of sourceSignatures) {
@@ -19996,7 +19992,6 @@ namespace ts {
1999619992                            }
1999719993                            shouldElaborateErrors = false;
1999819994                        }
19999- 
2000019995                        if (shouldElaborateErrors) {
2000119996                            reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
2000219997                                typeToString(source),
0 commit comments