From 735a67a05ea2b5844f7b0210af1df3e7ada71155 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 17 Sep 2020 10:42:47 -0700 Subject: [PATCH] Fix iterable contextual type (#40592) --- src/compiler/checker.ts | 5 ++- .../reference/contextualTypeIterableUnions.js | 17 ++++++++ .../contextualTypeIterableUnions.symbols | 33 +++++++++++++++ .../contextualTypeIterableUnions.types | 40 +++++++++++++++++++ .../compiler/contextualTypeIterableUnions.ts | 11 +++++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/contextualTypeIterableUnions.js create mode 100644 tests/baselines/reference/contextualTypeIterableUnions.symbols create mode 100644 tests/baselines/reference/contextualTypeIterableUnions.types create mode 100644 tests/cases/compiler/contextualTypeIterableUnions.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ccba60fe42d..c5ffd98f9ae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23651,7 +23651,10 @@ namespace ts { function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined { return arrayContextualType && ( getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) - || getIteratedTypeOrElementType(IterationUse.Element, arrayContextualType, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false)); + || mapType( + arrayContextualType, + t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false), + /*noReductions*/ true)); } // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. diff --git a/tests/baselines/reference/contextualTypeIterableUnions.js b/tests/baselines/reference/contextualTypeIterableUnions.js new file mode 100644 index 00000000000..d1bb4e9d8a8 --- /dev/null +++ b/tests/baselines/reference/contextualTypeIterableUnions.js @@ -0,0 +1,17 @@ +//// [contextualTypeIterableUnions.ts] +declare class DMap { + constructor(iterable: Iterable<[K, V]> | undefined); +} +new DMap([["1", 2]]); + +const i1: Iterable<{ a: true }> | undefined = [{ a: true }]; +const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }]; +const i3: Iterable | 1[] = [2]; + + +//// [contextualTypeIterableUnions.js] +"use strict"; +new DMap([["1", 2]]); +const i1 = [{ a: true }]; +const i2 = [{ b: false }]; +const i3 = [2]; diff --git a/tests/baselines/reference/contextualTypeIterableUnions.symbols b/tests/baselines/reference/contextualTypeIterableUnions.symbols new file mode 100644 index 00000000000..0ae7379596e --- /dev/null +++ b/tests/baselines/reference/contextualTypeIterableUnions.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/contextualTypeIterableUnions.ts === +declare class DMap { +>DMap : Symbol(DMap, Decl(contextualTypeIterableUnions.ts, 0, 0)) +>K : Symbol(K, Decl(contextualTypeIterableUnions.ts, 0, 19)) +>V : Symbol(V, Decl(contextualTypeIterableUnions.ts, 0, 21)) + + constructor(iterable: Iterable<[K, V]> | undefined); +>iterable : Symbol(iterable, Decl(contextualTypeIterableUnions.ts, 1, 14)) +>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) +>K : Symbol(K, Decl(contextualTypeIterableUnions.ts, 0, 19)) +>V : Symbol(V, Decl(contextualTypeIterableUnions.ts, 0, 21)) +} +new DMap([["1", 2]]); +>DMap : Symbol(DMap, Decl(contextualTypeIterableUnions.ts, 0, 0)) + +const i1: Iterable<{ a: true }> | undefined = [{ a: true }]; +>i1 : Symbol(i1, Decl(contextualTypeIterableUnions.ts, 5, 5)) +>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(contextualTypeIterableUnions.ts, 5, 20)) +>a : Symbol(a, Decl(contextualTypeIterableUnions.ts, 5, 48)) + +const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }]; +>i2 : Symbol(i2, Decl(contextualTypeIterableUnions.ts, 6, 5)) +>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(contextualTypeIterableUnions.ts, 6, 20)) +>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) +>b : Symbol(b, Decl(contextualTypeIterableUnions.ts, 6, 44)) +>b : Symbol(b, Decl(contextualTypeIterableUnions.ts, 6, 61)) + +const i3: Iterable | 1[] = [2]; +>i3 : Symbol(i3, Decl(contextualTypeIterableUnions.ts, 7, 5)) +>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) + diff --git a/tests/baselines/reference/contextualTypeIterableUnions.types b/tests/baselines/reference/contextualTypeIterableUnions.types new file mode 100644 index 00000000000..455b4d55733 --- /dev/null +++ b/tests/baselines/reference/contextualTypeIterableUnions.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/contextualTypeIterableUnions.ts === +declare class DMap { +>DMap : DMap + + constructor(iterable: Iterable<[K, V]> | undefined); +>iterable : Iterable<[K, V]> | undefined +} +new DMap([["1", 2]]); +>new DMap([["1", 2]]) : DMap +>DMap : typeof DMap +>[["1", 2]] : [string, number][] +>["1", 2] : [string, number] +>"1" : "1" +>2 : 2 + +const i1: Iterable<{ a: true }> | undefined = [{ a: true }]; +>i1 : Iterable<{ a: true; }> | undefined +>a : true +>true : true +>[{ a: true }] : { a: true; }[] +>{ a: true } : { a: true; } +>a : true +>true : true + +const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }]; +>i2 : Iterable<{ a: true; }> | Iterable<{ b: false; }> +>a : true +>true : true +>b : false +>false : false +>[{ b: false }] : { b: false; }[] +>{ b: false } : { b: false; } +>b : false +>false : false + +const i3: Iterable | 1[] = [2]; +>i3 : Iterable | 1[] +>[2] : 2[] +>2 : 2 + diff --git a/tests/cases/compiler/contextualTypeIterableUnions.ts b/tests/cases/compiler/contextualTypeIterableUnions.ts new file mode 100644 index 00000000000..2ab1857f391 --- /dev/null +++ b/tests/cases/compiler/contextualTypeIterableUnions.ts @@ -0,0 +1,11 @@ +// @strict: true +// @target: esnext + +declare class DMap { + constructor(iterable: Iterable<[K, V]> | undefined); +} +new DMap([["1", 2]]); + +const i1: Iterable<{ a: true }> | undefined = [{ a: true }]; +const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }]; +const i3: Iterable | 1[] = [2];