diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ce1769118a454..0cb7fe909dc4b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8579,16 +8579,16 @@ namespace ts { for (let i = 0; i < checkCount; i++) { const sourceType = i < sourceMax ? getTypeOfParameter(sourceParams[i]) : getRestTypeOfSignature(source); const targetType = i < targetMax ? getTypeOfParameter(targetParams[i]) : getRestTypeOfSignature(target); - const sourceSig = getSingleCallSignature(getNonNullableType(sourceType)); - const targetSig = getSingleCallSignature(getNonNullableType(targetType)); // In order to ensure that any generic type Foo 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 known we are relating two callback parameters. In + // 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, // where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant) // with respect to T. + const sourceSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); + const targetSig = callbackCheck ? undefined : getSingleCallSignature(getNonNullableType(targetType)); const callbacks = sourceSig && targetSig && !sourceSig.typePredicate && !targetSig.typePredicate && (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); const related = callbacks ? diff --git a/tests/baselines/reference/mutuallyRecursiveCallbacks.errors.txt b/tests/baselines/reference/mutuallyRecursiveCallbacks.errors.txt new file mode 100644 index 0000000000000..0682caad5b8aa --- /dev/null +++ b/tests/baselines/reference/mutuallyRecursiveCallbacks.errors.txt @@ -0,0 +1,24 @@ +tests/cases/compiler/mutuallyRecursiveCallbacks.ts(7,1): error TS2322: Type '(bar: Bar) => void' is not assignable to type 'Bar<{}>'. + Types of parameters 'bar' and 'foo' are incompatible. + Types of parameters 'bar' and 'foo' are incompatible. + Type 'Foo<{}>' is not assignable to type 'Bar<{}>'. + Types of parameters 'bar' and 'foo' are incompatible. + Type 'void' is not assignable to type 'Foo<{}>'. + + +==== tests/cases/compiler/mutuallyRecursiveCallbacks.ts (1 errors) ==== + // Repro from #18277 + + interface Foo { (bar: Bar): void }; + type Bar = (foo: Foo) => Foo; + declare function foo(bar: Bar): void; + declare var bar: Bar<{}>; + bar = foo; + ~~~ +!!! error TS2322: Type '(bar: Bar) => void' is not assignable to type 'Bar<{}>'. +!!! error TS2322: Types of parameters 'bar' and 'foo' are incompatible. +!!! error TS2322: Types of parameters 'bar' and 'foo' are incompatible. +!!! error TS2322: Type 'Foo<{}>' is not assignable to type 'Bar<{}>'. +!!! error TS2322: Types of parameters 'bar' and 'foo' are incompatible. +!!! error TS2322: Type 'void' is not assignable to type 'Foo<{}>'. + \ No newline at end of file diff --git a/tests/baselines/reference/mutuallyRecursiveCallbacks.js b/tests/baselines/reference/mutuallyRecursiveCallbacks.js new file mode 100644 index 0000000000000..df52508df7a17 --- /dev/null +++ b/tests/baselines/reference/mutuallyRecursiveCallbacks.js @@ -0,0 +1,14 @@ +//// [mutuallyRecursiveCallbacks.ts] +// Repro from #18277 + +interface Foo { (bar: Bar): void }; +type Bar = (foo: Foo) => Foo; +declare function foo(bar: Bar): void; +declare var bar: Bar<{}>; +bar = foo; + + +//// [mutuallyRecursiveCallbacks.js] +// Repro from #18277 +; +bar = foo; diff --git a/tests/baselines/reference/mutuallyRecursiveCallbacks.symbols b/tests/baselines/reference/mutuallyRecursiveCallbacks.symbols new file mode 100644 index 0000000000000..50cb0c0dea052 --- /dev/null +++ b/tests/baselines/reference/mutuallyRecursiveCallbacks.symbols @@ -0,0 +1,34 @@ +=== tests/cases/compiler/mutuallyRecursiveCallbacks.ts === +// Repro from #18277 + +interface Foo { (bar: Bar): void }; +>Foo : Symbol(Foo, Decl(mutuallyRecursiveCallbacks.ts, 0, 0)) +>T : Symbol(T, Decl(mutuallyRecursiveCallbacks.ts, 2, 14)) +>bar : Symbol(bar, Decl(mutuallyRecursiveCallbacks.ts, 2, 20)) +>Bar : Symbol(Bar, Decl(mutuallyRecursiveCallbacks.ts, 2, 41)) +>T : Symbol(T, Decl(mutuallyRecursiveCallbacks.ts, 2, 14)) + +type Bar = (foo: Foo) => Foo; +>Bar : Symbol(Bar, Decl(mutuallyRecursiveCallbacks.ts, 2, 41)) +>T : Symbol(T, Decl(mutuallyRecursiveCallbacks.ts, 3, 9)) +>foo : Symbol(foo, Decl(mutuallyRecursiveCallbacks.ts, 3, 15)) +>Foo : Symbol(Foo, Decl(mutuallyRecursiveCallbacks.ts, 0, 0)) +>T : Symbol(T, Decl(mutuallyRecursiveCallbacks.ts, 3, 9)) +>Foo : Symbol(Foo, Decl(mutuallyRecursiveCallbacks.ts, 0, 0)) +>T : Symbol(T, Decl(mutuallyRecursiveCallbacks.ts, 3, 9)) + +declare function foo(bar: Bar): void; +>foo : Symbol(foo, Decl(mutuallyRecursiveCallbacks.ts, 3, 38)) +>T : Symbol(T, Decl(mutuallyRecursiveCallbacks.ts, 4, 21)) +>bar : Symbol(bar, Decl(mutuallyRecursiveCallbacks.ts, 4, 24)) +>Bar : Symbol(Bar, Decl(mutuallyRecursiveCallbacks.ts, 2, 41)) +>T : Symbol(T, Decl(mutuallyRecursiveCallbacks.ts, 4, 21)) + +declare var bar: Bar<{}>; +>bar : Symbol(bar, Decl(mutuallyRecursiveCallbacks.ts, 5, 11)) +>Bar : Symbol(Bar, Decl(mutuallyRecursiveCallbacks.ts, 2, 41)) + +bar = foo; +>bar : Symbol(bar, Decl(mutuallyRecursiveCallbacks.ts, 5, 11)) +>foo : Symbol(foo, Decl(mutuallyRecursiveCallbacks.ts, 3, 38)) + diff --git a/tests/baselines/reference/mutuallyRecursiveCallbacks.types b/tests/baselines/reference/mutuallyRecursiveCallbacks.types new file mode 100644 index 0000000000000..4a7b4dd049314 --- /dev/null +++ b/tests/baselines/reference/mutuallyRecursiveCallbacks.types @@ -0,0 +1,35 @@ +=== tests/cases/compiler/mutuallyRecursiveCallbacks.ts === +// Repro from #18277 + +interface Foo { (bar: Bar): void }; +>Foo : Foo +>T : T +>bar : Bar +>Bar : Bar +>T : T + +type Bar = (foo: Foo) => Foo; +>Bar : Bar +>T : T +>foo : Foo +>Foo : Foo +>T : T +>Foo : Foo +>T : T + +declare function foo(bar: Bar): void; +>foo : (bar: Bar) => void +>T : T +>bar : Bar +>Bar : Bar +>T : T + +declare var bar: Bar<{}>; +>bar : Bar<{}> +>Bar : Bar + +bar = foo; +>bar = foo : (bar: Bar) => void +>bar : Bar<{}> +>foo : (bar: Bar) => void + diff --git a/tests/cases/compiler/mutuallyRecursiveCallbacks.ts b/tests/cases/compiler/mutuallyRecursiveCallbacks.ts new file mode 100644 index 0000000000000..94f2d28578614 --- /dev/null +++ b/tests/cases/compiler/mutuallyRecursiveCallbacks.ts @@ -0,0 +1,7 @@ +// Repro from #18277 + +interface Foo { (bar: Bar): void }; +type Bar = (foo: Foo) => Foo; +declare function foo(bar: Bar): void; +declare var bar: Bar<{}>; +bar = foo;