Skip to content

Ensure resolved signature is cached before processing call errors #49598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30732,6 +30732,16 @@ namespace ts {
return result;
}

result = getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray, checkMode);
// Preemptively cache the result; getResolvedSignature will do this after we return, but
// we need to ensure that the result is present for the error checks below so that if
// this signature is encountered again, we handle the circularity (rather than producing a
// different result which may produce no errors and assert). Callers of getResolvedSignature
// don't hit this issue because they only observe this result after it's had a chance to
// be cached, but the error reporting code below executes before getResolvedSignature sets
// resolvedSignature.
getNodeLinks(node).resolvedSignature = result;

// No signatures were applicable. Now report errors based on the last applicable signature with
// no arguments excluded from assignability checks.
// If candidate is undefined, it means that no candidates had a suitable arity. In that case,
Expand Down Expand Up @@ -30822,7 +30832,7 @@ namespace ts {
}
}

return getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray, checkMode);
return result;

function addImplementationSuccessElaboration(failed: Signature, diagnostic: Diagnostic) {
const oldCandidatesForArgumentError = candidatesForArgumentError;
Expand Down
23 changes: 23 additions & 0 deletions tests/baselines/reference/circularResolvedSignature.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
tests/cases/compiler/circularResolvedSignature.ts(11,9): error TS2322: Type 'string' is not assignable to type 'number'.


==== tests/cases/compiler/circularResolvedSignature.ts (1 errors) ====
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];

type Data = Readonly<{
value: number;
foo: (arg: any) => void;
bar: (arg: any) => void;
}>;

export function Component() {
const [state, setState] = useState<Data>(() => ({
value: "string", // this should be a number
~~~~~
!!! error TS2322: Type 'string' is not assignable to type 'number'.
!!! 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; }>'
foo: (arg) => setState(arg),
bar: (arg) => setState(arg),
}));
}

30 changes: 30 additions & 0 deletions tests/baselines/reference/circularResolvedSignature.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//// [circularResolvedSignature.ts]
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];

type Data = Readonly<{
value: number;
foo: (arg: any) => void;
bar: (arg: any) => void;
}>;

export function Component() {
const [state, setState] = useState<Data>(() => ({
value: "string", // this should be a number
foo: (arg) => setState(arg),
bar: (arg) => setState(arg),
}));
}


//// [circularResolvedSignature.js]
"use strict";
exports.__esModule = true;
exports.Component = void 0;
function Component() {
var _a = useState(function () { return ({
value: "string",
foo: function (arg) { return setState(arg); },
bar: function (arg) { return setState(arg); }
}); }), state = _a[0], setState = _a[1];
}
exports.Component = Component;
54 changes: 54 additions & 0 deletions tests/baselines/reference/circularResolvedSignature.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
=== tests/cases/compiler/circularResolvedSignature.ts ===
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];
>useState : Symbol(useState, Decl(circularResolvedSignature.ts, 0, 0))
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))
>initialState : Symbol(initialState, Decl(circularResolvedSignature.ts, 0, 29))
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))
>s : Symbol(s, Decl(circularResolvedSignature.ts, 0, 60))
>S : Symbol(S, Decl(circularResolvedSignature.ts, 0, 26))

type Data = Readonly<{
>Data : Symbol(Data, Decl(circularResolvedSignature.ts, 0, 75))
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))

value: number;
>value : Symbol(value, Decl(circularResolvedSignature.ts, 2, 22))

foo: (arg: any) => void;
>foo : Symbol(foo, Decl(circularResolvedSignature.ts, 3, 18))
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 4, 10))

bar: (arg: any) => void;
>bar : Symbol(bar, Decl(circularResolvedSignature.ts, 4, 28))
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 5, 10))

}>;

export function Component() {
>Component : Symbol(Component, Decl(circularResolvedSignature.ts, 6, 3))

const [state, setState] = useState<Data>(() => ({
>state : Symbol(state, Decl(circularResolvedSignature.ts, 9, 11))
>setState : Symbol(setState, Decl(circularResolvedSignature.ts, 9, 17))
>useState : Symbol(useState, Decl(circularResolvedSignature.ts, 0, 0))
>Data : Symbol(Data, Decl(circularResolvedSignature.ts, 0, 75))

value: "string", // this should be a number
>value : Symbol(value, Decl(circularResolvedSignature.ts, 9, 53))

foo: (arg) => setState(arg),
>foo : Symbol(foo, Decl(circularResolvedSignature.ts, 10, 24))
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 11, 14))
>setState : Symbol(setState, Decl(circularResolvedSignature.ts, 9, 17))
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 11, 14))

bar: (arg) => setState(arg),
>bar : Symbol(bar, Decl(circularResolvedSignature.ts, 11, 36))
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 12, 14))
>setState : Symbol(setState, Decl(circularResolvedSignature.ts, 9, 17))
>arg : Symbol(arg, Decl(circularResolvedSignature.ts, 12, 14))

}));
}

57 changes: 57 additions & 0 deletions tests/baselines/reference/circularResolvedSignature.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
=== tests/cases/compiler/circularResolvedSignature.ts ===
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];
>useState : <S>(initialState: (() => S)) => [S, (s: S) => void]
>initialState : () => S
>s : S

type Data = Readonly<{
>Data : Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>

value: number;
>value : number

foo: (arg: any) => void;
>foo : (arg: any) => void
>arg : any

bar: (arg: any) => void;
>bar : (arg: any) => void
>arg : any

}>;

export function Component() {
>Component : () => void

const [state, setState] = useState<Data>(() => ({
>state : Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>
>setState : (s: Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>) => void
>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]
>useState : <S>(initialState: () => S) => [S, (s: S) => void]
>() => ({ 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; }
>({ 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; }
>{ 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; }

value: "string", // this should be a number
>value : string
>"string" : "string"

foo: (arg) => setState(arg),
>foo : (arg: any) => void
>(arg) => setState(arg) : (arg: any) => void
>arg : any
>setState(arg) : void
>setState : (s: Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>) => void
>arg : any

bar: (arg) => setState(arg),
>bar : (arg: any) => void
>(arg) => setState(arg) : (arg: any) => void
>arg : any
>setState(arg) : void
>setState : (s: Readonly<{ value: number; foo: (arg: any) => void; bar: (arg: any) => void; }>) => void
>arg : any

}));
}

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
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'.
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'.
Types of parameters 'a1' and 'x' are incompatible.
Type 'boolean' is not assignable to type 'string'.
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'.
Type 'number' is not assignable to type '(n: Object) => number'.
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'.
Type 'number' is not assignable to type '(n: Object) => 1'.


==== tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGenericSignatureArguments3.ts (2 errors) ====
Expand Down Expand Up @@ -39,10 +39,10 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithGen
var x: (a: string) => boolean;
var r11 = foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! 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'.
!!! 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'.
!!! error TS2345: Types of parameters 'a1' and 'x' are incompatible.
!!! error TS2345: Type 'boolean' is not assignable to type 'string'.
var r12 = foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(a2: (z: string) => boolean) => number' is not assignable to parameter of type '(x: (z: string) => boolean) => (n: Object) => number'.
!!! error TS2345: Type 'number' is not assignable to type '(n: Object) => number'.
!!! error TS2345: Argument of type '(a2: (z: string) => boolean) => number' is not assignable to parameter of type '(x: (z: string) => boolean) => (n: Object) => 1'.
!!! error TS2345: Type 'number' is not assignable to type '(n: Object) => 1'.
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,14 @@ var x: (a: string) => boolean;
>a : string

var r11 = foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2); // error
>r11 : (x: (a: string) => boolean) => (n: Object) => number
>foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2) : (x: (a: string) => boolean) => (n: Object) => number
>r11 : (x: (a: string) => boolean) => (n: Object) => 1
>foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: string) => string) => 2) : (x: (a: string) => boolean) => (n: Object) => 1
>foo2 : <T, U>(x: T, a: (x: T) => U, b: (x: T) => U) => (x: T) => U
>x : (a: string) => boolean
>(a1: (y: string) => string) => (n: Object) => 1 : (a1: (y: string) => string) => (n: Object) => number
>(a1: (y: string) => string) => (n: Object) => 1 : (a1: (y: string) => string) => (n: Object) => 1
>a1 : (y: string) => string
>y : string
>(n: Object) => 1 : (n: Object) => number
>(n: Object) => 1 : (n: Object) => 1
>n : Object
>1 : 1
>(a2: (z: string) => string) => 2 : (a2: (z: string) => string) => number
Expand All @@ -191,14 +191,14 @@ var r11 = foo2(x, (a1: (y: string) => string) => (n: Object) => 1, (a2: (z: stri
>2 : 2

var r12 = foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2); // error
>r12 : (x: (z: string) => boolean) => (n: Object) => number
>foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2) : (x: (z: string) => boolean) => (n: Object) => number
>r12 : (x: (z: string) => boolean) => (n: Object) => 1
>foo2(x, (a1: (y: string) => boolean) => (n: Object) => 1, (a2: (z: string) => boolean) => 2) : (x: (z: string) => boolean) => (n: Object) => 1
>foo2 : <T, U>(x: T, a: (x: T) => U, b: (x: T) => U) => (x: T) => U
>x : (a: string) => boolean
>(a1: (y: string) => boolean) => (n: Object) => 1 : (a1: (y: string) => boolean) => (n: Object) => number
>(a1: (y: string) => boolean) => (n: Object) => 1 : (a1: (y: string) => boolean) => (n: Object) => 1
>a1 : (y: string) => boolean
>y : string
>(n: Object) => 1 : (n: Object) => number
>(n: Object) => 1 : (n: Object) => 1
>n : Object
>1 : 1
>(a2: (z: string) => boolean) => 2 : (a2: (z: string) => boolean) => number
Expand Down
15 changes: 15 additions & 0 deletions tests/cases/compiler/circularResolvedSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
declare function useState<S>(initialState: (() => S)): [S, (s: S) => void];

type Data = Readonly<{
value: number;
foo: (arg: any) => void;
bar: (arg: any) => void;
}>;

export function Component() {
const [state, setState] = useState<Data>(() => ({
value: "string", // this should be a number
foo: (arg) => setState(arg),
bar: (arg) => setState(arg),
}));
}