From 7119e2b74fc66b9af2a712cafb33a9129682b8b4 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 30 Jul 2020 11:37:04 -0700 Subject: [PATCH] The iteration type of overloaded iterator signatures derives from the intersection of their return types (#39722) --- src/compiler/checker.ts | 4 +-- tests/baselines/reference/for-of58.js | 17 +++++++++++ tests/baselines/reference/for-of58.symbols | 29 +++++++++++++++++++ tests/baselines/reference/for-of58.types | 27 +++++++++++++++++ .../es6/for-ofStatements/for-of58.ts | 10 +++++++ 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/for-of58.js create mode 100644 tests/baselines/reference/for-of58.symbols create mode 100644 tests/baselines/reference/for-of58.types create mode 100644 tests/cases/conformance/es6/for-ofStatements/for-of58.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b4f67eb27b8..fb32f9b4824 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33624,7 +33624,7 @@ namespace ts { return setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes); } - const iteratorType = getUnionType(map(signatures, getReturnTypeOfSignature), UnionReduction.Subtype); + const iteratorType = getIntersectionType(map(signatures, getReturnTypeOfSignature)); const iterationTypes = getIterationTypesOfIterator(iteratorType, resolver, errorNode) ?? noIterationTypes; return setCachedIterationTypes(type, resolver.iterableCacheKey, iterationTypes); } @@ -33830,7 +33830,7 @@ namespace ts { // Resolve the *yield* and *return* types from the return type of the method (i.e. `IteratorResult`) let yieldType: Type; - const methodReturnType = methodReturnTypes ? getUnionType(methodReturnTypes, UnionReduction.Subtype) : neverType; + const methodReturnType = methodReturnTypes ? getIntersectionType(methodReturnTypes) : neverType; const resolvedMethodReturnType = resolver.resolveIterationType(methodReturnType, errorNode) || anyType; const iterationTypes = getIterationTypesOfIteratorResult(resolvedMethodReturnType); if (iterationTypes === noIterationTypes) { diff --git a/tests/baselines/reference/for-of58.js b/tests/baselines/reference/for-of58.js new file mode 100644 index 00000000000..133485b2196 --- /dev/null +++ b/tests/baselines/reference/for-of58.js @@ -0,0 +1,17 @@ +//// [for-of58.ts] +type X = { x: 'x' }; +type Y = { y: 'y' }; + +declare const arr: X[] & Y[]; + +for (const item of arr) { + item.x; + item.y; +} + + +//// [for-of58.js] +for (const item of arr) { + item.x; + item.y; +} diff --git a/tests/baselines/reference/for-of58.symbols b/tests/baselines/reference/for-of58.symbols new file mode 100644 index 00000000000..5013b3264dc --- /dev/null +++ b/tests/baselines/reference/for-of58.symbols @@ -0,0 +1,29 @@ +=== tests/cases/conformance/es6/for-ofStatements/for-of58.ts === +type X = { x: 'x' }; +>X : Symbol(X, Decl(for-of58.ts, 0, 0)) +>x : Symbol(x, Decl(for-of58.ts, 0, 10)) + +type Y = { y: 'y' }; +>Y : Symbol(Y, Decl(for-of58.ts, 0, 20)) +>y : Symbol(y, Decl(for-of58.ts, 1, 10)) + +declare const arr: X[] & Y[]; +>arr : Symbol(arr, Decl(for-of58.ts, 3, 13)) +>X : Symbol(X, Decl(for-of58.ts, 0, 0)) +>Y : Symbol(Y, Decl(for-of58.ts, 0, 20)) + +for (const item of arr) { +>item : Symbol(item, Decl(for-of58.ts, 5, 10)) +>arr : Symbol(arr, Decl(for-of58.ts, 3, 13)) + + item.x; +>item.x : Symbol(x, Decl(for-of58.ts, 0, 10)) +>item : Symbol(item, Decl(for-of58.ts, 5, 10)) +>x : Symbol(x, Decl(for-of58.ts, 0, 10)) + + item.y; +>item.y : Symbol(y, Decl(for-of58.ts, 1, 10)) +>item : Symbol(item, Decl(for-of58.ts, 5, 10)) +>y : Symbol(y, Decl(for-of58.ts, 1, 10)) +} + diff --git a/tests/baselines/reference/for-of58.types b/tests/baselines/reference/for-of58.types new file mode 100644 index 00000000000..f188378dfce --- /dev/null +++ b/tests/baselines/reference/for-of58.types @@ -0,0 +1,27 @@ +=== tests/cases/conformance/es6/for-ofStatements/for-of58.ts === +type X = { x: 'x' }; +>X : X +>x : "x" + +type Y = { y: 'y' }; +>Y : Y +>y : "y" + +declare const arr: X[] & Y[]; +>arr : X[] & Y[] + +for (const item of arr) { +>item : X & Y +>arr : X[] & Y[] + + item.x; +>item.x : "x" +>item : X & Y +>x : "x" + + item.y; +>item.y : "y" +>item : X & Y +>y : "y" +} + diff --git a/tests/cases/conformance/es6/for-ofStatements/for-of58.ts b/tests/cases/conformance/es6/for-ofStatements/for-of58.ts new file mode 100644 index 00000000000..eaebbcebacf --- /dev/null +++ b/tests/cases/conformance/es6/for-ofStatements/for-of58.ts @@ -0,0 +1,10 @@ +// @target: es6 +type X = { x: 'x' }; +type Y = { y: 'y' }; + +declare const arr: X[] & Y[]; + +for (const item of arr) { + item.x; + item.y; +}