From 81fc2a14d19ae763286f75a6fba61e05e777edd3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 11 Oct 2017 12:01:26 -0700 Subject: [PATCH 1/3] Don't check for callbacks in recursive call that resulted from callbacks --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 ? From 07e4819b8bb5db64c2d00c91b7ce184de1eb4723 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 11 Oct 2017 12:01:38 -0700 Subject: [PATCH 2/3] Add regression test --- tests/cases/compiler/mutuallyRecursiveCallbacks.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/cases/compiler/mutuallyRecursiveCallbacks.ts 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; From 38cec121902d505de3cf71711f7c4c847563e9d6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 11 Oct 2017 12:02:01 -0700 Subject: [PATCH 3/3] Accept new baselines --- .../mutuallyRecursiveCallbacks.errors.txt | 24 +++++++++++++ .../reference/mutuallyRecursiveCallbacks.js | 14 ++++++++ .../mutuallyRecursiveCallbacks.symbols | 34 ++++++++++++++++++ .../mutuallyRecursiveCallbacks.types | 35 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 tests/baselines/reference/mutuallyRecursiveCallbacks.errors.txt create mode 100644 tests/baselines/reference/mutuallyRecursiveCallbacks.js create mode 100644 tests/baselines/reference/mutuallyRecursiveCallbacks.symbols create mode 100644 tests/baselines/reference/mutuallyRecursiveCallbacks.types 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 +