Skip to content

Commit 218180d

Browse files
authored
Fixed an issue with an incorrect resolved signature being cached/returned sometimes for signatures depending on the contextual type/outer inference (#52146)
1 parent 916f9b7 commit 218180d

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

src/compiler/checker.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -33984,10 +33984,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3398433984
return cached;
3398533985
}
3398633986
links.resolvedSignature = resolvingSignature;
33987-
const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal);
33987+
let result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal);
3398833988
// When CheckMode.SkipGenericFunctions is set we use resolvingSignature to indicate that call
3398933989
// resolution should be deferred.
3399033990
if (result !== resolvingSignature) {
33991+
// if the signature resolution originated on a node that itself depends on the contextual type
33992+
// then it's possible that the resolved signature might not be the same as the one that would be computed in source order
33993+
// since resolving such signature leads to resolving the potential outer signature, its arguments and thus the very same signature
33994+
// it's possible that this inner resolution sets the resolvedSignature first.
33995+
// In such a case we ignore the local result and reuse the correct one that was cached.
33996+
if (links.resolvedSignature !== resolvingSignature) {
33997+
result = links.resolvedSignature;
33998+
}
3399133999
// If signature resolution originated in control flow type analysis (for example to compute the
3399234000
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
3399334001
// types from the control flow analysis.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path='fourslash.ts' />
2+
// @strict: true
3+
//// /*1*/m({ foo: /*2*/$("foo") });
4+
//// m({ foo: /*3*/$("foo") });
5+
//// declare const m: <S extends string>(s: { [_ in S]: { $: NoInfer<S> } }) => void
6+
//// declare const $: <S, T extends S>(s: T) => { $: S }
7+
//// type NoInfer<T> = [T][T extends any ? 0 : never];
8+
9+
verify.quickInfoAt("1", `const m: <"foo">(s: {
10+
foo: {
11+
$: "foo";
12+
};
13+
}) => void`);
14+
15+
// the exact generic type params are not important in this test (they could change with changes to the inference algorithm)
16+
// it's important though that they both display the same types
17+
verify.quickInfoAt("2", `const $: <unknown, string>(s: string) => {
18+
$: unknown;
19+
}`);
20+
verify.quickInfoAt("3", `const $: <unknown, string>(s: string) => {
21+
$: unknown;
22+
}`);

0 commit comments

Comments
 (0)