Skip to content

Commit bd27bd8

Browse files
authored
Don't relate unmatched parameter positions in signatures (#41308)
* Don't relate unmatched parameter positions in signatures * Add regression test * Accept new baselines
1 parent 3eed4a6 commit bd27bd8

File tree

5 files changed

+82
-28
lines changed

5 files changed

+82
-28
lines changed

src/compiler/checker.ts

+30-28
Original file line numberDiff line numberDiff line change
@@ -16156,36 +16156,38 @@ namespace ts {
1615616156
const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1;
1615716157

1615816158
for (let i = 0; i < paramCount; i++) {
16159-
const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : getTypeAtPosition(source, i);
16160-
const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : getTypeAtPosition(target, i);
16161-
// In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
16162-
// how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
16163-
// they naturally relate only contra-variantly). However, if the source and target parameters both have
16164-
// function types with a single call signature, we know we are relating two callback parameters. In
16165-
// that case it is sufficient to only relate the parameters of the signatures co-variantly because,
16166-
// similar to return values, callback parameters are output positions. This means that a Promise<T>,
16167-
// where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant)
16168-
// with respect to T.
16169-
const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
16170-
const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType));
16171-
const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
16172-
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
16173-
let related = callbacks ?
16174-
compareSignaturesRelated(targetSig!, sourceSig!, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
16175-
!(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
16176-
// With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void
16177-
if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) {
16178-
related = Ternary.False;
16179-
}
16180-
if (!related) {
16181-
if (reportErrors) {
16182-
errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
16183-
unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)),
16184-
unescapeLeadingUnderscores(getParameterNameAtPosition(target, i)));
16159+
const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i);
16160+
const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i);
16161+
if (sourceType && targetType) {
16162+
// In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
16163+
// how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
16164+
// they naturally relate only contra-variantly). However, if the source and target parameters both have
16165+
// function types with a single call signature, we know we are relating two callback parameters. In
16166+
// that case it is sufficient to only relate the parameters of the signatures co-variantly because,
16167+
// similar to return values, callback parameters are output positions. This means that a Promise<T>,
16168+
// where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant)
16169+
// with respect to T.
16170+
const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType));
16171+
const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType));
16172+
const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
16173+
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
16174+
let related = callbacks ?
16175+
compareSignaturesRelated(targetSig!, sourceSig!, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
16176+
!(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
16177+
// With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void
16178+
if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) {
16179+
related = Ternary.False;
1618516180
}
16186-
return Ternary.False;
16181+
if (!related) {
16182+
if (reportErrors) {
16183+
errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
16184+
unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)),
16185+
unescapeLeadingUnderscores(getParameterNameAtPosition(target, i)));
16186+
}
16187+
return Ternary.False;
16188+
}
16189+
result &= related;
1618716190
}
16188-
result &= related;
1618916191
}
1619016192

1619116193
if (!(checkMode & SignatureCheckMode.IgnoreReturnTypes)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [unmatchedParameterPositions.ts]
2+
// Repros from #40251
3+
4+
declare let s: (...items: never[]) => never[];
5+
let t1: () => unknown[] = s;
6+
let t2: (...args: []) => unknown[] = s;
7+
8+
9+
//// [unmatchedParameterPositions.js]
10+
"use strict";
11+
// Repros from #40251
12+
var t1 = s;
13+
var t2 = s;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/compiler/unmatchedParameterPositions.ts ===
2+
// Repros from #40251
3+
4+
declare let s: (...items: never[]) => never[];
5+
>s : Symbol(s, Decl(unmatchedParameterPositions.ts, 2, 11))
6+
>items : Symbol(items, Decl(unmatchedParameterPositions.ts, 2, 16))
7+
8+
let t1: () => unknown[] = s;
9+
>t1 : Symbol(t1, Decl(unmatchedParameterPositions.ts, 3, 3))
10+
>s : Symbol(s, Decl(unmatchedParameterPositions.ts, 2, 11))
11+
12+
let t2: (...args: []) => unknown[] = s;
13+
>t2 : Symbol(t2, Decl(unmatchedParameterPositions.ts, 4, 3))
14+
>args : Symbol(args, Decl(unmatchedParameterPositions.ts, 4, 9))
15+
>s : Symbol(s, Decl(unmatchedParameterPositions.ts, 2, 11))
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/compiler/unmatchedParameterPositions.ts ===
2+
// Repros from #40251
3+
4+
declare let s: (...items: never[]) => never[];
5+
>s : (...items: never[]) => never[]
6+
>items : never[]
7+
8+
let t1: () => unknown[] = s;
9+
>t1 : () => unknown[]
10+
>s : (...items: never[]) => never[]
11+
12+
let t2: (...args: []) => unknown[] = s;
13+
>t2 : () => unknown[]
14+
>args : []
15+
>s : (...items: never[]) => never[]
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @strict: true
2+
3+
// Repros from #40251
4+
5+
declare let s: (...items: never[]) => never[];
6+
let t1: () => unknown[] = s;
7+
let t2: (...args: []) => unknown[] = s;

0 commit comments

Comments
 (0)