Skip to content

Commit 71b5bdf

Browse files
authored
Ensure resolved signature is cached before processing call errors (microsoft#49598)
1 parent 9f2ab7f commit 71b5bdf

8 files changed

+204
-15
lines changed

src/compiler/checker.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -30736,6 +30736,16 @@ namespace ts {
3073630736
return result;
3073730737
}
3073830738

30739+
result = getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray, checkMode);
30740+
// Preemptively cache the result; getResolvedSignature will do this after we return, but
30741+
// we need to ensure that the result is present for the error checks below so that if
30742+
// this signature is encountered again, we handle the circularity (rather than producing a
30743+
// different result which may produce no errors and assert). Callers of getResolvedSignature
30744+
// don't hit this issue because they only observe this result after it's had a chance to
30745+
// be cached, but the error reporting code below executes before getResolvedSignature sets
30746+
// resolvedSignature.
30747+
getNodeLinks(node).resolvedSignature = result;
30748+
3073930749
// No signatures were applicable. Now report errors based on the last applicable signature with
3074030750
// no arguments excluded from assignability checks.
3074130751
// If candidate is undefined, it means that no candidates had a suitable arity. In that case,
@@ -30826,7 +30836,7 @@ namespace ts {
3082630836
}
3082730837
}
3082830838

30829-
return getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray, checkMode);
30839+
return result;
3083030840

3083130841
function addImplementationSuccessElaboration(failed: Signature, diagnostic: Diagnostic) {
3083230842
const oldCandidatesForArgumentError = candidatesForArgumentError;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
tests/cases/compiler/circularResolvedSignature.ts(11,9): error TS2322: Type 'string' is not assignable to type 'number'.
2+
3+
4+
==== tests/cases/compiler/circularResolvedSignature.ts (1 errors) ====
5+
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];
6+
7+
type Data = Readonly<{
8+
value: number;
9+
foo: (arg: any) => void;
10+
bar: (arg: any) => void;
11+
}>;
12+
13+
export function Component() {
14+
const [state, setState] = useState<Data>(() => ({
15+
value: "string", // this should be a number
16+
~~~~~
17+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
18+
!!! related TS6500 tests/cases/compiler/circularResolvedSignature.ts:4:5: The expected type comes from property 'value' which is declared here on type 'Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>'
19+
foo: (arg) => setState(arg),
20+
bar: (arg) => setState(arg),
21+
}));
22+
}
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [circularResolvedSignature.ts]
2+
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];
3+
4+
type Data = Readonly<{
5+
value: number;
6+
foo: (arg: any) => void;
7+
bar: (arg: any) => void;
8+
}>;
9+
10+
export function Component() {
11+
const [state, setState] = useState<Data>(() => ({
12+
value: "string", // this should be a number
13+
foo: (arg) => setState(arg),
14+
bar: (arg) => setState(arg),
15+
}));
16+
}
17+
18+
19+
//// [circularResolvedSignature.js]
20+
"use strict";
21+
exports.__esModule = true;
22+
exports.Component = void 0;
23+
function Component() {
24+
var _a = useState(function () { return ({
25+
value: "string",
26+
foo: function (arg) { return setState(arg); },
27+
bar: function (arg) { return setState(arg); }
28+
}); }), state = _a[0], setState = _a[1];
29+
}
30+
exports.Component = Component;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
=== tests/cases/compiler/circularResolvedSignature.ts ===
2+
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];
3+
>useState : Symbol(useState, Decl(circularResolvedSignature.ts, 0, 0))
4+
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))
5+
>initialState : Symbol(initialState, Decl(circularResolvedSignature.ts, 0, 29))
6+
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))
7+
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))
8+
>s : Symbol(s, Decl(circularResolvedSignature.ts, 0, 60))
9+
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))
10+
11+
type Data = Readonly<{
12+
>Data : Symbol(Data, Decl(circularResolvedSignature.ts, 0, 75))
13+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
14+
15+
value: number;
16+
>value : Symbol(value, Decl(circularResolvedSignature.ts, 2, 22))
17+
18+
foo: (arg: any) => void;
19+
>foo : Symbol(foo, Decl(circularResolvedSignature.ts, 3, 18))
20+
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 4, 10))
21+
22+
bar: (arg: any) => void;
23+
>bar : Symbol(bar, Decl(circularResolvedSignature.ts, 4, 28))
24+
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 5, 10))
25+
26+
}>;
27+
28+
export function Component() {
29+
>Component : Symbol(Component, Decl(circularResolvedSignature.ts, 6, 3))
30+
31+
const [state, setState] = useState<Data>(() => ({
32+
>state : Symbol(state, Decl(circularResolvedSignature.ts, 9, 11))
33+
>setState : Symbol(setState, Decl(circularResolvedSignature.ts, 9, 17))
34+
>useState : Symbol(useState, Decl(circularResolvedSignature.ts, 0, 0))
35+
>Data : Symbol(Data, Decl(circularResolvedSignature.ts, 0, 75))
36+
37+
value: "string", // this should be a number
38+
>value : Symbol(value, Decl(circularResolvedSignature.ts, 9, 53))
39+
40+
foo: (arg) => setState(arg),
41+
>foo : Symbol(foo, Decl(circularResolvedSignature.ts, 10, 24))
42+
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 11, 14))
43+
>setState : Symbol(setState, Decl(circularResolvedSignature.ts, 9, 17))
44+
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 11, 14))
45+
46+
bar: (arg) => setState(arg),
47+
>bar : Symbol(bar, Decl(circularResolvedSignature.ts, 11, 36))
48+
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 12, 14))
49+
>setState : Symbol(setState, Decl(circularResolvedSignature.ts, 9, 17))
50+
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 12, 14))
51+
52+
}));
53+
}
54+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
=== tests/cases/compiler/circularResolvedSignature.ts ===
2+
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];
3+
>useState : <S>(initialState: (() => S)) => [S, (s: S) => void]
4+
>initialState : () => S
5+
>s : S
6+
7+
type Data = Readonly<{
8+
>Data : Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>
9+
10+
value: number;
11+
>value : number
12+
13+
foo: (arg: any) => void;
14+
>foo : (arg: any) => void
15+
>arg : any
16+
17+
bar: (arg: any) => void;
18+
>bar : (arg: any) => void
19+
>arg : any
20+
21+
}>;
22+
23+
export function Component() {
24+
>Component : () => void
25+
26+
const [state, setState] = useState<Data>(() => ({
27+
>state : Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>
28+
>setState : (s: Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>) => void
29+
>useState<Data>(() => ({ value: "string", // this should be a number foo: (arg) => setState(arg), bar: (arg) => setState(arg), })) : [Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>, (s: Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>) => void]
30+
>useState : <S>(initialState: () => S) => [S, (s: S) => void]
31+
>() => ({ value: "string", // this should be a number foo: (arg) => setState(arg), bar: (arg) => setState(arg), }) : () => { value: string; foo: (arg: any) => void; bar: (arg: any) => void; }
32+
>({ value: "string", // this should be a number foo: (arg) => setState(arg), bar: (arg) => setState(arg), }) : { value: string; foo: (arg: any) => void; bar: (arg: any) => void; }
33+
>{ value: "string", // this should be a number foo: (arg) => setState(arg), bar: (arg) => setState(arg), } : { value: string; foo: (arg: any) => void; bar: (arg: any) => void; }
34+
35+
value: "string", // this should be a number
36+
>value : string
37+
>"string" : "string"
38+
39+
foo: (arg) => setState(arg),
40+
>foo : (arg: any) => void
41+
>(arg) => setState(arg) : (arg: any) => void
42+
>arg : any
43+
>setState(arg) : void
44+
>setState : (s: Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>) => void
45+
>arg : any
46+
47+
bar: (arg) => setState(arg),
48+
>bar : (arg: any) => void
49+
>(arg) => setState(arg) : (arg: any) => void
50+
>arg : any
51+
>setState(arg) : void
52+
>setState : (s: Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>) => void
53+
>arg : any
54+
55+
}));
56+
}
57+

tests/baselines/reference/genericCallWithGenericSignatureArguments3.errors.txt

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGenericSignatureArguments3.ts(32,19): error TS2345: Argument of type '(a1: (y: string) => string) => (n: Object) => number' is not assignable to parameter of type '(x: (a: string) => boolean) => (n: Object) => number'.
1+
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGenericSignatureArguments3.ts(32,19): error TS2345: Argument of type '(a1: (y: string) => string) => (n: Object) => 1' is not assignable to parameter of type '(x: (a: string) => boolean) => (n: Object) => 1'.
22
Types of parameters 'a1' and 'x' are incompatible.
33
Type 'boolean' is not assignable to type 'string'.
4-
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGenericSignatureArguments3.ts(33,69): error TS2345: Argument of type '(a2: (z: string) => boolean) => number' is not assignable to parameter of type '(x: (z: string) => boolean) => (n: Object) => number'.
5-
Type 'number' is not assignable to type '(n: Object) => number'.
4+
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGenericSignatureArguments3.ts(33,69): error TS2345: Argument of type '(a2: (z: string) => boolean) => number' is not assignable to parameter of type '(x: (z: string) => boolean) => (n: Object) => 1'.
5+
Type 'number' is not assignable to type '(n: Object) => 1'.
66

77

88
==== tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGenericSignatureArguments3.ts (2 errors) ====
@@ -39,10 +39,10 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGen
3939
var x: (a: string) => boolean;
4040
var r11 = foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2); // error
4141
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42-
!!! error TS2345: Argument of type '(a1: (y: string) => string) => (n: Object) => number' is not assignable to parameter of type '(x: (a: string) => boolean) => (n: Object) => number'.
42+
!!! error TS2345: Argument of type '(a1: (y: string) => string) => (n: Object) => 1' is not assignable to parameter of type '(x: (a: string) => boolean) => (n: Object) => 1'.
4343
!!! error TS2345: Types of parameters 'a1' and 'x' are incompatible.
4444
!!! error TS2345: Type 'boolean' is not assignable to type 'string'.
4545
var r12 = foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2); // error
4646
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47-
!!! error TS2345: Argument of type '(a2: (z: string) => boolean) => number' is not assignable to parameter of type '(x: (z: string) => boolean) => (n: Object) => number'.
48-
!!! error TS2345: Type 'number' is not assignable to type '(n: Object) => number'.
47+
!!! error TS2345: Argument of type '(a2: (z: string) => boolean) => number' is not assignable to parameter of type '(x: (z: string) => boolean) => (n: Object) => 1'.
48+
!!! error TS2345: Type 'number' is not assignable to type '(n: Object) => 1'.

tests/baselines/reference/genericCallWithGenericSignatureArguments3.types

+8-8
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,14 @@ var x: (a: string) => boolean;
175175
>a : string
176176

177177
var r11 = foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2); // error
178-
>r11 : (x: (a: string) => boolean) => (n: Object) => number
179-
>foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2) : (x: (a: string) => boolean) => (n: Object) => number
178+
>r11 : (x: (a: string) => boolean) => (n: Object) => 1
179+
>foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2) : (x: (a: string) => boolean) => (n: Object) => 1
180180
>foo2 : <T, U>(x: T, a: (x: T) => U, b: (x: T) => U) => (x: T) => U
181181
>x : (a: string) => boolean
182-
>(a1: (y: string) => string) => (n: Object) => 1 : (a1: (y: string) => string) => (n: Object) => number
182+
>(a1: (y: string) => string) => (n: Object) => 1 : (a1: (y: string) => string) => (n: Object) => 1
183183
>a1 : (y: string) => string
184184
>y : string
185-
>(n: Object) => 1 : (n: Object) => number
185+
>(n: Object) => 1 : (n: Object) => 1
186186
>n : Object
187187
>1 : 1
188188
>(a2: (z: string) => string) => 2 : (a2: (z: string) => string) => number
@@ -191,14 +191,14 @@ var r11 = foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: stri
191191
>2 : 2
192192

193193
var r12 = foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2); // error
194-
>r12 : (x: (z: string) => boolean) => (n: Object) => number
195-
>foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2) : (x: (z: string) => boolean) => (n: Object) => number
194+
>r12 : (x: (z: string) => boolean) => (n: Object) => 1
195+
>foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2) : (x: (z: string) => boolean) => (n: Object) => 1
196196
>foo2 : <T, U>(x: T, a: (x: T) => U, b: (x: T) => U) => (x: T) => U
197197
>x : (a: string) => boolean
198-
>(a1: (y: string) => boolean) => (n: Object) => 1 : (a1: (y: string) => boolean) => (n: Object) => number
198+
>(a1: (y: string) => boolean) => (n: Object) => 1 : (a1: (y: string) => boolean) => (n: Object) => 1
199199
>a1 : (y: string) => boolean
200200
>y : string
201-
>(n: Object) => 1 : (n: Object) => number
201+
>(n: Object) => 1 : (n: Object) => 1
202202
>n : Object
203203
>1 : 1
204204
>(a2: (z: string) => boolean) => 2 : (a2: (z: string) => boolean) => number
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];
2+
3+
type Data = Readonly<{
4+
value: number;
5+
foo: (arg: any) => void;
6+
bar: (arg: any) => void;
7+
}>;
8+
9+
export function Component() {
10+
const [state, setState] = useState<Data>(() => ({
11+
value: "string", // this should be a number
12+
foo: (arg) => setState(arg),
13+
bar: (arg) => setState(arg),
14+
}));
15+
}

0 commit comments

Comments
 (0)