diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d4565607249fd..71e7fc64a4d15 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33856,11 +33856,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature; applyToParameterTypes(sourceSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type - inferTypes(context.inferences, source, target); + inferTypes(context.inferences, source, target, /*priority*/ undefined, /*contravariant*/ strictFunctionTypes); }); if (!inferenceContext) { applyToReturnTypes(contextualSignature, signature, (source, target) => { - inferTypes(context.inferences, source, target, InferencePriority.ReturnType); + inferTypes(context.inferences, source, target); }); } return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration)); diff --git a/tests/baselines/reference/assignmentCompatWithCallSignatures3.errors.txt b/tests/baselines/reference/assignmentCompatWithCallSignatures3.errors.txt index def250f002fe2..a316eb6e311c9 100644 --- a/tests/baselines/reference/assignmentCompatWithCallSignatures3.errors.txt +++ b/tests/baselines/reference/assignmentCompatWithCallSignatures3.errors.txt @@ -50,11 +50,6 @@ assignmentCompatWithCallSignatures3.ts(80,1): error TS2322: Type '(x: Base[], y: assignmentCompatWithCallSignatures3.ts(83,1): error TS2322: Type '(x: Base[], y: Derived[]) => Derived[]' is not assignable to type '(x: Base[], y: T) => T'. Type 'Derived[]' is not assignable to type 'T'. 'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'. -assignmentCompatWithCallSignatures3.ts(85,1): error TS2322: Type '(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => Object'. - Types of parameters 'x' and 'x' are incompatible. - Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'. - Types of property 'b' are incompatible. - Type 'number' is not assignable to type 'string'. assignmentCompatWithCallSignatures3.ts(86,1): error TS2322: Type '(x: { a: string; b: number; }) => Object' is not assignable to type '(x: { a: T; b: T; }) => T'. Types of parameters 'x' and 'x' are incompatible. Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'. @@ -62,7 +57,7 @@ assignmentCompatWithCallSignatures3.ts(86,1): error TS2322: Type '(x: { a: strin Type 'T' is not assignable to type 'string'. -==== assignmentCompatWithCallSignatures3.ts (15 errors) ==== +==== assignmentCompatWithCallSignatures3.ts (14 errors) ==== // these are all permitted with the current rules, since we do not do contextual signature instantiation class Base { foo: string; } @@ -218,12 +213,6 @@ assignmentCompatWithCallSignatures3.ts(86,1): error TS2322: Type '(x: { a: strin !!! error TS2322: 'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'. var b14: (x: { a: T; b: T }) => T; a14 = b14; // ok - ~~~ -!!! error TS2322: Type '(x: { a: T; b: T; }) => T' is not assignable to type '(x: { a: string; b: number; }) => Object'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'. -!!! error TS2322: Types of property 'b' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. b14 = a14; // ok ~~~ !!! error TS2322: Type '(x: { a: string; b: number; }) => Object' is not assignable to type '(x: { a: T; b: T; }) => T'. diff --git a/tests/baselines/reference/assignmentCompatWithConstructSignatures3.errors.txt b/tests/baselines/reference/assignmentCompatWithConstructSignatures3.errors.txt index fc64e02f7c6a9..accda4dd0fcb3 100644 --- a/tests/baselines/reference/assignmentCompatWithConstructSignatures3.errors.txt +++ b/tests/baselines/reference/assignmentCompatWithConstructSignatures3.errors.txt @@ -50,11 +50,6 @@ assignmentCompatWithConstructSignatures3.ts(80,1): error TS2322: Type 'new (x: B assignmentCompatWithConstructSignatures3.ts(83,1): error TS2322: Type 'new (x: Base[], y: Derived[]) => Derived[]' is not assignable to type 'new (x: Base[], y: T) => T'. Type 'Derived[]' is not assignable to type 'T'. 'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'. -assignmentCompatWithConstructSignatures3.ts(85,1): error TS2322: Type 'new (x: { a: T; b: T; }) => T' is not assignable to type 'new (x: { a: string; b: number; }) => Object'. - Types of parameters 'x' and 'x' are incompatible. - Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'. - Types of property 'b' are incompatible. - Type 'number' is not assignable to type 'string'. assignmentCompatWithConstructSignatures3.ts(86,1): error TS2322: Type 'new (x: { a: string; b: number; }) => Object' is not assignable to type 'new (x: { a: T; b: T; }) => T'. Types of parameters 'x' and 'x' are incompatible. Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'. @@ -62,7 +57,7 @@ assignmentCompatWithConstructSignatures3.ts(86,1): error TS2322: Type 'new (x: { Type 'T' is not assignable to type 'string'. -==== assignmentCompatWithConstructSignatures3.ts (15 errors) ==== +==== assignmentCompatWithConstructSignatures3.ts (14 errors) ==== // checking assignment compatibility relations for function types. All of these are valid. class Base { foo: string; } @@ -218,12 +213,6 @@ assignmentCompatWithConstructSignatures3.ts(86,1): error TS2322: Type 'new (x: { !!! error TS2322: 'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'. var b14: new (x: { a: T; b: T }) => T; a14 = b14; // ok - ~~~ -!!! error TS2322: Type 'new (x: { a: T; b: T; }) => T' is not assignable to type 'new (x: { a: string; b: number; }) => Object'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: string; b: string; }'. -!!! error TS2322: Types of property 'b' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. b14 = a14; // ok ~~~ !!! error TS2322: Type 'new (x: { a: string; b: number; }) => Object' is not assignable to type 'new (x: { a: T; b: T; }) => T'. diff --git a/tests/baselines/reference/callbackAssignabilityErrorMessage.errors.txt b/tests/baselines/reference/callbackAssignabilityErrorMessage.errors.txt new file mode 100644 index 0000000000000..ff9c4c85c7f5f --- /dev/null +++ b/tests/baselines/reference/callbackAssignabilityErrorMessage.errors.txt @@ -0,0 +1,45 @@ +callbackAssignabilityErrorMessage.ts(31,1): error TS2322: Type 'Source1' is not assignable to type 'Target'. + Types of property 'map' are incompatible. + Types of parameters 'callbackfn' and 'callbackfn' are incompatible. + Type 'T | undefined' is not assignable to type 'T'. + 'T' could be instantiated with an arbitrary type which could be unrelated to 'T | undefined'. + + +==== callbackAssignabilityErrorMessage.ts (1 errors) ==== + export interface Source1 { + map: (callbackfn: (value: string) => S) => S[]; + } + + export interface Target { + map: (callbackfn: (value: string) => T | undefined) => T[]; + } + + declare let s1: Source1; + declare let t: Target; + + // During the following assignment, `Source1["map"]` gets + // instantiated with the contextual type `Target["map"]` before checking + // assignability. To do that, an inference is made to `S`. For `Source1`, + // the only candidate is `T | undefined` from the return type of `callbackfn`. + // Inference also runs on `map` return types `S[]` and `T[]`, but the result + // is discarded because it’s run with a lower inference priority. As a result, + // we end up seeing if the contextually instantiated source signature: + // + // (callbackfn: (value: string) => T | undefined) => (T | undefined)[] + // + // is assignable to the target signature: + // + // (callbackfn: (value: string) => T | undefined) => T[] + // + // and the return types cause the failed assignability. But as a human reader + // interpreting why `s1` is not assignable to `t`, I instead equate `S` and `T` + // and identify the “real” problem as the return type of `callbackfn` in `Target` + // (`T | undefined`) being a supertype of the one in `Source1` (`S` → `T`). + + t = s1; // Bad: instantiates `S` with `T | undefined`, fails `map` return type assignability + ~ +!!! error TS2322: Type 'Source1' is not assignable to type 'Target'. +!!! error TS2322: Types of property 'map' are incompatible. +!!! error TS2322: Types of parameters 'callbackfn' and 'callbackfn' are incompatible. +!!! error TS2322: Type 'T | undefined' is not assignable to type 'T'. +!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T | undefined'. \ No newline at end of file diff --git a/tests/baselines/reference/callbackAssignabilityErrorMessage.js b/tests/baselines/reference/callbackAssignabilityErrorMessage.js new file mode 100644 index 0000000000000..698fa82c8647f --- /dev/null +++ b/tests/baselines/reference/callbackAssignabilityErrorMessage.js @@ -0,0 +1,56 @@ +//// [tests/cases/compiler/callbackAssignabilityErrorMessage.ts] //// + +//// [callbackAssignabilityErrorMessage.ts] +export interface Source1 { + map: (callbackfn: (value: string) => S) => S[]; +} + +export interface Target { + map: (callbackfn: (value: string) => T | undefined) => T[]; +} + +declare let s1: Source1; +declare let t: Target; + +// During the following assignment, `Source1["map"]` gets +// instantiated with the contextual type `Target["map"]` before checking +// assignability. To do that, an inference is made to `S`. For `Source1`, +// the only candidate is `T | undefined` from the return type of `callbackfn`. +// Inference also runs on `map` return types `S[]` and `T[]`, but the result +// is discarded because it’s run with a lower inference priority. As a result, +// we end up seeing if the contextually instantiated source signature: +// +// (callbackfn: (value: string) => T | undefined) => (T | undefined)[] +// +// is assignable to the target signature: +// +// (callbackfn: (value: string) => T | undefined) => T[] +// +// and the return types cause the failed assignability. But as a human reader +// interpreting why `s1` is not assignable to `t`, I instead equate `S` and `T` +// and identify the “real” problem as the return type of `callbackfn` in `Target` +// (`T | undefined`) being a supertype of the one in `Source1` (`S` → `T`). + +t = s1; // Bad: instantiates `S` with `T | undefined`, fails `map` return type assignability + +//// [callbackAssignabilityErrorMessage.js] +// During the following assignment, `Source1["map"]` gets +// instantiated with the contextual type `Target["map"]` before checking +// assignability. To do that, an inference is made to `S`. For `Source1`, +// the only candidate is `T | undefined` from the return type of `callbackfn`. +// Inference also runs on `map` return types `S[]` and `T[]`, but the result +// is discarded because it’s run with a lower inference priority. As a result, +// we end up seeing if the contextually instantiated source signature: +// +// (callbackfn: (value: string) => T | undefined) => (T | undefined)[] +// +// is assignable to the target signature: +// +// (callbackfn: (value: string) => T | undefined) => T[] +// +// and the return types cause the failed assignability. But as a human reader +// interpreting why `s1` is not assignable to `t`, I instead equate `S` and `T` +// and identify the “real” problem as the return type of `callbackfn` in `Target` +// (`T | undefined`) being a supertype of the one in `Source1` (`S` → `T`). +t = s1; // Bad: instantiates `S` with `T | undefined`, fails `map` return type assignability +export {}; diff --git a/tests/baselines/reference/callbackAssignabilityErrorMessage.symbols b/tests/baselines/reference/callbackAssignabilityErrorMessage.symbols new file mode 100644 index 0000000000000..f7efd73bdce4f --- /dev/null +++ b/tests/baselines/reference/callbackAssignabilityErrorMessage.symbols @@ -0,0 +1,58 @@ +//// [tests/cases/compiler/callbackAssignabilityErrorMessage.ts] //// + +=== callbackAssignabilityErrorMessage.ts === +export interface Source1 { +>Source1 : Symbol(Source1, Decl(callbackAssignabilityErrorMessage.ts, 0, 0)) + + map: (callbackfn: (value: string) => S) => S[]; +>map : Symbol(Source1.map, Decl(callbackAssignabilityErrorMessage.ts, 0, 26)) +>S : Symbol(S, Decl(callbackAssignabilityErrorMessage.ts, 1, 8)) +>callbackfn : Symbol(callbackfn, Decl(callbackAssignabilityErrorMessage.ts, 1, 11)) +>value : Symbol(value, Decl(callbackAssignabilityErrorMessage.ts, 1, 24)) +>S : Symbol(S, Decl(callbackAssignabilityErrorMessage.ts, 1, 8)) +>S : Symbol(S, Decl(callbackAssignabilityErrorMessage.ts, 1, 8)) +} + +export interface Target { +>Target : Symbol(Target, Decl(callbackAssignabilityErrorMessage.ts, 2, 1)) + + map: (callbackfn: (value: string) => T | undefined) => T[]; +>map : Symbol(Target.map, Decl(callbackAssignabilityErrorMessage.ts, 4, 25)) +>T : Symbol(T, Decl(callbackAssignabilityErrorMessage.ts, 5, 8)) +>callbackfn : Symbol(callbackfn, Decl(callbackAssignabilityErrorMessage.ts, 5, 11)) +>value : Symbol(value, Decl(callbackAssignabilityErrorMessage.ts, 5, 24)) +>T : Symbol(T, Decl(callbackAssignabilityErrorMessage.ts, 5, 8)) +>T : Symbol(T, Decl(callbackAssignabilityErrorMessage.ts, 5, 8)) +} + +declare let s1: Source1; +>s1 : Symbol(s1, Decl(callbackAssignabilityErrorMessage.ts, 8, 11)) +>Source1 : Symbol(Source1, Decl(callbackAssignabilityErrorMessage.ts, 0, 0)) + +declare let t: Target; +>t : Symbol(t, Decl(callbackAssignabilityErrorMessage.ts, 9, 11)) +>Target : Symbol(Target, Decl(callbackAssignabilityErrorMessage.ts, 2, 1)) + +// During the following assignment, `Source1["map"]` gets +// instantiated with the contextual type `Target["map"]` before checking +// assignability. To do that, an inference is made to `S`. For `Source1`, +// the only candidate is `T | undefined` from the return type of `callbackfn`. +// Inference also runs on `map` return types `S[]` and `T[]`, but the result +// is discarded because it’s run with a lower inference priority. As a result, +// we end up seeing if the contextually instantiated source signature: +// +// (callbackfn: (value: string) => T | undefined) => (T | undefined)[] +// +// is assignable to the target signature: +// +// (callbackfn: (value: string) => T | undefined) => T[] +// +// and the return types cause the failed assignability. But as a human reader +// interpreting why `s1` is not assignable to `t`, I instead equate `S` and `T` +// and identify the “real” problem as the return type of `callbackfn` in `Target` +// (`T | undefined`) being a supertype of the one in `Source1` (`S` → `T`). + +t = s1; // Bad: instantiates `S` with `T | undefined`, fails `map` return type assignability +>t : Symbol(t, Decl(callbackAssignabilityErrorMessage.ts, 9, 11)) +>s1 : Symbol(s1, Decl(callbackAssignabilityErrorMessage.ts, 8, 11)) + diff --git a/tests/baselines/reference/callbackAssignabilityErrorMessage.types b/tests/baselines/reference/callbackAssignabilityErrorMessage.types new file mode 100644 index 0000000000000..69118163e6186 --- /dev/null +++ b/tests/baselines/reference/callbackAssignabilityErrorMessage.types @@ -0,0 +1,58 @@ +//// [tests/cases/compiler/callbackAssignabilityErrorMessage.ts] //// + +=== callbackAssignabilityErrorMessage.ts === +export interface Source1 { + map: (callbackfn: (value: string) => S) => S[]; +>map : (callbackfn: (value: string) => S) => S[] +> : ^ ^^ ^^ ^^^^^ +>callbackfn : (value: string) => S +> : ^ ^^ ^^^^^ +>value : string +> : ^^^^^^ +} + +export interface Target { + map: (callbackfn: (value: string) => T | undefined) => T[]; +>map : (callbackfn: (value: string) => T | undefined) => T[] +> : ^ ^^ ^^ ^^^^^ +>callbackfn : (value: string) => T | undefined +> : ^ ^^ ^^^^^ +>value : string +> : ^^^^^^ +} + +declare let s1: Source1; +>s1 : Source1 +> : ^^^^^^^ + +declare let t: Target; +>t : Target +> : ^^^^^^ + +// During the following assignment, `Source1["map"]` gets +// instantiated with the contextual type `Target["map"]` before checking +// assignability. To do that, an inference is made to `S`. For `Source1`, +// the only candidate is `T | undefined` from the return type of `callbackfn`. +// Inference also runs on `map` return types `S[]` and `T[]`, but the result +// is discarded because it’s run with a lower inference priority. As a result, +// we end up seeing if the contextually instantiated source signature: +// +// (callbackfn: (value: string) => T | undefined) => (T | undefined)[] +// +// is assignable to the target signature: +// +// (callbackfn: (value: string) => T | undefined) => T[] +// +// and the return types cause the failed assignability. But as a human reader +// interpreting why `s1` is not assignable to `t`, I instead equate `S` and `T` +// and identify the “real” problem as the return type of `callbackfn` in `Target` +// (`T | undefined`) being a supertype of the one in `Source1` (`S` → `T`). + +t = s1; // Bad: instantiates `S` with `T | undefined`, fails `map` return type assignability +>t = s1 : Source1 +> : ^^^^^^^ +>t : Target +> : ^^^^^^ +>s1 : Source1 +> : ^^^^^^^ + diff --git a/tests/baselines/reference/mappedTypeInferenceFromApparentType.errors.txt b/tests/baselines/reference/mappedTypeInferenceFromApparentType.errors.txt index f61f0d58bcb99..1fb9256f04838 100644 --- a/tests/baselines/reference/mappedTypeInferenceFromApparentType.errors.txt +++ b/tests/baselines/reference/mappedTypeInferenceFromApparentType.errors.txt @@ -1,9 +1,7 @@ mappedTypeInferenceFromApparentType.ts(10,1): error TS2322: Type 'foo' is not assignable to type 'bar'. Types of parameters 'target' and 'source' are incompatible. - Type '{ [K in keyof U]: Obj[K]; }' is not assignable to type '{ [K in keyof U]: U[K]; }'. - Type 'Obj[K]' is not assignable to type 'U[K]'. - Type 'Obj' is not assignable to type 'U'. - 'U' could be instantiated with an arbitrary type which could be unrelated to 'Obj'. + Type '{ [K in keyof U]: Obj[K]; }' is not assignable to type '{ [x: string]: number; }'. + Index signature for type 'string' is missing in type 'number[]'. ==== mappedTypeInferenceFromApparentType.ts (1 errors) ==== @@ -20,7 +18,5 @@ mappedTypeInferenceFromApparentType.ts(10,1): error TS2322: Type 'foo' is not as ~ !!! error TS2322: Type 'foo' is not assignable to type 'bar'. !!! error TS2322: Types of parameters 'target' and 'source' are incompatible. -!!! error TS2322: Type '{ [K in keyof U]: Obj[K]; }' is not assignable to type '{ [K in keyof U]: U[K]; }'. -!!! error TS2322: Type 'Obj[K]' is not assignable to type 'U[K]'. -!!! error TS2322: Type 'Obj' is not assignable to type 'U'. -!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'Obj'. \ No newline at end of file +!!! error TS2322: Type '{ [K in keyof U]: Obj[K]; }' is not assignable to type '{ [x: string]: number; }'. +!!! error TS2322: Index signature for type 'string' is missing in type 'number[]'. \ No newline at end of file diff --git a/tests/baselines/reference/subtypingWithCallSignatures2.types b/tests/baselines/reference/subtypingWithCallSignatures2.types index 7315697b45ee2..8f4a10455a0c7 100644 --- a/tests/baselines/reference/subtypingWithCallSignatures2.types +++ b/tests/baselines/reference/subtypingWithCallSignatures2.types @@ -1178,8 +1178,10 @@ var r14arg2 = (x: { a: string; b: number }) => null; > : ^^^^^^ var r14 = foo14(r14arg1); // any ->r14 : any ->foo14(r14arg1) : any +>r14 : (x: { a: string; b: number; }) => Object +> : ^ ^^ ^^^^^^^^^^^ +>foo14(r14arg1) : (x: { a: string; b: number; }) => Object +> : ^ ^^ ^^^^^^^^^^^ >foo14 : { (a: (x: { a: string; b: number; }) => Object): (x: { a: string; b: number; }) => Object; (a: any): any; } > : ^^^ ^^ ^^^^ ^^ ^^^^^^^^^^^^^^ ^^ ^^^^^^^^^ >r14arg1 : (x: { a: T; b: T; }) => T diff --git a/tests/baselines/reference/subtypingWithConstructSignatures2.types b/tests/baselines/reference/subtypingWithConstructSignatures2.types index 7d2f0f659d747..dae8a3a23c2a4 100644 --- a/tests/baselines/reference/subtypingWithConstructSignatures2.types +++ b/tests/baselines/reference/subtypingWithConstructSignatures2.types @@ -1038,8 +1038,10 @@ var r14arg2: new (x: { a: string; b: number }) => Object; > : ^^^^^^ var r14 = foo14(r14arg1); // any ->r14 : any ->foo14(r14arg1) : any +>r14 : new (x: { a: string; b: number; }) => Object +> : ^^^^^ ^^ ^^^^^^^^^^^ +>foo14(r14arg1) : new (x: { a: string; b: number; }) => Object +> : ^^^^^ ^^ ^^^^^^^^^^^ >foo14 : { (a: new (x: { a: string; b: number; }) => Object): new (x: { a: string; b: number; }) => Object; (a: any): any; } > : ^^^ ^^ ^^^^^^^^ ^^ ^^^^^^^^^^^^^^ ^^ ^^^^^^^^^ >r14arg1 : new (x: { a: T; b: T; }) => T diff --git a/tests/cases/compiler/callbackAssignabilityErrorMessage.ts b/tests/cases/compiler/callbackAssignabilityErrorMessage.ts new file mode 100644 index 0000000000000..0eeaa299cef9f --- /dev/null +++ b/tests/cases/compiler/callbackAssignabilityErrorMessage.ts @@ -0,0 +1,35 @@ +// @strict: true +// @target: esnext + + +export interface Source1 { + map: (callbackfn: (value: string) => S) => S[]; +} + +export interface Target { + map: (callbackfn: (value: string) => T | undefined) => T[]; +} + +declare let s1: Source1; +declare let t: Target; + +// During the following assignment, `Source1["map"]` gets +// instantiated with the contextual type `Target["map"]` before checking +// assignability. To do that, an inference is made to `S`. For `Source1`, +// the only candidate is `T | undefined` from the return type of `callbackfn`. +// Inference also runs on `map` return types `S[]` and `T[]`, but the result +// is discarded because it’s run with a lower inference priority. As a result, +// we end up seeing if the contextually instantiated source signature: +// +// (callbackfn: (value: string) => T | undefined) => (T | undefined)[] +// +// is assignable to the target signature: +// +// (callbackfn: (value: string) => T | undefined) => T[] +// +// and the return types cause the failed assignability. But as a human reader +// interpreting why `s1` is not assignable to `t`, I instead equate `S` and `T` +// and identify the “real” problem as the return type of `callbackfn` in `Target` +// (`T | undefined`) being a supertype of the one in `Source1` (`S` → `T`). + +t = s1; // Bad: instantiates `S` with `T | undefined`, fails `map` return type assignability \ No newline at end of file