From f55167e5658f92061b767e4cee839833a022d327 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Wed, 22 Feb 2017 10:23:47 -0800 Subject: [PATCH 1/5] Collect type from return statment in generator function --- src/compiler/checker.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 12b55aa818b..56306fb772f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14963,10 +14963,12 @@ namespace ts { } } else { - let types: Type[]; + let yieldTypes: Type[]; + let returnTypes: Type[]; if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function - types = checkAndAggregateYieldOperandTypes(func, contextualMapper); - if (types.length === 0) { + yieldTypes = checkAndAggregateYieldOperandTypes(func, contextualMapper); + returnTypes = checkAndAggregateReturnExpressionTypes(func, contextualMapper); + if (yieldTypes.length === 0 && (!returnTypes || returnTypes.length === 0)) { const iterableIteratorAny = functionFlags & FunctionFlags.Async ? createAsyncIterableIteratorType(anyType) // AsyncGenerator function : createIterableIteratorType(anyType); // Generator function @@ -14978,14 +14980,14 @@ namespace ts { } } else { - types = checkAndAggregateReturnExpressionTypes(func, contextualMapper); - if (!types) { + returnTypes = checkAndAggregateReturnExpressionTypes(func, contextualMapper); + if (!returnTypes) { // For an async function, the return type will not be never, but rather a Promise for never. return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, neverType) // Async function : neverType; // Normal function } - if (types.length === 0) { + if (returnTypes.length === 0) { // For an async function, the return type will not be void, but rather a Promise for void. return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, voidType) // Async function @@ -14993,7 +14995,7 @@ namespace ts { } } // Return a union of the return expression types. - type = getUnionType(types, /*subtypeReduction*/ true); + type = getUnionType(yieldTypes ? yieldTypes.concat(returnTypes) : returnTypes, /*subtypeReduction*/ true); if (functionFlags & FunctionFlags.Generator) { // AsyncGenerator function or Generator function type = functionFlags & FunctionFlags.Async From 43cb2f56460de3d3883a2e8a39eb934de2d6c566 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Wed, 22 Feb 2017 10:24:00 -0800 Subject: [PATCH 2/5] Add tests --- .../yieldExpressions/generatorTypeCheck62.ts | 40 +++++++++++++++++ .../yieldExpressions/generatorTypeCheck63.ts | 43 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck62.ts create mode 100644 tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts diff --git a/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck62.ts b/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck62.ts new file mode 100644 index 00000000000..2f30fe9d902 --- /dev/null +++ b/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck62.ts @@ -0,0 +1,40 @@ +// @module: commonjs +// @target: es6 +// @noImplicitAny: true + +export interface StrategicState { + lastStrategyApplied?: string; +} + +export function strategy(stratName: string, gen: (a: T) => IterableIterator): (a: T) => IterableIterator { + return function*(state) { + for (const next of gen(state)) { + if (next) { + next.lastStrategyApplied = stratName; + } + yield next; + } + } +} + +export interface Strategy { + (a: T): IterableIterator; +} + +export interface State extends StrategicState { + foo: number; +} + +export const Nothing1: Strategy = strategy("Nothing", function*(state: State) { + return state; +}); + +export const Nothing2: Strategy = strategy("Nothing", function*(state: State) { + yield state; +}); + +export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { + yield ; + return state; +}); + \ No newline at end of file diff --git a/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts b/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts new file mode 100644 index 00000000000..58411e409b8 --- /dev/null +++ b/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts @@ -0,0 +1,43 @@ +// @module: commonjs +// @target: es6 +// @noImplicitAny: true + +export interface StrategicState { + lastStrategyApplied?: string; +} + +export function strategy(stratName: string, gen: (a: T) => IterableIterator): (a: T) => IterableIterator { + return function*(state) { + for (const next of gen(state)) { + if (next) { + next.lastStrategyApplied = stratName; + } + yield next; + } + } +} + +export interface Strategy { + (a: T): IterableIterator; +} + +export interface State extends StrategicState { + foo: number; +} + +export const Nothing: Strategy = strategy("Nothing", function* (state: State) { + yield 1; + return state; +}); + +export const Nothing1: Strategy = strategy("Nothing", function* (state: State) { +}); + +export const Nothing2: Strategy = strategy("Nothing", function* (state: State) { + return 1; +}); + +export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { + yield state; + return 1; +}); \ No newline at end of file From 5cc9414839351f673488a4d30181d312a7437d62 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Wed, 22 Feb 2017 10:24:24 -0800 Subject: [PATCH 3/5] Update baselines --- ....asyncGenerators.classMethods.es2015.types | 2 +- ...ter.asyncGenerators.classMethods.es5.types | 2 +- ....asyncGenerators.classMethods.esnext.types | 2 +- ...nerators.functionDeclarations.es2015.types | 2 +- ...cGenerators.functionDeclarations.es5.types | 2 +- ...nerators.functionDeclarations.esnext.types | 2 +- ...enerators.functionExpressions.es2015.types | 4 +- ...ncGenerators.functionExpressions.es5.types | 4 +- ...enerators.functionExpressions.esnext.types | 4 +- ...nerators.objectLiteralMethods.es2015.types | 6 +- ...cGenerators.objectLiteralMethods.es5.types | 6 +- ...nerators.objectLiteralMethods.esnext.types | 6 +- .../reference/generatorTypeCheck14.types | 2 +- .../reference/generatorTypeCheck15.types | 2 +- .../reference/generatorTypeCheck34.types | 2 +- .../reference/generatorTypeCheck62.js | 63 +++++++++ .../reference/generatorTypeCheck62.symbols | 106 +++++++++++++++ .../reference/generatorTypeCheck62.types | 122 ++++++++++++++++++ .../reference/generatorTypeCheck63.errors.txt | 63 +++++++++ .../reference/generatorTypeCheck63.js | 69 ++++++++++ 20 files changed, 447 insertions(+), 24 deletions(-) create mode 100644 tests/baselines/reference/generatorTypeCheck62.js create mode 100644 tests/baselines/reference/generatorTypeCheck62.symbols create mode 100644 tests/baselines/reference/generatorTypeCheck62.types create mode 100644 tests/baselines/reference/generatorTypeCheck63.errors.txt create mode 100644 tests/baselines/reference/generatorTypeCheck63.js diff --git a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.types b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.types index 524f7c9b71b..c375fb6f455 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.types +++ b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.types @@ -80,7 +80,7 @@ class C7 { >C7 : C7 async * f() { ->f : () => AsyncIterableIterator +>f : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.types b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.types index c20e0d35010..e4be9f80d4a 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.types +++ b/tests/baselines/reference/emitter.asyncGenerators.classMethods.es5.types @@ -80,7 +80,7 @@ class C7 { >C7 : C7 async * f() { ->f : () => AsyncIterableIterator +>f : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.classMethods.esnext.types b/tests/baselines/reference/emitter.asyncGenerators.classMethods.esnext.types index b5230006f1b..1232130a389 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.classMethods.esnext.types +++ b/tests/baselines/reference/emitter.asyncGenerators.classMethods.esnext.types @@ -80,7 +80,7 @@ class C7 { >C7 : C7 async * f() { ->f : () => AsyncIterableIterator +>f : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.types b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.types index 5d57519d140..0e434639906 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.types +++ b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.types @@ -53,7 +53,7 @@ async function * f6() { } === tests/cases/conformance/emitter/es2015/asyncGenerators/F7.ts === async function * f7() { ->f7 : () => AsyncIterableIterator +>f7 : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.types b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.types index 2c3063eca59..9ebd2659ef4 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.types +++ b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es5.types @@ -53,7 +53,7 @@ async function * f6() { } === tests/cases/conformance/emitter/es5/asyncGenerators/F7.ts === async function * f7() { ->f7 : () => AsyncIterableIterator +>f7 : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.esnext.types b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.esnext.types index 5eb09901ac8..4e61c903227 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.esnext.types +++ b/tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.esnext.types @@ -53,7 +53,7 @@ async function * f6() { } === tests/cases/conformance/emitter/esnext/asyncGenerators/F7.ts === async function * f7() { ->f7 : () => AsyncIterableIterator +>f7 : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.types b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.types index ab41ffd9c71..83d65ce5246 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.types +++ b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es2015.types @@ -59,8 +59,8 @@ const f6 = async function * () { } === tests/cases/conformance/emitter/es2015/asyncGenerators/F7.ts === const f7 = async function * () { ->f7 : () => AsyncIterableIterator ->async function * () { return 1;} : () => AsyncIterableIterator +>f7 : () => AsyncIterableIterator<1> +>async function * () { return 1;} : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.types b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.types index 424f09cf53b..7d736b2327c 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.types +++ b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.es5.types @@ -59,8 +59,8 @@ const f6 = async function * () { } === tests/cases/conformance/emitter/es5/asyncGenerators/F7.ts === const f7 = async function * () { ->f7 : () => AsyncIterableIterator ->async function * () { return 1;} : () => AsyncIterableIterator +>f7 : () => AsyncIterableIterator<1> +>async function * () { return 1;} : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.esnext.types b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.esnext.types index e4559e3ecef..6c40f9cebb1 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.esnext.types +++ b/tests/baselines/reference/emitter.asyncGenerators.functionExpressions.esnext.types @@ -59,8 +59,8 @@ const f6 = async function * () { } === tests/cases/conformance/emitter/esnext/asyncGenerators/F7.ts === const f7 = async function * () { ->f7 : () => AsyncIterableIterator ->async function * () { return 1;} : () => AsyncIterableIterator +>f7 : () => AsyncIterableIterator<1> +>async function * () { return 1;} : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.types b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.types index 0e89d9a1ca6..59c5bcfa167 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.types +++ b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es2015.types @@ -83,11 +83,11 @@ const o6 = { } === tests/cases/conformance/emitter/es2015/asyncGenerators/O7.ts === const o7 = { ->o7 : { f(): AsyncIterableIterator; } ->{ async * f() { return 1; }} : { f(): AsyncIterableIterator; } +>o7 : { f(): AsyncIterableIterator<1>; } +>{ async * f() { return 1; }} : { f(): AsyncIterableIterator<1>; } async * f() { ->f : () => AsyncIterableIterator +>f : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.types b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.types index 4c8ae47b6a2..3e7ead2f737 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.types +++ b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.es5.types @@ -83,11 +83,11 @@ const o6 = { } === tests/cases/conformance/emitter/es5/asyncGenerators/O7.ts === const o7 = { ->o7 : { f(): AsyncIterableIterator; } ->{ async * f() { return 1; }} : { f(): AsyncIterableIterator; } +>o7 : { f(): AsyncIterableIterator<1>; } +>{ async * f() { return 1; }} : { f(): AsyncIterableIterator<1>; } async * f() { ->f : () => AsyncIterableIterator +>f : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.esnext.types b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.esnext.types index 511cd7ec9e0..9e5aad8af23 100644 --- a/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.esnext.types +++ b/tests/baselines/reference/emitter.asyncGenerators.objectLiteralMethods.esnext.types @@ -83,11 +83,11 @@ const o6 = { } === tests/cases/conformance/emitter/esnext/asyncGenerators/O7.ts === const o7 = { ->o7 : { f(): AsyncIterableIterator; } ->{ async * f() { return 1; }} : { f(): AsyncIterableIterator; } +>o7 : { f(): AsyncIterableIterator<1>; } +>{ async * f() { return 1; }} : { f(): AsyncIterableIterator<1>; } async * f() { ->f : () => AsyncIterableIterator +>f : () => AsyncIterableIterator<1> return 1; >1 : 1 diff --git a/tests/baselines/reference/generatorTypeCheck14.types b/tests/baselines/reference/generatorTypeCheck14.types index 48565fe2be0..28401e68567 100644 --- a/tests/baselines/reference/generatorTypeCheck14.types +++ b/tests/baselines/reference/generatorTypeCheck14.types @@ -1,6 +1,6 @@ === tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck14.ts === function* g() { ->g : () => IterableIterator<0> +>g : () => IterableIterator<0 | ""> yield 0; >yield 0 : any diff --git a/tests/baselines/reference/generatorTypeCheck15.types b/tests/baselines/reference/generatorTypeCheck15.types index eb14208009a..3851d8e56a4 100644 --- a/tests/baselines/reference/generatorTypeCheck15.types +++ b/tests/baselines/reference/generatorTypeCheck15.types @@ -1,6 +1,6 @@ === tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck15.ts === function* g() { ->g : () => IterableIterator +>g : () => IterableIterator<""> return ""; >"" : "" diff --git a/tests/baselines/reference/generatorTypeCheck34.types b/tests/baselines/reference/generatorTypeCheck34.types index 2ca11177218..239c5ff1493 100644 --- a/tests/baselines/reference/generatorTypeCheck34.types +++ b/tests/baselines/reference/generatorTypeCheck34.types @@ -7,7 +7,7 @@ function* g() { >0 : 0 function* g2() { ->g2 : () => IterableIterator +>g2 : () => IterableIterator<""> return ""; >"" : "" diff --git a/tests/baselines/reference/generatorTypeCheck62.js b/tests/baselines/reference/generatorTypeCheck62.js new file mode 100644 index 00000000000..30864722210 --- /dev/null +++ b/tests/baselines/reference/generatorTypeCheck62.js @@ -0,0 +1,63 @@ +//// [generatorTypeCheck62.ts] + +export interface StrategicState { + lastStrategyApplied?: string; +} + +export function strategy(stratName: string, gen: (a: T) => IterableIterator): (a: T) => IterableIterator { + return function*(state) { + for (const next of gen(state)) { + if (next) { + next.lastStrategyApplied = stratName; + } + yield next; + } + } +} + +export interface Strategy { + (a: T): IterableIterator; +} + +export interface State extends StrategicState { + foo: number; +} + +export const Nothing1: Strategy = strategy("Nothing", function*(state: State) { + return state; +}); + +export const Nothing2: Strategy = strategy("Nothing", function*(state: State) { + yield state; +}); + +export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { + yield ; + return state; +}); + + +//// [generatorTypeCheck62.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function strategy(stratName, gen) { + return function* (state) { + for (const next of gen(state)) { + if (next) { + next.lastStrategyApplied = stratName; + } + yield next; + } + }; +} +exports.strategy = strategy; +exports.Nothing1 = strategy("Nothing", function* (state) { + return state; +}); +exports.Nothing2 = strategy("Nothing", function* (state) { + yield state; +}); +exports.Nothing3 = strategy("Nothing", function* (state) { + yield; + return state; +}); diff --git a/tests/baselines/reference/generatorTypeCheck62.symbols b/tests/baselines/reference/generatorTypeCheck62.symbols new file mode 100644 index 00000000000..580ab208840 --- /dev/null +++ b/tests/baselines/reference/generatorTypeCheck62.symbols @@ -0,0 +1,106 @@ +=== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck62.ts === + +export interface StrategicState { +>StrategicState : Symbol(StrategicState, Decl(generatorTypeCheck62.ts, 0, 0)) + + lastStrategyApplied?: string; +>lastStrategyApplied : Symbol(StrategicState.lastStrategyApplied, Decl(generatorTypeCheck62.ts, 1, 33)) +} + +export function strategy(stratName: string, gen: (a: T) => IterableIterator): (a: T) => IterableIterator { +>strategy : Symbol(strategy, Decl(generatorTypeCheck62.ts, 3, 1)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 5, 25)) +>StrategicState : Symbol(StrategicState, Decl(generatorTypeCheck62.ts, 0, 0)) +>stratName : Symbol(stratName, Decl(generatorTypeCheck62.ts, 5, 51)) +>gen : Symbol(gen, Decl(generatorTypeCheck62.ts, 5, 69)) +>a : Symbol(a, Decl(generatorTypeCheck62.ts, 5, 76)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 5, 25)) +>IterableIterator : Symbol(IterableIterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 5, 25)) +>a : Symbol(a, Decl(generatorTypeCheck62.ts, 5, 120)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 5, 25)) +>IterableIterator : Symbol(IterableIterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 5, 25)) + + return function*(state) { +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 6, 21)) + + for (const next of gen(state)) { +>next : Symbol(next, Decl(generatorTypeCheck62.ts, 7, 18)) +>gen : Symbol(gen, Decl(generatorTypeCheck62.ts, 5, 69)) +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 6, 21)) + + if (next) { +>next : Symbol(next, Decl(generatorTypeCheck62.ts, 7, 18)) + + next.lastStrategyApplied = stratName; +>next.lastStrategyApplied : Symbol(StrategicState.lastStrategyApplied, Decl(generatorTypeCheck62.ts, 1, 33)) +>next : Symbol(next, Decl(generatorTypeCheck62.ts, 7, 18)) +>lastStrategyApplied : Symbol(StrategicState.lastStrategyApplied, Decl(generatorTypeCheck62.ts, 1, 33)) +>stratName : Symbol(stratName, Decl(generatorTypeCheck62.ts, 5, 51)) + } + yield next; +>next : Symbol(next, Decl(generatorTypeCheck62.ts, 7, 18)) + } + } +} + +export interface Strategy { +>Strategy : Symbol(Strategy, Decl(generatorTypeCheck62.ts, 14, 1)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 16, 26)) + + (a: T): IterableIterator; +>a : Symbol(a, Decl(generatorTypeCheck62.ts, 17, 5)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 16, 26)) +>IterableIterator : Symbol(IterableIterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>T : Symbol(T, Decl(generatorTypeCheck62.ts, 16, 26)) +} + +export interface State extends StrategicState { +>State : Symbol(State, Decl(generatorTypeCheck62.ts, 18, 1)) +>StrategicState : Symbol(StrategicState, Decl(generatorTypeCheck62.ts, 0, 0)) + + foo: number; +>foo : Symbol(State.foo, Decl(generatorTypeCheck62.ts, 20, 47)) +} + +export const Nothing1: Strategy = strategy("Nothing", function*(state: State) { +>Nothing1 : Symbol(Nothing1, Decl(generatorTypeCheck62.ts, 24, 12)) +>Strategy : Symbol(Strategy, Decl(generatorTypeCheck62.ts, 14, 1)) +>State : Symbol(State, Decl(generatorTypeCheck62.ts, 18, 1)) +>strategy : Symbol(strategy, Decl(generatorTypeCheck62.ts, 3, 1)) +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 24, 71)) +>State : Symbol(State, Decl(generatorTypeCheck62.ts, 18, 1)) + + return state; +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 24, 71)) + +}); + +export const Nothing2: Strategy = strategy("Nothing", function*(state: State) { +>Nothing2 : Symbol(Nothing2, Decl(generatorTypeCheck62.ts, 28, 12)) +>Strategy : Symbol(Strategy, Decl(generatorTypeCheck62.ts, 14, 1)) +>State : Symbol(State, Decl(generatorTypeCheck62.ts, 18, 1)) +>strategy : Symbol(strategy, Decl(generatorTypeCheck62.ts, 3, 1)) +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 28, 71)) +>State : Symbol(State, Decl(generatorTypeCheck62.ts, 18, 1)) + + yield state; +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 28, 71)) + +}); + +export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { +>Nothing3 : Symbol(Nothing3, Decl(generatorTypeCheck62.ts, 32, 12)) +>Strategy : Symbol(Strategy, Decl(generatorTypeCheck62.ts, 14, 1)) +>State : Symbol(State, Decl(generatorTypeCheck62.ts, 18, 1)) +>strategy : Symbol(strategy, Decl(generatorTypeCheck62.ts, 3, 1)) +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 32, 72)) +>State : Symbol(State, Decl(generatorTypeCheck62.ts, 18, 1)) + + yield ; + return state; +>state : Symbol(state, Decl(generatorTypeCheck62.ts, 32, 72)) + +}); + diff --git a/tests/baselines/reference/generatorTypeCheck62.types b/tests/baselines/reference/generatorTypeCheck62.types new file mode 100644 index 00000000000..289d33dc7d4 --- /dev/null +++ b/tests/baselines/reference/generatorTypeCheck62.types @@ -0,0 +1,122 @@ +=== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck62.ts === + +export interface StrategicState { +>StrategicState : StrategicState + + lastStrategyApplied?: string; +>lastStrategyApplied : string +} + +export function strategy(stratName: string, gen: (a: T) => IterableIterator): (a: T) => IterableIterator { +>strategy : (stratName: string, gen: (a: T) => IterableIterator) => (a: T) => IterableIterator +>T : T +>StrategicState : StrategicState +>stratName : string +>gen : (a: T) => IterableIterator +>a : T +>T : T +>IterableIterator : IterableIterator +>T : T +>a : T +>T : T +>IterableIterator : IterableIterator +>T : T + + return function*(state) { +>function*(state) { for (const next of gen(state)) { if (next) { next.lastStrategyApplied = stratName; } yield next; } } : (state: T) => IterableIterator +>state : T + + for (const next of gen(state)) { +>next : T +>gen(state) : IterableIterator +>gen : (a: T) => IterableIterator +>state : T + + if (next) { +>next : T + + next.lastStrategyApplied = stratName; +>next.lastStrategyApplied = stratName : string +>next.lastStrategyApplied : string +>next : T +>lastStrategyApplied : string +>stratName : string + } + yield next; +>yield next : any +>next : T + } + } +} + +export interface Strategy { +>Strategy : Strategy +>T : T + + (a: T): IterableIterator; +>a : T +>T : T +>IterableIterator : IterableIterator +>T : T +} + +export interface State extends StrategicState { +>State : State +>StrategicState : StrategicState + + foo: number; +>foo : number +} + +export const Nothing1: Strategy = strategy("Nothing", function*(state: State) { +>Nothing1 : Strategy +>Strategy : Strategy +>State : State +>strategy("Nothing", function*(state: State) { return state;}) : (a: State) => IterableIterator +>strategy : (stratName: string, gen: (a: T) => IterableIterator) => (a: T) => IterableIterator +>"Nothing" : "Nothing" +>function*(state: State) { return state;} : (state: State) => IterableIterator +>state : State +>State : State + + return state; +>state : State + +}); + +export const Nothing2: Strategy = strategy("Nothing", function*(state: State) { +>Nothing2 : Strategy +>Strategy : Strategy +>State : State +>strategy("Nothing", function*(state: State) { yield state;}) : (a: State) => IterableIterator +>strategy : (stratName: string, gen: (a: T) => IterableIterator) => (a: T) => IterableIterator +>"Nothing" : "Nothing" +>function*(state: State) { yield state;} : (state: State) => IterableIterator +>state : State +>State : State + + yield state; +>yield state : any +>state : State + +}); + +export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { +>Nothing3 : Strategy +>Strategy : Strategy +>State : State +>strategy("Nothing", function* (state: State) { yield ; return state;}) : (a: State) => IterableIterator +>strategy : (stratName: string, gen: (a: T) => IterableIterator) => (a: T) => IterableIterator +>"Nothing" : "Nothing" +>function* (state: State) { yield ; return state;} : (state: State) => IterableIterator +>state : State +>State : State + + yield ; +>yield : any + + return state; +>state : State + +}); + diff --git a/tests/baselines/reference/generatorTypeCheck63.errors.txt b/tests/baselines/reference/generatorTypeCheck63.errors.txt new file mode 100644 index 00000000000..46e722a0dd1 --- /dev/null +++ b/tests/baselines/reference/generatorTypeCheck63.errors.txt @@ -0,0 +1,63 @@ +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(25,14): error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. + Type 'IterableIterator' is not assignable to type 'IterableIterator'. + Type 'State | 1' is not assignable to type 'State'. + Type '1' is not assignable to type 'State'. +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(30,70): error TS7025: Generator implicitly has type 'IterableIterator' because it does not yield any values. Consider supplying a return type. +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(33,42): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. + Type argument candidate 'State' is not a valid type argument because it is not a supertype of candidate '1'. +tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(37,14): error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. + + +==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts (4 errors) ==== + + export interface StrategicState { + lastStrategyApplied?: string; + } + + export function strategy(stratName: string, gen: (a: T) => IterableIterator): (a: T) => IterableIterator { + return function*(state) { + for (const next of gen(state)) { + if (next) { + next.lastStrategyApplied = stratName; + } + yield next; + } + } + } + + export interface Strategy { + (a: T): IterableIterator; + } + + export interface State extends StrategicState { + foo: number; + } + + export const Nothing: Strategy = strategy("Nothing", function* (state: State) { + ~~~~~~~ +!!! error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. +!!! error TS2322: Type 'IterableIterator' is not assignable to type 'IterableIterator'. +!!! error TS2322: Type 'State | 1' is not assignable to type 'State'. +!!! error TS2322: Type '1' is not assignable to type 'State'. + yield 1; + return state; + }); + + export const Nothing1: Strategy = strategy("Nothing", function* (state: State) { + ~ +!!! error TS7025: Generator implicitly has type 'IterableIterator' because it does not yield any values. Consider supplying a return type. + }); + + export const Nothing2: Strategy = strategy("Nothing", function* (state: State) { + ~~~~~~~~ +!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. +!!! error TS2453: Type argument candidate 'State' is not a valid type argument because it is not a supertype of candidate '1'. + return 1; + }); + + export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { + ~~~~~~~~ +!!! error TS2322: Type '(a: State | 1) => IterableIterator' is not assignable to type 'Strategy'. + yield state; + return 1; + }); \ No newline at end of file diff --git a/tests/baselines/reference/generatorTypeCheck63.js b/tests/baselines/reference/generatorTypeCheck63.js new file mode 100644 index 00000000000..92cf2f867fc --- /dev/null +++ b/tests/baselines/reference/generatorTypeCheck63.js @@ -0,0 +1,69 @@ +//// [generatorTypeCheck63.ts] + +export interface StrategicState { + lastStrategyApplied?: string; +} + +export function strategy(stratName: string, gen: (a: T) => IterableIterator): (a: T) => IterableIterator { + return function*(state) { + for (const next of gen(state)) { + if (next) { + next.lastStrategyApplied = stratName; + } + yield next; + } + } +} + +export interface Strategy { + (a: T): IterableIterator; +} + +export interface State extends StrategicState { + foo: number; +} + +export const Nothing: Strategy = strategy("Nothing", function* (state: State) { + yield 1; + return state; +}); + +export const Nothing1: Strategy = strategy("Nothing", function* (state: State) { +}); + +export const Nothing2: Strategy = strategy("Nothing", function* (state: State) { + return 1; +}); + +export const Nothing3: Strategy = strategy("Nothing", function* (state: State) { + yield state; + return 1; +}); + +//// [generatorTypeCheck63.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function strategy(stratName, gen) { + return function* (state) { + for (const next of gen(state)) { + if (next) { + next.lastStrategyApplied = stratName; + } + yield next; + } + }; +} +exports.strategy = strategy; +exports.Nothing = strategy("Nothing", function* (state) { + yield 1; + return state; +}); +exports.Nothing1 = strategy("Nothing", function* (state) { +}); +exports.Nothing2 = strategy("Nothing", function* (state) { + return 1; +}); +exports.Nothing3 = strategy("Nothing", function* (state) { + yield state; + return 1; +}); From bb5b20b587d89a01d2e4a3bb8235205553006e38 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 21 Mar 2017 08:07:11 -0700 Subject: [PATCH 4/5] Address code review --- src/compiler/checker.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 56306fb772f..56b3a0704b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14964,11 +14964,10 @@ namespace ts { } else { let yieldTypes: Type[]; - let returnTypes: Type[]; + let types: Type[]; if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function - yieldTypes = checkAndAggregateYieldOperandTypes(func, contextualMapper); - returnTypes = checkAndAggregateReturnExpressionTypes(func, contextualMapper); - if (yieldTypes.length === 0 && (!returnTypes || returnTypes.length === 0)) { + types = concatenate(checkAndAggregateYieldOperandTypes(func, contextualMapper), checkAndAggregateReturnExpressionTypes(func, contextualMapper)); + if (!types || types.length === 0) { const iterableIteratorAny = functionFlags & FunctionFlags.Async ? createAsyncIterableIteratorType(anyType) // AsyncGenerator function : createIterableIteratorType(anyType); // Generator function @@ -14980,14 +14979,14 @@ namespace ts { } } else { - returnTypes = checkAndAggregateReturnExpressionTypes(func, contextualMapper); - if (!returnTypes) { + types = checkAndAggregateReturnExpressionTypes(func, contextualMapper); + if (!types) { // For an async function, the return type will not be never, but rather a Promise for never. return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, neverType) // Async function : neverType; // Normal function } - if (returnTypes.length === 0) { + if (types.length === 0) { // For an async function, the return type will not be void, but rather a Promise for void. return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, voidType) // Async function @@ -14995,7 +14994,7 @@ namespace ts { } } // Return a union of the return expression types. - type = getUnionType(yieldTypes ? yieldTypes.concat(returnTypes) : returnTypes, /*subtypeReduction*/ true); + type = getUnionType(yieldTypes ? yieldTypes.concat(types) : types, /*subtypeReduction*/ true); if (functionFlags & FunctionFlags.Generator) { // AsyncGenerator function or Generator function type = functionFlags & FunctionFlags.Async From 71e52dea923670fac1b8373ec041009bd0cc95ba Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 21 Mar 2017 08:38:01 -0700 Subject: [PATCH 5/5] finish remove unused yieldTypes --- 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 f550fcf9c35..43311c81f7b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15138,7 +15138,7 @@ namespace ts { } } // Return a union of the return expression types. - type = getUnionType(yieldTypes ? yieldTypes.concat(types) : types, /*subtypeReduction*/ true); + type = getUnionType(types, /*subtypeReduction*/ true); if (functionFlags & FunctionFlags.Generator) { // AsyncGenerator function or Generator function type = functionFlags & FunctionFlags.Async