Check callback parameters bivariantly if they result from instantiation (#56218)

This commit is contained in:
Anders Hejlsberg 2023-12-01 10:38:04 -08:00 committed by GitHub
parent 5bc6617738
commit 8da01f3583
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 414 additions and 5 deletions

View File

@ -20691,8 +20691,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// similar to return values, callback parameters are output positions. This means that a Promise<T>,
// where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant)
// with respect to T.
const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType));
const sourceSig = checkMode & SignatureCheckMode.Callback || isInstantiatedGenericParameter(source, i) ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
const targetSig = checkMode & SignatureCheckMode.Callback || isInstantiatedGenericParameter(target, i) ? undefined : getSingleCallSignature(getNonNullableType(targetType));
const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
getTypeFacts(sourceType, TypeFacts.IsUndefinedOrNull) === getTypeFacts(targetType, TypeFacts.IsUndefinedOrNull);
let related = callbacks ?
@ -33486,6 +33486,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
(typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters);
}
function isInstantiatedGenericParameter(signature: Signature, pos: number) {
let type;
return !!(signature.target && (type = tryGetTypeAtPosition(signature.target, pos)) && isGenericType(type));
}
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
function getSingleCallSignature(type: Type): Signature | undefined {
return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false);

View File

@ -23,9 +23,18 @@ covariantCallbacks.ts(69,5): error TS2322: Type 'AList4' is not assignable to ty
Types of parameters 'cb' and 'cb' are incompatible.
Types of parameters 'item' and 'item' are incompatible.
Type 'A' is not assignable to type 'B'.
covariantCallbacks.ts(98,1): error TS2322: Type 'SetLike1<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
Types of parameters 'x' and 'x' are incompatible.
Type 'unknown' is not assignable to type 'string'.
covariantCallbacks.ts(106,1): error TS2322: Type 'SetLike2<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
The types returned by 'get()' are incompatible between these types.
Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
Types of parameters 'x' and 'x' are incompatible.
Type 'unknown' is not assignable to type 'string'.
==== covariantCallbacks.ts (6 errors) ====
==== covariantCallbacks.ts (8 errors) ====
// Test that callback parameters are related covariantly
interface P<T> {
@ -128,4 +137,52 @@ covariantCallbacks.ts(69,5): error TS2322: Type 'AList4' is not assignable to ty
!!! error TS2322: Types of parameters 'item' and 'item' are incompatible.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
}
// Repro from #51620
type Bivar<T> = { set(value: T): void }
declare let bu: Bivar<unknown>;
declare let bs: Bivar<string>;
bu = bs;
bs = bu;
declare let bfu: Bivar<(x: unknown) => void>;
declare let bfs: Bivar<(x: string) => void>;
bfu = bfs;
bfs = bfu;
type Bivar1<T> = { set(value: T): void }
type Bivar2<T> = { set(value: T): void }
declare let b1fu: Bivar1<(x: unknown) => void>;
declare let b2fs: Bivar2<(x: string) => void>;
b1fu = b2fs;
b2fs = b1fu;
type SetLike<T> = { set(value: T): void, get(): T }
declare let sx: SetLike1<(x: unknown) => void>;
declare let sy: SetLike1<(x: string) => void>;
sx = sy; // Error
~~
!!! error TS2322: Type 'SetLike1<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
!!! error TS2322: Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
sy = sx;
type SetLike1<T> = { set(value: T): void, get(): T }
type SetLike2<T> = { set(value: T): void, get(): T }
declare let s1: SetLike1<(x: unknown) => void>;
declare let s2: SetLike2<(x: string) => void>;
s1 = s2; // Error
~~
!!! error TS2322: Type 'SetLike2<(x: string) => void>' is not assignable to type 'SetLike1<(x: unknown) => void>'.
!!! error TS2322: The types returned by 'get()' are incompatible between these types.
!!! error TS2322: Type '(x: string) => void' is not assignable to type '(x: unknown) => void'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
s2 = s1;

View File

@ -71,6 +71,43 @@ function f14(a: AList4, b: BList4) {
a = b;
b = a; // Error
}
// Repro from #51620
type Bivar<T> = { set(value: T): void }
declare let bu: Bivar<unknown>;
declare let bs: Bivar<string>;
bu = bs;
bs = bu;
declare let bfu: Bivar<(x: unknown) => void>;
declare let bfs: Bivar<(x: string) => void>;
bfu = bfs;
bfs = bfu;
type Bivar1<T> = { set(value: T): void }
type Bivar2<T> = { set(value: T): void }
declare let b1fu: Bivar1<(x: unknown) => void>;
declare let b2fs: Bivar2<(x: string) => void>;
b1fu = b2fs;
b2fs = b1fu;
type SetLike<T> = { set(value: T): void, get(): T }
declare let sx: SetLike1<(x: unknown) => void>;
declare let sy: SetLike1<(x: string) => void>;
sx = sy; // Error
sy = sx;
type SetLike1<T> = { set(value: T): void, get(): T }
type SetLike2<T> = { set(value: T): void, get(): T }
declare let s1: SetLike1<(x: unknown) => void>;
declare let s2: SetLike2<(x: string) => void>;
s1 = s2; // Error
s2 = s1;
//// [covariantCallbacks.js]
@ -101,3 +138,13 @@ function f14(a, b) {
a = b;
b = a; // Error
}
bu = bs;
bs = bu;
bfu = bfs;
bfs = bfu;
b1fu = b2fs;
b2fs = b1fu;
sx = sy; // Error
sy = sx;
s1 = s2; // Error
s2 = s1;

View File

@ -207,3 +207,141 @@ function f14(a: AList4, b: BList4) {
>a : Symbol(a, Decl(covariantCallbacks.ts, 66, 13))
}
// Repro from #51620
type Bivar<T> = { set(value: T): void }
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
>T : Symbol(T, Decl(covariantCallbacks.ts, 73, 11))
>set : Symbol(set, Decl(covariantCallbacks.ts, 73, 17))
>value : Symbol(value, Decl(covariantCallbacks.ts, 73, 22))
>T : Symbol(T, Decl(covariantCallbacks.ts, 73, 11))
declare let bu: Bivar<unknown>;
>bu : Symbol(bu, Decl(covariantCallbacks.ts, 75, 11))
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
declare let bs: Bivar<string>;
>bs : Symbol(bs, Decl(covariantCallbacks.ts, 76, 11))
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
bu = bs;
>bu : Symbol(bu, Decl(covariantCallbacks.ts, 75, 11))
>bs : Symbol(bs, Decl(covariantCallbacks.ts, 76, 11))
bs = bu;
>bs : Symbol(bs, Decl(covariantCallbacks.ts, 76, 11))
>bu : Symbol(bu, Decl(covariantCallbacks.ts, 75, 11))
declare let bfu: Bivar<(x: unknown) => void>;
>bfu : Symbol(bfu, Decl(covariantCallbacks.ts, 80, 11))
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
>x : Symbol(x, Decl(covariantCallbacks.ts, 80, 24))
declare let bfs: Bivar<(x: string) => void>;
>bfs : Symbol(bfs, Decl(covariantCallbacks.ts, 81, 11))
>Bivar : Symbol(Bivar, Decl(covariantCallbacks.ts, 69, 1))
>x : Symbol(x, Decl(covariantCallbacks.ts, 81, 24))
bfu = bfs;
>bfu : Symbol(bfu, Decl(covariantCallbacks.ts, 80, 11))
>bfs : Symbol(bfs, Decl(covariantCallbacks.ts, 81, 11))
bfs = bfu;
>bfs : Symbol(bfs, Decl(covariantCallbacks.ts, 81, 11))
>bfu : Symbol(bfu, Decl(covariantCallbacks.ts, 80, 11))
type Bivar1<T> = { set(value: T): void }
>Bivar1 : Symbol(Bivar1, Decl(covariantCallbacks.ts, 83, 10))
>T : Symbol(T, Decl(covariantCallbacks.ts, 85, 12))
>set : Symbol(set, Decl(covariantCallbacks.ts, 85, 18))
>value : Symbol(value, Decl(covariantCallbacks.ts, 85, 23))
>T : Symbol(T, Decl(covariantCallbacks.ts, 85, 12))
type Bivar2<T> = { set(value: T): void }
>Bivar2 : Symbol(Bivar2, Decl(covariantCallbacks.ts, 85, 40))
>T : Symbol(T, Decl(covariantCallbacks.ts, 86, 12))
>set : Symbol(set, Decl(covariantCallbacks.ts, 86, 18))
>value : Symbol(value, Decl(covariantCallbacks.ts, 86, 23))
>T : Symbol(T, Decl(covariantCallbacks.ts, 86, 12))
declare let b1fu: Bivar1<(x: unknown) => void>;
>b1fu : Symbol(b1fu, Decl(covariantCallbacks.ts, 88, 11))
>Bivar1 : Symbol(Bivar1, Decl(covariantCallbacks.ts, 83, 10))
>x : Symbol(x, Decl(covariantCallbacks.ts, 88, 26))
declare let b2fs: Bivar2<(x: string) => void>;
>b2fs : Symbol(b2fs, Decl(covariantCallbacks.ts, 89, 11))
>Bivar2 : Symbol(Bivar2, Decl(covariantCallbacks.ts, 85, 40))
>x : Symbol(x, Decl(covariantCallbacks.ts, 89, 26))
b1fu = b2fs;
>b1fu : Symbol(b1fu, Decl(covariantCallbacks.ts, 88, 11))
>b2fs : Symbol(b2fs, Decl(covariantCallbacks.ts, 89, 11))
b2fs = b1fu;
>b2fs : Symbol(b2fs, Decl(covariantCallbacks.ts, 89, 11))
>b1fu : Symbol(b1fu, Decl(covariantCallbacks.ts, 88, 11))
type SetLike<T> = { set(value: T): void, get(): T }
>SetLike : Symbol(SetLike, Decl(covariantCallbacks.ts, 91, 12))
>T : Symbol(T, Decl(covariantCallbacks.ts, 93, 13))
>set : Symbol(set, Decl(covariantCallbacks.ts, 93, 19))
>value : Symbol(value, Decl(covariantCallbacks.ts, 93, 24))
>T : Symbol(T, Decl(covariantCallbacks.ts, 93, 13))
>get : Symbol(get, Decl(covariantCallbacks.ts, 93, 40))
>T : Symbol(T, Decl(covariantCallbacks.ts, 93, 13))
declare let sx: SetLike1<(x: unknown) => void>;
>sx : Symbol(sx, Decl(covariantCallbacks.ts, 95, 11))
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
>x : Symbol(x, Decl(covariantCallbacks.ts, 95, 26))
declare let sy: SetLike1<(x: string) => void>;
>sy : Symbol(sy, Decl(covariantCallbacks.ts, 96, 11))
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
>x : Symbol(x, Decl(covariantCallbacks.ts, 96, 26))
sx = sy; // Error
>sx : Symbol(sx, Decl(covariantCallbacks.ts, 95, 11))
>sy : Symbol(sy, Decl(covariantCallbacks.ts, 96, 11))
sy = sx;
>sy : Symbol(sy, Decl(covariantCallbacks.ts, 96, 11))
>sx : Symbol(sx, Decl(covariantCallbacks.ts, 95, 11))
type SetLike1<T> = { set(value: T): void, get(): T }
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
>T : Symbol(T, Decl(covariantCallbacks.ts, 100, 14))
>set : Symbol(set, Decl(covariantCallbacks.ts, 100, 20))
>value : Symbol(value, Decl(covariantCallbacks.ts, 100, 25))
>T : Symbol(T, Decl(covariantCallbacks.ts, 100, 14))
>get : Symbol(get, Decl(covariantCallbacks.ts, 100, 41))
>T : Symbol(T, Decl(covariantCallbacks.ts, 100, 14))
type SetLike2<T> = { set(value: T): void, get(): T }
>SetLike2 : Symbol(SetLike2, Decl(covariantCallbacks.ts, 100, 52))
>T : Symbol(T, Decl(covariantCallbacks.ts, 101, 14))
>set : Symbol(set, Decl(covariantCallbacks.ts, 101, 20))
>value : Symbol(value, Decl(covariantCallbacks.ts, 101, 25))
>T : Symbol(T, Decl(covariantCallbacks.ts, 101, 14))
>get : Symbol(get, Decl(covariantCallbacks.ts, 101, 41))
>T : Symbol(T, Decl(covariantCallbacks.ts, 101, 14))
declare let s1: SetLike1<(x: unknown) => void>;
>s1 : Symbol(s1, Decl(covariantCallbacks.ts, 103, 11))
>SetLike1 : Symbol(SetLike1, Decl(covariantCallbacks.ts, 98, 8))
>x : Symbol(x, Decl(covariantCallbacks.ts, 103, 26))
declare let s2: SetLike2<(x: string) => void>;
>s2 : Symbol(s2, Decl(covariantCallbacks.ts, 104, 11))
>SetLike2 : Symbol(SetLike2, Decl(covariantCallbacks.ts, 100, 52))
>x : Symbol(x, Decl(covariantCallbacks.ts, 104, 26))
s1 = s2; // Error
>s1 : Symbol(s1, Decl(covariantCallbacks.ts, 103, 11))
>s2 : Symbol(s2, Decl(covariantCallbacks.ts, 104, 11))
s2 = s1;
>s2 : Symbol(s2, Decl(covariantCallbacks.ts, 104, 11))
>s1 : Symbol(s1, Decl(covariantCallbacks.ts, 103, 11))

View File

@ -170,3 +170,126 @@ function f14(a: AList4, b: BList4) {
>a : AList4
}
// Repro from #51620
type Bivar<T> = { set(value: T): void }
>Bivar : Bivar<T>
>set : (value: T) => void
>value : T
declare let bu: Bivar<unknown>;
>bu : Bivar<unknown>
declare let bs: Bivar<string>;
>bs : Bivar<string>
bu = bs;
>bu = bs : Bivar<string>
>bu : Bivar<unknown>
>bs : Bivar<string>
bs = bu;
>bs = bu : Bivar<unknown>
>bs : Bivar<string>
>bu : Bivar<unknown>
declare let bfu: Bivar<(x: unknown) => void>;
>bfu : Bivar<(x: unknown) => void>
>x : unknown
declare let bfs: Bivar<(x: string) => void>;
>bfs : Bivar<(x: string) => void>
>x : string
bfu = bfs;
>bfu = bfs : Bivar<(x: string) => void>
>bfu : Bivar<(x: unknown) => void>
>bfs : Bivar<(x: string) => void>
bfs = bfu;
>bfs = bfu : Bivar<(x: unknown) => void>
>bfs : Bivar<(x: string) => void>
>bfu : Bivar<(x: unknown) => void>
type Bivar1<T> = { set(value: T): void }
>Bivar1 : Bivar1<T>
>set : (value: T) => void
>value : T
type Bivar2<T> = { set(value: T): void }
>Bivar2 : Bivar2<T>
>set : (value: T) => void
>value : T
declare let b1fu: Bivar1<(x: unknown) => void>;
>b1fu : Bivar1<(x: unknown) => void>
>x : unknown
declare let b2fs: Bivar2<(x: string) => void>;
>b2fs : Bivar2<(x: string) => void>
>x : string
b1fu = b2fs;
>b1fu = b2fs : Bivar2<(x: string) => void>
>b1fu : Bivar1<(x: unknown) => void>
>b2fs : Bivar2<(x: string) => void>
b2fs = b1fu;
>b2fs = b1fu : Bivar1<(x: unknown) => void>
>b2fs : Bivar2<(x: string) => void>
>b1fu : Bivar1<(x: unknown) => void>
type SetLike<T> = { set(value: T): void, get(): T }
>SetLike : SetLike<T>
>set : (value: T) => void
>value : T
>get : () => T
declare let sx: SetLike1<(x: unknown) => void>;
>sx : SetLike1<(x: unknown) => void>
>x : unknown
declare let sy: SetLike1<(x: string) => void>;
>sy : SetLike1<(x: string) => void>
>x : string
sx = sy; // Error
>sx = sy : SetLike1<(x: string) => void>
>sx : SetLike1<(x: unknown) => void>
>sy : SetLike1<(x: string) => void>
sy = sx;
>sy = sx : SetLike1<(x: unknown) => void>
>sy : SetLike1<(x: string) => void>
>sx : SetLike1<(x: unknown) => void>
type SetLike1<T> = { set(value: T): void, get(): T }
>SetLike1 : SetLike1<T>
>set : (value: T) => void
>value : T
>get : () => T
type SetLike2<T> = { set(value: T): void, get(): T }
>SetLike2 : SetLike2<T>
>set : (value: T) => void
>value : T
>get : () => T
declare let s1: SetLike1<(x: unknown) => void>;
>s1 : SetLike1<(x: unknown) => void>
>x : unknown
declare let s2: SetLike2<(x: string) => void>;
>s2 : SetLike2<(x: string) => void>
>x : string
s1 = s2; // Error
>s1 = s2 : SetLike2<(x: string) => void>
>s1 : SetLike1<(x: unknown) => void>
>s2 : SetLike2<(x: string) => void>
s2 = s1;
>s2 = s1 : SetLike1<(x: unknown) => void>
>s2 : SetLike2<(x: string) => void>
>s1 : SetLike1<(x: unknown) => void>

View File

@ -1,6 +1,7 @@
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'.
Type '(a: string) => boolean' is not assignable to type '(y: string) => string'.
Type 'boolean' is not assignable to type 'string'.
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'.
@ -41,7 +42,8 @@ genericCallWithGenericSignatureArguments3.ts(33,69): error TS2345: Argument of t
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! 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'.
!!! error TS2345: Type '(a: string) => boolean' is not assignable to type '(y: string) => string'.
!!! 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) => 1'.

View File

@ -71,3 +71,40 @@ function f14(a: AList4, b: BList4) {
a = b;
b = a; // Error
}
// Repro from #51620
type Bivar<T> = { set(value: T): void }
declare let bu: Bivar<unknown>;
declare let bs: Bivar<string>;
bu = bs;
bs = bu;
declare let bfu: Bivar<(x: unknown) => void>;
declare let bfs: Bivar<(x: string) => void>;
bfu = bfs;
bfs = bfu;
type Bivar1<T> = { set(value: T): void }
type Bivar2<T> = { set(value: T): void }
declare let b1fu: Bivar1<(x: unknown) => void>;
declare let b2fs: Bivar2<(x: string) => void>;
b1fu = b2fs;
b2fs = b1fu;
type SetLike<T> = { set(value: T): void, get(): T }
declare let sx: SetLike1<(x: unknown) => void>;
declare let sy: SetLike1<(x: string) => void>;
sx = sy; // Error
sy = sx;
type SetLike1<T> = { set(value: T): void, get(): T }
type SetLike2<T> = { set(value: T): void, get(): T }
declare let s1: SetLike1<(x: unknown) => void>;
declare let s2: SetLike2<(x: string) => void>;
s1 = s2; // Error
s2 = s1;