diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 8f1bf66fa63da..0ee591294a8db 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -33324,10 +33324,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return cached;
}
links.resolvedSignature = resolvingSignature;
- const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal);
+ let result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal);
// When CheckMode.SkipGenericFunctions is set we use resolvingSignature to indicate that call
// resolution should be deferred.
if (result !== resolvingSignature) {
+ // if the signature resolution originated on a node that itself depends on the contextual type
+ // then it's possible that the resolved signature might not be the same as the one that would be computed in source order
+ // since resolving such signature leads to resolving the potential outer signature, its arguments and thus the very same signature
+ // it's possible that this inner resolution sets the resolvedSignature first.
+ // In such a case we ignore the local result and reuse the correct one that was cached.
+ if (links.resolvedSignature !== resolvingSignature) {
+ result = links.resolvedSignature;
+ }
// If signature resolution originated in control flow type analysis (for example to compute the
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
// types from the control flow analysis.
diff --git a/tests/cases/fourslash/quickInfoNestedGenericCalls.ts b/tests/cases/fourslash/quickInfoNestedGenericCalls.ts
new file mode 100644
index 0000000000000..c950728f48b08
--- /dev/null
+++ b/tests/cases/fourslash/quickInfoNestedGenericCalls.ts
@@ -0,0 +1,22 @@
+///
+// @strict: true
+//// /*1*/m({ foo: /*2*/$("foo") });
+//// m({ foo: /*3*/$("foo") });
+//// declare const m: (s: { [_ in S]: { $: NoInfer } }) => void
+//// declare const $: (s: T) => { $: S }
+//// type NoInfer = [T][T extends any ? 0 : never];
+
+verify.quickInfoAt("1", `const m: <"foo">(s: {
+ foo: {
+ $: "foo";
+ };
+}) => void`);
+
+// the exact generic type params are not important in this test (they could change with changes to the inference algorithm)
+// it's important though that they both display the same types
+verify.quickInfoAt("2", `const $: (s: string) => {
+ $: unknown;
+}`);
+verify.quickInfoAt("3", `const $: (s: string) => {
+ $: unknown;
+}`);