From 8ebc95ffcdb81fb6acab7dec548afc7540fa01f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 3 Feb 2023 14:28:38 +0100 Subject: [PATCH 1/8] Filter out non-array types when contextually typing union members --- src/compiler/checker.ts | 3 +- ...rrayElementPrefersArrayUnionMember.symbols | 27 ++++++++++++++++++ ...nArrayElementPrefersArrayUnionMember.types | 28 +++++++++++++++++++ ...reInArrayElementPrefersArrayUnionMember.ts | 14 ++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.symbols create mode 100644 tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.types create mode 100644 tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c61581facde83..215c8d82aaaae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28838,8 +28838,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated // type of T. function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined { + const hasIterable = getGlobalIterableType(/* reportErrors */ false) !== emptyGenericType; return arrayContextualType && ( - getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) + getTypeOfPropertyOfContextualType(filterType(arrayContextualType, t => isArrayOrTupleLikeType(t) || !!getIndexTypeOfType(t, numberType) || hasIterable && isTypeAssignableTo(t, createIterableType(anyType))), "" + index as __String) || mapType( arrayContextualType, t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false), diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.symbols b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.symbols new file mode 100644 index 0000000000000..7a10411bfa84b --- /dev/null +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts === +// repro from #52588 + +declare function test( +>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 0, 0)) + + arg: Record void> | Array<(arg: number) => void> +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 2, 22)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 3, 23)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 3, 54)) + +): void; + +test([ +>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 0, 0)) + + (arg) => { +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 7, 3)) + + arg; // number +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 7, 3)) + + }, +]); + diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.types b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.types new file mode 100644 index 0000000000000..46c74beb9459d --- /dev/null +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.types @@ -0,0 +1,28 @@ +=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts === +// repro from #52588 + +declare function test( +>test : (arg: Record void> | ((arg: number) => void)[]) => void + + arg: Record void> | Array<(arg: number) => void> +>arg : Record void> | ((arg: number) => void)[] +>arg : string +>arg : number + +): void; + +test([ +>test([ (arg) => { arg; // number },]) : void +>test : (arg: Record void> | ((arg: number) => void)[]) => void +>[ (arg) => { arg; // number },] : ((arg: number) => void)[] + + (arg) => { +>(arg) => { arg; // number } : (arg: number) => void +>arg : number + + arg; // number +>arg : number + + }, +]); + diff --git a/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts b/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts new file mode 100644 index 0000000000000..2af3c0735fcdd --- /dev/null +++ b/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts @@ -0,0 +1,14 @@ +// @strict: true +// @noEmit: true + +// repro from #52588 + +declare function test( + arg: Record void> | Array<(arg: number) => void> +): void; + +test([ + (arg) => { + arg; // number + }, +]); From c659bc8fb69792e3dbd401836b0d124f2c90b81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 11 Feb 2023 09:36:24 +0100 Subject: [PATCH 2/8] Add extra test case for contextual type caching --- .../reference/contextualTypeCaching.symbols | 67 +++++++++++++++++++ .../reference/contextualTypeCaching.types | 58 ++++++++++++++++ tests/cases/compiler/contextualTypeCaching.ts | 24 +++++++ 3 files changed, 149 insertions(+) diff --git a/tests/baselines/reference/contextualTypeCaching.symbols b/tests/baselines/reference/contextualTypeCaching.symbols index 24122b7afddd5..2550a1e5ff02e 100644 --- a/tests/baselines/reference/contextualTypeCaching.symbols +++ b/tests/baselines/reference/contextualTypeCaching.symbols @@ -60,3 +60,70 @@ emit('a', { }, }); +// simplified repro from 52589#issuecomment-1416180638 +declare class MyCompiler { +>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3)) + + compile(): void; +>compile : Symbol(MyCompiler.compile, Decl(contextualTypeCaching.ts, 24, 26)) +} +interface WebpackPluginInstance { +>WebpackPluginInstance : Symbol(WebpackPluginInstance, Decl(contextualTypeCaching.ts, 26, 1)) + + apply: (compiler: MyCompiler) => void; +>apply : Symbol(WebpackPluginInstance.apply, Decl(contextualTypeCaching.ts, 27, 33)) +>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 28, 10)) +>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3)) +} +type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void; +>WebpackPluginFunction : Symbol(WebpackPluginFunction, Decl(contextualTypeCaching.ts, 29, 1)) +>this : Symbol(this, Decl(contextualTypeCaching.ts, 30, 30)) +>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3)) +>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 30, 47)) +>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3)) + +interface Optimization { +>Optimization : Symbol(Optimization, Decl(contextualTypeCaching.ts, 30, 78)) + + minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[]; +>minimizer : Symbol(Optimization.minimizer, Decl(contextualTypeCaching.ts, 31, 24)) +>WebpackPluginInstance : Symbol(WebpackPluginInstance, Decl(contextualTypeCaching.ts, 26, 1)) +>WebpackPluginFunction : Symbol(WebpackPluginFunction, Decl(contextualTypeCaching.ts, 29, 1)) +} +declare const A: ( +>A : Symbol(A, Decl(contextualTypeCaching.ts, 34, 13)) +>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18)) +>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20)) +>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18)) + + obj: T, +>obj : Symbol(obj, Decl(contextualTypeCaching.ts, 34, 40)) +>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18)) + + prop: P, +>prop : Symbol(prop, Decl(contextualTypeCaching.ts, 35, 9)) +>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20)) + + factory: () => T[P] +>factory : Symbol(factory, Decl(contextualTypeCaching.ts, 36, 10)) +>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18)) +>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20)) + +) => void; +export const applyOptimizationDefaults = (optimization: Optimization) => { +>applyOptimizationDefaults : Symbol(applyOptimizationDefaults, Decl(contextualTypeCaching.ts, 39, 12)) +>optimization : Symbol(optimization, Decl(contextualTypeCaching.ts, 39, 42)) +>Optimization : Symbol(Optimization, Decl(contextualTypeCaching.ts, 30, 78)) + + A(optimization, "minimizer", () => [ +>A : Symbol(A, Decl(contextualTypeCaching.ts, 34, 13)) +>optimization : Symbol(optimization, Decl(contextualTypeCaching.ts, 39, 42)) + { + apply: (compiler) => {}, +>apply : Symbol(apply, Decl(contextualTypeCaching.ts, 41, 5)) +>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 42, 14)) + + }, + ]); +}; + diff --git a/tests/baselines/reference/contextualTypeCaching.types b/tests/baselines/reference/contextualTypeCaching.types index 16c99d04e16d2..8b898dcb2e0ee 100644 --- a/tests/baselines/reference/contextualTypeCaching.types +++ b/tests/baselines/reference/contextualTypeCaching.types @@ -54,3 +54,61 @@ emit('a', { }, }); +// simplified repro from 52589#issuecomment-1416180638 +declare class MyCompiler { +>MyCompiler : MyCompiler + + compile(): void; +>compile : () => void +} +interface WebpackPluginInstance { + apply: (compiler: MyCompiler) => void; +>apply : (compiler: MyCompiler) => void +>compiler : MyCompiler +} +type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void; +>WebpackPluginFunction : (this: MyCompiler, compiler: MyCompiler) => void +>this : MyCompiler +>compiler : MyCompiler + +interface Optimization { + minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[]; +>minimizer : (WebpackPluginInstance | WebpackPluginFunction)[] | undefined +} +declare const A: ( +>A : (obj: T, prop: P, factory: () => T[P]) => void + + obj: T, +>obj : T + + prop: P, +>prop : P + + factory: () => T[P] +>factory : () => T[P] + +) => void; +export const applyOptimizationDefaults = (optimization: Optimization) => { +>applyOptimizationDefaults : (optimization: Optimization) => void +>(optimization: Optimization) => { A(optimization, "minimizer", () => [ { apply: (compiler) => {}, }, ]);} : (optimization: Optimization) => void +>optimization : Optimization + + A(optimization, "minimizer", () => [ +>A(optimization, "minimizer", () => [ { apply: (compiler) => {}, }, ]) : void +>A : (obj: T, prop: P, factory: () => T[P]) => void +>optimization : Optimization +>"minimizer" : "minimizer" +>() => [ { apply: (compiler) => {}, }, ] : () => { apply: (compiler: MyCompiler) => void; }[] +>[ { apply: (compiler) => {}, }, ] : { apply: (compiler: MyCompiler) => void; }[] + { +>{ apply: (compiler) => {}, } : { apply: (compiler: MyCompiler) => void; } + + apply: (compiler) => {}, +>apply : (compiler: MyCompiler) => void +>(compiler) => {} : (compiler: MyCompiler) => void +>compiler : MyCompiler + + }, + ]); +}; + diff --git a/tests/cases/compiler/contextualTypeCaching.ts b/tests/cases/compiler/contextualTypeCaching.ts index 542a98724e56a..d8b56d68914b1 100644 --- a/tests/cases/compiler/contextualTypeCaching.ts +++ b/tests/cases/compiler/contextualTypeCaching.ts @@ -23,3 +23,27 @@ emit('a', { nestedCallback: (r) => {}, }, }); + +// simplified repro from 52589#issuecomment-1416180638 +declare class MyCompiler { + compile(): void; +} +interface WebpackPluginInstance { + apply: (compiler: MyCompiler) => void; +} +type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void; +interface Optimization { + minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[]; +} +declare const A: ( + obj: T, + prop: P, + factory: () => T[P] +) => void; +export const applyOptimizationDefaults = (optimization: Optimization) => { + A(optimization, "minimizer", () => [ + { + apply: (compiler) => {}, + }, + ]); +}; From d56e1a92612080f2069c8371195bde9bcf3a6f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 11 Feb 2023 21:09:48 +0100 Subject: [PATCH 3/8] Cache `anyIterable` in `getContextualTypeForElementExpression` --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 86ce90ea724a7..82ffab9b14b79 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28838,9 +28838,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated // type of T. function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined { - const hasIterable = getGlobalIterableType(/* reportErrors */ false) !== emptyGenericType; + const anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType ? createIterableType(anyType) : undefined; return arrayContextualType && ( - getTypeOfPropertyOfContextualType(filterType(arrayContextualType, t => isArrayOrTupleLikeType(t) || !!getIndexTypeOfType(t, numberType) || hasIterable && isTypeAssignableTo(t, createIterableType(anyType))), "" + index as __String) + getTypeOfPropertyOfContextualType(filterType(arrayContextualType, t => !!getIndexTypeOfType(t, numberType) || (anyIterable ? isTypeAssignableTo(t, anyIterable) : isArrayOrTupleLikeType(t))), "" + index as __String) || mapType( arrayContextualType, t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false), From 0d5b9d50a5a13173a49d6429a2d18584427ed557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 11 Feb 2023 21:13:39 +0100 Subject: [PATCH 4/8] Cover both lib es5 and es2015 cases --- ...ntPrefersArrayUnionMemberLibEs2015.symbols | 27 ++++++++++++++++++ ...mentPrefersArrayUnionMemberLibEs2015.types | 28 +++++++++++++++++++ ...mentPrefersArrayUnionMemberLibEs5.symbols} | 16 +++++------ ...lementPrefersArrayUnionMemberLibEs5.types} | 2 +- ...ElementPrefersArrayUnionMemberLibEs2015.ts | 15 ++++++++++ ...ayElementPrefersArrayUnionMemberLibEs5.ts} | 1 + 6 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.symbols create mode 100644 tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.types rename tests/baselines/reference/{contextualSignatureInArrayElementPrefersArrayUnionMember.symbols => contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.symbols} (73%) rename tests/baselines/reference/{contextualSignatureInArrayElementPrefersArrayUnionMember.types => contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.types} (92%) create mode 100644 tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts rename tests/cases/compiler/{contextualSignatureInArrayElementPrefersArrayUnionMember.ts => contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts} (94%) diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.symbols b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.symbols new file mode 100644 index 0000000000000..b0ff34c16170b --- /dev/null +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts === +// repro from #52588 + +declare function test( +>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 0, 0)) + + arg: Record void> | Array<(arg: number) => void> +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 2, 22)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 3, 23)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 3, 54)) + +): void; + +test([ +>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 0, 0)) + + (arg) => { +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 7, 3)) + + arg; // number +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 7, 3)) + + }, +]); + diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.types b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.types new file mode 100644 index 0000000000000..c7c6d9c096f61 --- /dev/null +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.types @@ -0,0 +1,28 @@ +=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts === +// repro from #52588 + +declare function test( +>test : (arg: Record void> | ((arg: number) => void)[]) => void + + arg: Record void> | Array<(arg: number) => void> +>arg : Record void> | ((arg: number) => void)[] +>arg : string +>arg : number + +): void; + +test([ +>test([ (arg) => { arg; // number },]) : void +>test : (arg: Record void> | ((arg: number) => void)[]) => void +>[ (arg) => { arg; // number },] : ((arg: number) => void)[] + + (arg) => { +>(arg) => { arg; // number } : (arg: number) => void +>arg : number + + arg; // number +>arg : number + + }, +]); + diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.symbols b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.symbols similarity index 73% rename from tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.symbols rename to tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.symbols index 7a10411bfa84b..cb803d9186e96 100644 --- a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.symbols +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.symbols @@ -1,26 +1,26 @@ -=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts === +=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts === // repro from #52588 declare function test( ->test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 0, 0)) +>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 0, 0)) arg: Record void> | Array<(arg: number) => void> ->arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 2, 22)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 2, 22)) >Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 3, 23)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 3, 23)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 3, 54)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 3, 54)) ): void; test([ ->test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 0, 0)) +>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 0, 0)) (arg) => { ->arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 7, 3)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 7, 3)) arg; // number ->arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMember.ts, 7, 3)) +>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 7, 3)) }, ]); diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.types b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.types similarity index 92% rename from tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.types rename to tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.types index 46c74beb9459d..04c1ea69a2789 100644 --- a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMember.types +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.types @@ -1,4 +1,4 @@ -=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts === +=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts === // repro from #52588 declare function test( diff --git a/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts b/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts new file mode 100644 index 0000000000000..ff53d21e895ba --- /dev/null +++ b/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts @@ -0,0 +1,15 @@ +// @strict: true +// @noEmit: true +// @lib: es2015 + +// repro from #52588 + +declare function test( + arg: Record void> | Array<(arg: number) => void> +): void; + +test([ + (arg) => { + arg; // number + }, +]); diff --git a/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts b/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts similarity index 94% rename from tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts rename to tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts index 2af3c0735fcdd..340bd7690578c 100644 --- a/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMember.ts +++ b/tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts @@ -1,5 +1,6 @@ // @strict: true // @noEmit: true +// @lib: es5 // repro from #52588 From f0093bda45ca7ba1c5e2fdef3a61c26da75d93d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 11 Feb 2023 23:32:40 +0100 Subject: [PATCH 5/8] Introduce `isAssignableToAvailableAnyIterable` helper --- src/compiler/checker.ts | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 82ffab9b14b79..0ac1cd6a28ff4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19405,18 +19405,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } const moreThanOneRealChildren = length(validChildren) > 1; - let arrayLikeTargetParts: Type; - let nonArrayLikeTargetParts: Type; - const iterableType = getGlobalIterableType(/*reportErrors*/ false); - if (iterableType !== emptyGenericType) { - const anyIterable = createIterableType(anyType); - arrayLikeTargetParts = filterType(childrenTargetType, t => isTypeAssignableTo(t, anyIterable)); - nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isTypeAssignableTo(t, anyIterable)); - } - else { - arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType); - nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t)); - } + const arrayLikeTargetParts = filterType(childrenTargetType, isAssignableToAvailableAnyIterable); + const nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isAssignableToAvailableAnyIterable(t)); if (moreThanOneRealChildren) { if (arrayLikeTargetParts !== neverType) { const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal)); @@ -22922,6 +22912,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isArrayLikeType(type) || isTupleLikeType(type); } + function isAssignableToAvailableAnyIterable(type: Type): boolean { + const anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType ? createIterableType(anyType) : undefined; + return anyIterable ? isTypeAssignableTo(type, anyIterable) : isArrayOrTupleLikeType(type); + } + function getTupleElementType(type: Type, index: number) { const propType = getTypeOfPropertyOfType(type, "" + index as __String); if (propType) { @@ -28838,9 +28833,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated // type of T. function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined { - const anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType ? createIterableType(anyType) : undefined; return arrayContextualType && ( - getTypeOfPropertyOfContextualType(filterType(arrayContextualType, t => !!getIndexTypeOfType(t, numberType) || (anyIterable ? isTypeAssignableTo(t, anyIterable) : isArrayOrTupleLikeType(t))), "" + index as __String) + getTypeOfPropertyOfContextualType(filterType(arrayContextualType, t => !!getIndexTypeOfType(t, numberType) || isAssignableToAvailableAnyIterable(t)), "" + index as __String) || mapType( arrayContextualType, t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false), From 64ec07473d8f3ed048bbda25f6dad682ba1db174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 12 Feb 2023 00:11:55 +0100 Subject: [PATCH 6/8] Cache `anyIterable` creation --- src/compiler/checker.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0ac1cd6a28ff4..cb982ab2194db 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2056,6 +2056,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let anyArrayType: Type; let autoArrayType: Type; let anyReadonlyArrayType: Type; + let anyIterable: Type; let deferredGlobalNonNullableTypeAlias: Symbol; // The library files are only loaded when the feature is used. @@ -22913,8 +22914,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isAssignableToAvailableAnyIterable(type: Type): boolean { - const anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType ? createIterableType(anyType) : undefined; - return anyIterable ? isTypeAssignableTo(type, anyIterable) : isArrayOrTupleLikeType(type); + if (!anyIterable) { + anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType ? createIterableType(anyType) : emptyGenericType; + } + return anyIterable !== emptyGenericType ? isTypeAssignableTo(type, anyIterable) : isArrayOrTupleLikeType(type); } function getTupleElementType(type: Type, index: number) { From 52c423a9948494304d7747158cfeb7c122ddc55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 8 Mar 2023 23:30:23 +0100 Subject: [PATCH 7/8] use var instead of let --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 33eaf7df2e2fa..2f4e729004daa 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2078,7 +2078,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var anyArrayType: Type; var autoArrayType: Type; var anyReadonlyArrayType: Type; - let anyIterable: Type; + var anyIterable: Type; var deferredGlobalNonNullableTypeAlias: Symbol; // The library files are only loaded when the feature is used. From 85c03c5f7f47410044350903a68497784ccf4f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 9 Mar 2023 00:31:36 +0100 Subject: [PATCH 8/8] Drop anyIterable caching --- src/compiler/checker.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2f4e729004daa..480e4fa2e8563 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2078,7 +2078,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var anyArrayType: Type; var autoArrayType: Type; var anyReadonlyArrayType: Type; - var anyIterable: Type; var deferredGlobalNonNullableTypeAlias: Symbol; // The library files are only loaded when the feature is used. @@ -23067,10 +23066,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isAssignableToAvailableAnyIterable(type: Type): boolean { - if (!anyIterable) { - anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType ? createIterableType(anyType) : emptyGenericType; - } - return anyIterable !== emptyGenericType ? isTypeAssignableTo(type, anyIterable) : isArrayOrTupleLikeType(type); + const anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType && createIterableType(anyType); + return anyIterable ? isTypeAssignableTo(type, anyIterable) : isArrayOrTupleLikeType(type); } function getTupleElementType(type: Type, index: number) {