mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 20:37:00 -05:00
Don't relate unmatched parameter positions in signatures (#41308)
* Don't relate unmatched parameter positions in signatures * Add regression test * Accept new baselines
This commit is contained in:
@@ -16156,36 +16156,38 @@ namespace ts {
|
||||
const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1;
|
||||
|
||||
for (let i = 0; i < paramCount; i++) {
|
||||
const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : getTypeAtPosition(source, i);
|
||||
const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : getTypeAtPosition(target, i);
|
||||
// In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
|
||||
// how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
|
||||
// they naturally relate only contra-variantly). However, if the source and target parameters both have
|
||||
// function types with a single call signature, we know we are relating two callback parameters. In
|
||||
// that case it is sufficient to only relate the parameters of the signatures co-variantly because,
|
||||
// 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 callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
|
||||
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
|
||||
let related = callbacks ?
|
||||
compareSignaturesRelated(targetSig!, sourceSig!, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
|
||||
!(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
|
||||
// With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void
|
||||
if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) {
|
||||
related = Ternary.False;
|
||||
}
|
||||
if (!related) {
|
||||
if (reportErrors) {
|
||||
errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
|
||||
unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)),
|
||||
unescapeLeadingUnderscores(getParameterNameAtPosition(target, i)));
|
||||
const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i);
|
||||
const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i);
|
||||
if (sourceType && targetType) {
|
||||
// In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
|
||||
// how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
|
||||
// they naturally relate only contra-variantly). However, if the source and target parameters both have
|
||||
// function types with a single call signature, we know we are relating two callback parameters. In
|
||||
// that case it is sufficient to only relate the parameters of the signatures co-variantly because,
|
||||
// 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 callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
|
||||
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
|
||||
let related = callbacks ?
|
||||
compareSignaturesRelated(targetSig!, sourceSig!, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
|
||||
!(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
|
||||
// With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void
|
||||
if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) {
|
||||
related = Ternary.False;
|
||||
}
|
||||
return Ternary.False;
|
||||
if (!related) {
|
||||
if (reportErrors) {
|
||||
errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
|
||||
unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)),
|
||||
unescapeLeadingUnderscores(getParameterNameAtPosition(target, i)));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
result &= related;
|
||||
}
|
||||
result &= related;
|
||||
}
|
||||
|
||||
if (!(checkMode & SignatureCheckMode.IgnoreReturnTypes)) {
|
||||
|
||||
13
tests/baselines/reference/unmatchedParameterPositions.js
Normal file
13
tests/baselines/reference/unmatchedParameterPositions.js
Normal file
@@ -0,0 +1,13 @@
|
||||
//// [unmatchedParameterPositions.ts]
|
||||
// Repros from #40251
|
||||
|
||||
declare let s: (...items: never[]) => never[];
|
||||
let t1: () => unknown[] = s;
|
||||
let t2: (...args: []) => unknown[] = s;
|
||||
|
||||
|
||||
//// [unmatchedParameterPositions.js]
|
||||
"use strict";
|
||||
// Repros from #40251
|
||||
var t1 = s;
|
||||
var t2 = s;
|
||||
@@ -0,0 +1,16 @@
|
||||
=== tests/cases/compiler/unmatchedParameterPositions.ts ===
|
||||
// Repros from #40251
|
||||
|
||||
declare let s: (...items: never[]) => never[];
|
||||
>s : Symbol(s, Decl(unmatchedParameterPositions.ts, 2, 11))
|
||||
>items : Symbol(items, Decl(unmatchedParameterPositions.ts, 2, 16))
|
||||
|
||||
let t1: () => unknown[] = s;
|
||||
>t1 : Symbol(t1, Decl(unmatchedParameterPositions.ts, 3, 3))
|
||||
>s : Symbol(s, Decl(unmatchedParameterPositions.ts, 2, 11))
|
||||
|
||||
let t2: (...args: []) => unknown[] = s;
|
||||
>t2 : Symbol(t2, Decl(unmatchedParameterPositions.ts, 4, 3))
|
||||
>args : Symbol(args, Decl(unmatchedParameterPositions.ts, 4, 9))
|
||||
>s : Symbol(s, Decl(unmatchedParameterPositions.ts, 2, 11))
|
||||
|
||||
16
tests/baselines/reference/unmatchedParameterPositions.types
Normal file
16
tests/baselines/reference/unmatchedParameterPositions.types
Normal file
@@ -0,0 +1,16 @@
|
||||
=== tests/cases/compiler/unmatchedParameterPositions.ts ===
|
||||
// Repros from #40251
|
||||
|
||||
declare let s: (...items: never[]) => never[];
|
||||
>s : (...items: never[]) => never[]
|
||||
>items : never[]
|
||||
|
||||
let t1: () => unknown[] = s;
|
||||
>t1 : () => unknown[]
|
||||
>s : (...items: never[]) => never[]
|
||||
|
||||
let t2: (...args: []) => unknown[] = s;
|
||||
>t2 : () => unknown[]
|
||||
>args : []
|
||||
>s : (...items: never[]) => never[]
|
||||
|
||||
7
tests/cases/compiler/unmatchedParameterPositions.ts
Normal file
7
tests/cases/compiler/unmatchedParameterPositions.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// @strict: true
|
||||
|
||||
// Repros from #40251
|
||||
|
||||
declare let s: (...items: never[]) => never[];
|
||||
let t1: () => unknown[] = s;
|
||||
let t2: (...args: []) => unknown[] = s;
|
||||
Reference in New Issue
Block a user