Skip to content

Commit 8da01f3

Browse files
authored
Check callback parameters bivariantly if they result from instantiation (#56218)
1 parent 5bc6617 commit 8da01f3

File tree

7 files changed

+414
-5
lines changed

7 files changed

+414
-5
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20691,8 +20691,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2069120691
// similar to return values, callback parameters are output positions. This means that a Promise<T>,
2069220692
// where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant)
2069320693
// with respect to T.
20694-
const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
20695-
const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType));
20694+
const sourceSig = checkMode & SignatureCheckMode.Callback || isInstantiatedGenericParameter(source, i) ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
20695+
const targetSig = checkMode & SignatureCheckMode.Callback || isInstantiatedGenericParameter(target, i) ? undefined : getSingleCallSignature(getNonNullableType(targetType));
2069620696
const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
2069720697
getTypeFacts(sourceType, TypeFacts.IsUndefinedOrNull) === getTypeFacts(targetType, TypeFacts.IsUndefinedOrNull);
2069820698
let related = callbacks ?
@@ -33486,6 +33486,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3348633486
(typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters);
3348733487
}
3348833488

33489+
function isInstantiatedGenericParameter(signature: Signature, pos: number) {
33490+
let type;
33491+
return !!(signature.target && (type = tryGetTypeAtPosition(signature.target, pos)) && isGenericType(type));
33492+
}
33493+
3348933494
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
3349033495
function getSingleCallSignature(type: Type): Signature | undefined {
3349133496
return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false);

tests/baselines/reference/covariantCallbacks.errors.txt

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,18 @@ covariantCallbacks.ts(69,5): error TS2322: Type 'AList4' is not assignable to ty
2323
Types of parameters 'cb' and 'cb' are incompatible.
2424
Types of parameters 'item' and 'item' are incompatible.
2525
Type 'A' is not assignable to type 'B'.
26+
covariantCallbacks.ts(98,1): error TS2322: Type 'SetLike1<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
27+
Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
28+
Types of parameters 'x' and 'x' are incompatible.
29+
Type 'unknown' is not assignable to type 'string'.
30+
covariantCallbacks.ts(106,1): error TS2322: Type 'SetLike2<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
31+
The types returned by 'get()' are incompatible between these types.
32+
Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
33+
Types of parameters 'x' and 'x' are incompatible.
34+
Type 'unknown' is not assignable to type 'string'.
2635

2736

28-
==== covariantCallbacks.ts (6 errors) ====
37+
==== covariantCallbacks.ts (8 errors) ====
2938
// Test that callback parameters are related covariantly
3039

3140
interface P<T> {
@@ -128,4 +137,52 @@ covariantCallbacks.ts(69,5): error TS2322: Type 'AList4' is not assignable to ty
128137
!!! error TS2322: Types of parameters 'item' and 'item' are incompatible.
129138
!!! error TS2322: Type 'A' is not assignable to type 'B'.
130139
}
140+
141+
// Repro from #51620
142+
143+
type Bivar<T> = { set(value: T): void }
144+
145+
declare let bu: Bivar<unknown>;
146+
declare let bs: Bivar<string>;
147+
bu = bs;
148+
bs = bu;
149+
150+
declare let bfu: Bivar<(x: unknown) => void>;
151+
declare let bfs: Bivar<(x: string) => void>;
152+
bfu = bfs;
153+
bfs = bfu;
154+
155+
type Bivar1<T> = { set(value: T): void }
156+
type Bivar2<T> = { set(value: T): void }
157+
158+
declare let b1fu: Bivar1<(x: unknown) => void>;
159+
declare let b2fs: Bivar2<(x: string) => void>;
160+
b1fu = b2fs;
161+
b2fs = b1fu;
162+
163+
type SetLike<T> = { set(value: T): void, get(): T }
164+
165+
declare let sx: SetLike1<(x: unknown) => void>;
166+
declare let sy: SetLike1<(x: string) => void>;
167+
sx = sy; // Error
168+
~~
169+
!!! error TS2322: Type 'SetLike1<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
170+
!!! error TS2322: Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
171+
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
172+
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
173+
sy = sx;
174+
175+
type SetLike1<T> = { set(value: T): void, get(): T }
176+
type SetLike2<T> = { set(value: T): void, get(): T }
177+
178+
declare let s1: SetLike1<(x: unknown) => void>;
179+
declare let s2: SetLike2<(x: string) => void>;
180+
s1 = s2; // Error
181+
~~
182+
!!! error TS2322: Type 'SetLike2<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
183+
!!! error TS2322: The types returned by 'get()' are incompatible between these types.
184+
!!! error TS2322: Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
185+
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
186+
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
187+
s2 = s1;
131188

tests/baselines/reference/covariantCallbacks.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,43 @@ function f14(a: AList4, b: BList4) {
7171
a = b;
7272
b = a; // Error
7373
}
74+
75+
// Repro from #51620
76+
77+
type Bivar<T> = { set(value: T): void }
78+
79+
declare let bu: Bivar<unknown>;
80+
declare let bs: Bivar<string>;
81+
bu = bs;
82+
bs = bu;
83+
84+
declare let bfu: Bivar<(x: unknown) => void>;
85+
declare let bfs: Bivar<(x: string) => void>;
86+
bfu = bfs;
87+
bfs = bfu;
88+
89+
type Bivar1<T> = { set(value: T): void }
90+
type Bivar2<T> = { set(value: T): void }
91+
92+
declare let b1fu: Bivar1<(x: unknown) => void>;
93+
declare let b2fs: Bivar2<(x: string) => void>;
94+
b1fu = b2fs;
95+
b2fs = b1fu;
96+
97+
type SetLike<T> = { set(value: T): void, get(): T }
98+
99+
declare let sx: SetLike1<(x: unknown) => void>;
100+
declare let sy: SetLike1<(x: string) => void>;
101+
sx = sy; // Error
102+
sy = sx;
103+
104+
type SetLike1<T> = { set(value: T): void, get(): T }
105+
type SetLike2<T> = { set(value: T): void, get(): T }
106+
107+
declare let s1: SetLike1<(x: unknown) => void>;
108+
declare let s2: SetLike2<(x: string) => void>;
109+
s1 = s2; // Error
110+
s2 = s1;
74111

75112

76113
//// [covariantCallbacks.js]
@@ -101,3 +138,13 @@ function f14(a, b) {
101138
a = b;
102139
b = a; // Error
103140
}
141+
bu = bs;
142+
bs = bu;
143+
bfu = bfs;
144+
bfs = bfu;
145+
b1fu = b2fs;
146+
b2fs = b1fu;
147+
sx = sy; // Error
148+
sy = sx;
149+
s1 = s2; // Error
150+
s2 = s1;

tests/baselines/reference/covariantCallbacks.symbols

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,141 @@ function f14(a: AList4, b: BList4) {
207207
>a : Symbol(a, Decl(covariantCallbacks.ts, 66, 13))
208208
}
209209

210+
// Repro from #51620
211+
212+
type Bivar<T> = { set(value: T): void }
213+
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
214+
>T : Symbol(T, Decl(covariantCallbacks.ts, 73, 11))
215+
>set : Symbol(set, Decl(covariantCallbacks.ts, 73, 17))
216+
>value : Symbol(value, Decl(covariantCallbacks.ts, 73, 22))
217+
>T : Symbol(T, Decl(covariantCallbacks.ts, 73, 11))
218+
219+
declare let bu: Bivar<unknown>;
220+
>bu : Symbol(bu, Decl(covariantCallbacks.ts, 75, 11))
221+
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
222+
223+
declare let bs: Bivar<string>;
224+
>bs : Symbol(bs, Decl(covariantCallbacks.ts, 76, 11))
225+
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
226+
227+
bu = bs;
228+
>bu : Symbol(bu, Decl(covariantCallbacks.ts, 75, 11))
229+
>bs : Symbol(bs, Decl(covariantCallbacks.ts, 76, 11))
230+
231+
bs = bu;
232+
>bs : Symbol(bs, Decl(covariantCallbacks.ts, 76, 11))
233+
>bu : Symbol(bu, Decl(covariantCallbacks.ts, 75, 11))
234+
235+
declare let bfu: Bivar<(x: unknown) => void>;
236+
>bfu : Symbol(bfu, Decl(covariantCallbacks.ts, 80, 11))
237+
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
238+
>x : Symbol(x, Decl(covariantCallbacks.ts, 80, 24))
239+
240+
declare let bfs: Bivar<(x: string) => void>;
241+
>bfs : Symbol(bfs, Decl(covariantCallbacks.ts, 81, 11))
242+
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
243+
>x : Symbol(x, Decl(covariantCallbacks.ts, 81, 24))
244+
245+
bfu = bfs;
246+
>bfu : Symbol(bfu, Decl(covariantCallbacks.ts, 80, 11))
247+
>bfs : Symbol(bfs, Decl(covariantCallbacks.ts, 81, 11))
248+
249+
bfs = bfu;
250+
>bfs : Symbol(bfs, Decl(covariantCallbacks.ts, 81, 11))
251+
>bfu : Symbol(bfu, Decl(covariantCallbacks.ts, 80, 11))
252+
253+
type Bivar1<T> = { set(value: T): void }
254+
>Bivar1 : Symbol(Bivar1, Decl(covariantCallbacks.ts, 83, 10))
255+
>T : Symbol(T, Decl(covariantCallbacks.ts, 85, 12))
256+
>set : Symbol(set, Decl(covariantCallbacks.ts, 85, 18))
257+
>value : Symbol(value, Decl(covariantCallbacks.ts, 85, 23))
258+
>T : Symbol(T, Decl(covariantCallbacks.ts, 85, 12))
259+
260+
type Bivar2<T> = { set(value: T): void }
261+
>Bivar2 : Symbol(Bivar2, Decl(covariantCallbacks.ts, 85, 40))
262+
>T : Symbol(T, Decl(covariantCallbacks.ts, 86, 12))
263+
>set : Symbol(set, Decl(covariantCallbacks.ts, 86, 18))
264+
>value : Symbol(value, Decl(covariantCallbacks.ts, 86, 23))
265+
>T : Symbol(T, Decl(covariantCallbacks.ts, 86, 12))
266+
267+
declare let b1fu: Bivar1<(x: unknown) => void>;
268+
>b1fu : Symbol(b1fu, Decl(covariantCallbacks.ts, 88, 11))
269+
>Bivar1 : Symbol(Bivar1, Decl(covariantCallbacks.ts, 83, 10))
270+
>x : Symbol(x, Decl(covariantCallbacks.ts, 88, 26))
271+
272+
declare let b2fs: Bivar2<(x: string) => void>;
273+
>b2fs : Symbol(b2fs, Decl(covariantCallbacks.ts, 89, 11))
274+
>Bivar2 : Symbol(Bivar2, Decl(covariantCallbacks.ts, 85, 40))
275+
>x : Symbol(x, Decl(covariantCallbacks.ts, 89, 26))
276+
277+
b1fu = b2fs;
278+
>b1fu : Symbol(b1fu, Decl(covariantCallbacks.ts, 88, 11))
279+
>b2fs : Symbol(b2fs, Decl(covariantCallbacks.ts, 89, 11))
280+
281+
b2fs = b1fu;
282+
>b2fs : Symbol(b2fs, Decl(covariantCallbacks.ts, 89, 11))
283+
>b1fu : Symbol(b1fu, Decl(covariantCallbacks.ts, 88, 11))
284+
285+
type SetLike<T> = { set(value: T): void, get(): T }
286+
>SetLike : Symbol(SetLike, Decl(covariantCallbacks.ts, 91, 12))
287+
>T : Symbol(T, Decl(covariantCallbacks.ts, 93, 13))
288+
>set : Symbol(set, Decl(covariantCallbacks.ts, 93, 19))
289+
>value : Symbol(value, Decl(covariantCallbacks.ts, 93, 24))
290+
>T : Symbol(T, Decl(covariantCallbacks.ts, 93, 13))
291+
>get : Symbol(get, Decl(covariantCallbacks.ts, 93, 40))
292+
>T : Symbol(T, Decl(covariantCallbacks.ts, 93, 13))
293+
294+
declare let sx: SetLike1<(x: unknown) => void>;
295+
>sx : Symbol(sx, Decl(covariantCallbacks.ts, 95, 11))
296+
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
297+
>x : Symbol(x, Decl(covariantCallbacks.ts, 95, 26))
298+
299+
declare let sy: SetLike1<(x: string) => void>;
300+
>sy : Symbol(sy, Decl(covariantCallbacks.ts, 96, 11))
301+
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
302+
>x : Symbol(x, Decl(covariantCallbacks.ts, 96, 26))
303+
304+
sx = sy; // Error
305+
>sx : Symbol(sx, Decl(covariantCallbacks.ts, 95, 11))
306+
>sy : Symbol(sy, Decl(covariantCallbacks.ts, 96, 11))
307+
308+
sy = sx;
309+
>sy : Symbol(sy, Decl(covariantCallbacks.ts, 96, 11))
310+
>sx : Symbol(sx, Decl(covariantCallbacks.ts, 95, 11))
311+
312+
type SetLike1<T> = { set(value: T): void, get(): T }
313+
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
314+
>T : Symbol(T, Decl(covariantCallbacks.ts, 100, 14))
315+
>set : Symbol(set, Decl(covariantCallbacks.ts, 100, 20))
316+
>value : Symbol(value, Decl(covariantCallbacks.ts, 100, 25))
317+
>T : Symbol(T, Decl(covariantCallbacks.ts, 100, 14))
318+
>get : Symbol(get, Decl(covariantCallbacks.ts, 100, 41))
319+
>T : Symbol(T, Decl(covariantCallbacks.ts, 100, 14))
320+
321+
type SetLike2<T> = { set(value: T): void, get(): T }
322+
>SetLike2 : Symbol(SetLike2, Decl(covariantCallbacks.ts, 100, 52))
323+
>T : Symbol(T, Decl(covariantCallbacks.ts, 101, 14))
324+
>set : Symbol(set, Decl(covariantCallbacks.ts, 101, 20))
325+
>value : Symbol(value, Decl(covariantCallbacks.ts, 101, 25))
326+
>T : Symbol(T, Decl(covariantCallbacks.ts, 101, 14))
327+
>get : Symbol(get, Decl(covariantCallbacks.ts, 101, 41))
328+
>T : Symbol(T, Decl(covariantCallbacks.ts, 101, 14))
329+
330+
declare let s1: SetLike1<(x: unknown) => void>;
331+
>s1 : Symbol(s1, Decl(covariantCallbacks.ts, 103, 11))
332+
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
333+
>x : Symbol(x, Decl(covariantCallbacks.ts, 103, 26))
334+
335+
declare let s2: SetLike2<(x: string) => void>;
336+
>s2 : Symbol(s2, Decl(covariantCallbacks.ts, 104, 11))
337+
>SetLike2 : Symbol(SetLike2, Decl(covariantCallbacks.ts, 100, 52))
338+
>x : Symbol(x, Decl(covariantCallbacks.ts, 104, 26))
339+
340+
s1 = s2; // Error
341+
>s1 : Symbol(s1, Decl(covariantCallbacks.ts, 103, 11))
342+
>s2 : Symbol(s2, Decl(covariantCallbacks.ts, 104, 11))
343+
344+
s2 = s1;
345+
>s2 : Symbol(s2, Decl(covariantCallbacks.ts, 104, 11))
346+
>s1 : Symbol(s1, Decl(covariantCallbacks.ts, 103, 11))
347+

0 commit comments

Comments
 (0)