Skip to content

Commit 624d1ca

Browse files
authored
Fix inferred TNext of generator to use TNext of contextual return type (microsoft#32719)
1 parent e3f4979 commit 624d1ca

13 files changed

+91
-82
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18815,6 +18815,17 @@ namespace ts {
1881518815
return false;
1881618816
}
1881718817

18818+
function getContextualIterationType(kind: IterationTypeKind, functionDecl: SignatureDeclaration): Type | undefined {
18819+
const isAsync = !!(getFunctionFlags(functionDecl) & FunctionFlags.Async);
18820+
const contextualReturnType = getContextualReturnType(functionDecl);
18821+
if (contextualReturnType) {
18822+
return getIterationTypeOfGeneratorFunctionReturnType(kind, contextualReturnType, isAsync)
18823+
|| undefined;
18824+
}
18825+
18826+
return undefined;
18827+
}
18828+
1881818829
function getContextualReturnType(functionDecl: SignatureDeclaration): Type | undefined {
1881918830
// If the containing function has a return type annotation, is a constructor, or is a get accessor whose
1882018831
// corresponding set accessor has a type annotation, return statements in the function are contextually typed
@@ -23480,7 +23491,11 @@ namespace ts {
2348023491
}
2348123492

2348223493
if (isGenerator) {
23483-
return createGeneratorReturnType(yieldType || neverType, returnType || fallbackReturnType, nextType || unknownType, isAsync);
23494+
return createGeneratorReturnType(
23495+
yieldType || neverType,
23496+
returnType || fallbackReturnType,
23497+
nextType || getContextualIterationType(IterationTypeKind.Next, func) || unknownType,
23498+
isAsync);
2348423499
}
2348523500
else {
2348623501
// From within an async function you can return either a non-promise value or a promise. Any
@@ -24841,13 +24856,7 @@ namespace ts {
2484124856
|| anyType;
2484224857
}
2484324858

24844-
const contextualReturnType = getContextualReturnType(func);
24845-
if (contextualReturnType) {
24846-
return getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, contextualReturnType, isAsync)
24847-
|| anyType;
24848-
}
24849-
24850-
return anyType;
24859+
return getContextualIterationType(IterationTypeKind.Next, func) || anyType;
2485124860
}
2485224861

2485324862
function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {

tests/baselines/reference/generatorTypeCheck28.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ function* g(): IterableIterator<(x: string) => number> {
55

66
yield * {
77
>yield * { *[Symbol.iterator]() { yield x => x.length; } } : void
8-
>{ *[Symbol.iterator]() { yield x => x.length; } } : { [Symbol.iterator](): Generator<(x: string) => number, void, unknown>; }
8+
>{ *[Symbol.iterator]() { yield x => x.length; } } : { [Symbol.iterator](): Generator<(x: string) => number, void, undefined>; }
99

1010
*[Symbol.iterator]() {
11-
>[Symbol.iterator] : () => Generator<(x: string) => number, void, unknown>
11+
>[Symbol.iterator] : () => Generator<(x: string) => number, void, undefined>
1212
>Symbol.iterator : symbol
1313
>Symbol : SymbolConstructor
1414
>iterator : symbol

tests/baselines/reference/generatorTypeCheck45.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ foo("", function* () { yield x => x.length }, p => undefined); // T is fixed, sh
1111
>foo("", function* () { yield x => x.length }, p => undefined) : string
1212
>foo : <T, U>(x: T, fun: () => Iterator<(x: T) => U, any, undefined>, fun2: (y: U) => T) => T
1313
>"" : ""
14-
>function* () { yield x => x.length } : () => Generator<(x: string) => number, void, unknown>
14+
>function* () { yield x => x.length } : () => Generator<(x: string) => number, void, undefined>
1515
>yield x => x.length : undefined
1616
>x => x.length : (x: string) => number
1717
>x : string

tests/baselines/reference/generatorTypeCheck46.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ foo("", function* () {
1111
>foo("", function* () { yield* { *[Symbol.iterator]() { yield x => x.length } }}, p => undefined) : string
1212
>foo : <T, U>(x: T, fun: () => Iterable<(x: T) => U>, fun2: (y: U) => T) => T
1313
>"" : ""
14-
>function* () { yield* { *[Symbol.iterator]() { yield x => x.length } }} : () => Generator<(x: string) => number, void, unknown>
14+
>function* () { yield* { *[Symbol.iterator]() { yield x => x.length } }} : () => Generator<(x: string) => number, void, undefined>
1515

1616
yield* {
1717
>yield* { *[Symbol.iterator]() { yield x => x.length } } : void
18-
>{ *[Symbol.iterator]() { yield x => x.length } } : { [Symbol.iterator](): Generator<(x: string) => number, void, unknown>; }
18+
>{ *[Symbol.iterator]() { yield x => x.length } } : { [Symbol.iterator](): Generator<(x: string) => number, void, undefined>; }
1919

2020
*[Symbol.iterator]() {
21-
>[Symbol.iterator] : () => Generator<(x: string) => number, void, unknown>
21+
>[Symbol.iterator] : () => Generator<(x: string) => number, void, undefined>
2222
>Symbol.iterator : symbol
2323
>Symbol : SymbolConstructor
2424
>iterator : symbol

tests/baselines/reference/generatorTypeCheck62.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function strategy<T extends StrategicState>(stratName: string, gen: (a: T
1212
>a : T
1313

1414
return function*(state) {
15-
>function*(state) { for (const next of gen(state)) { if (next) { next.lastStrategyApplied = stratName; } yield next; } } : (state: T) => Generator<T, void, unknown>
15+
>function*(state) { for (const next of gen(state)) { if (next) { next.lastStrategyApplied = stratName; } yield next; } } : (state: T) => Generator<T, void, undefined>
1616
>state : T
1717

1818
for (const next of gen(state)) {
@@ -53,7 +53,7 @@ export const Nothing1: Strategy<State> = strategy("Nothing", function*(state: St
5353
>strategy("Nothing", function*(state: State) { return state;}) : (a: State) => IterableIterator<State>
5454
>strategy : <T extends StrategicState>(stratName: string, gen: (a: T) => IterableIterator<T>) => (a: T) => IterableIterator<T>
5555
>"Nothing" : "Nothing"
56-
>function*(state: State) { return state;} : (state: State) => Generator<never, State, unknown>
56+
>function*(state: State) { return state;} : (state: State) => Generator<never, State, undefined>
5757
>state : State
5858

5959
return state;
@@ -66,7 +66,7 @@ export const Nothing2: Strategy<State> = strategy("Nothing", function*(state: St
6666
>strategy("Nothing", function*(state: State) { yield state;}) : (a: State) => IterableIterator<State>
6767
>strategy : <T extends StrategicState>(stratName: string, gen: (a: T) => IterableIterator<T>) => (a: T) => IterableIterator<T>
6868
>"Nothing" : "Nothing"
69-
>function*(state: State) { yield state;} : (state: State) => Generator<State, void, unknown>
69+
>function*(state: State) { yield state;} : (state: State) => Generator<State, void, undefined>
7070
>state : State
7171

7272
yield state;
@@ -80,7 +80,7 @@ export const Nothing3: Strategy<State> = strategy("Nothing", function* (state: S
8080
>strategy("Nothing", function* (state: State) { yield ; return state;}) : (a: any) => IterableIterator<any>
8181
>strategy : <T extends StrategicState>(stratName: string, gen: (a: T) => IterableIterator<T>) => (a: T) => IterableIterator<T>
8282
>"Nothing" : "Nothing"
83-
>function* (state: State) { yield ; return state;} : (state: State) => Generator<any, State, unknown>
83+
>function* (state: State) { yield ; return state;} : (state: State) => Generator<any, State, undefined>
8484
>state : State
8585

8686
yield ;

tests/baselines/reference/generatorTypeCheck63.errors.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(24,61): error TS2345: Argument of type '(state: State) => Generator<number, State, unknown>' is not assignable to parameter of type '(a: State) => IterableIterator<State>'.
2-
Type 'Generator<number, State, unknown>' is not assignable to type 'IterableIterator<State>'.
1+
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(24,61): error TS2345: Argument of type '(state: State) => Generator<number, State, undefined>' is not assignable to parameter of type '(a: State) => IterableIterator<State>'.
2+
Type 'Generator<number, State, undefined>' is not assignable to type 'IterableIterator<State>'.
33
Types of property 'next' are incompatible.
4-
Type '(...args: [] | [unknown]) => IteratorResult<number, State>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<State, any>'.
4+
Type '(...args: [] | [undefined]) => IteratorResult<number, State>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<State, any>'.
55
Type 'IteratorResult<number, State>' is not assignable to type 'IteratorResult<State, any>'.
66
Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorResult<State, any>'.
77
Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorYieldResult<State>'.
@@ -34,10 +34,10 @@ tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck63.ts(24,61): err
3434

3535
export const Nothing: Strategy<State> = strategy("Nothing", function* (state: State) {
3636
~~~~~~~~
37-
!!! error TS2345: Argument of type '(state: State) => Generator<number, State, unknown>' is not assignable to parameter of type '(a: State) => IterableIterator<State>'.
38-
!!! error TS2345: Type 'Generator<number, State, unknown>' is not assignable to type 'IterableIterator<State>'.
37+
!!! error TS2345: Argument of type '(state: State) => Generator<number, State, undefined>' is not assignable to parameter of type '(a: State) => IterableIterator<State>'.
38+
!!! error TS2345: Type 'Generator<number, State, undefined>' is not assignable to type 'IterableIterator<State>'.
3939
!!! error TS2345: Types of property 'next' are incompatible.
40-
!!! error TS2345: Type '(...args: [] | [unknown]) => IteratorResult<number, State>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<State, any>'.
40+
!!! error TS2345: Type '(...args: [] | [undefined]) => IteratorResult<number, State>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<State, any>'.
4141
!!! error TS2345: Type 'IteratorResult<number, State>' is not assignable to type 'IteratorResult<State, any>'.
4242
!!! error TS2345: Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorResult<State, any>'.
4343
!!! error TS2345: Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorYieldResult<State>'.

tests/baselines/reference/generatorTypeCheck63.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function strategy<T extends StrategicState>(stratName: string, gen: (a: T
1212
>a : T
1313

1414
return function*(state) {
15-
>function*(state) { for (const next of gen(state)) { if (next) { next.lastStrategyApplied = stratName; } yield next; } } : (state: T) => Generator<T, void, unknown>
15+
>function*(state) { for (const next of gen(state)) { if (next) { next.lastStrategyApplied = stratName; } yield next; } } : (state: T) => Generator<T, void, undefined>
1616
>state : T
1717

1818
for (const next of gen(state)) {
@@ -53,7 +53,7 @@ export const Nothing: Strategy<State> = strategy("Nothing", function* (state: St
5353
>strategy("Nothing", function* (state: State) { yield 1; return state;}) : any
5454
>strategy : <T extends StrategicState>(stratName: string, gen: (a: T) => IterableIterator<T>) => (a: T) => IterableIterator<T>
5555
>"Nothing" : "Nothing"
56-
>function* (state: State) { yield 1; return state;} : (state: State) => Generator<number, State, unknown>
56+
>function* (state: State) { yield 1; return state;} : (state: State) => Generator<number, State, undefined>
5757
>state : State
5858

5959
yield 1;
@@ -70,7 +70,7 @@ export const Nothing1: Strategy<State> = strategy("Nothing", function* (state: S
7070
>strategy("Nothing", function* (state: State) {}) : (a: State) => IterableIterator<State>
7171
>strategy : <T extends StrategicState>(stratName: string, gen: (a: T) => IterableIterator<T>) => (a: T) => IterableIterator<T>
7272
>"Nothing" : "Nothing"
73-
>function* (state: State) {} : (state: State) => Generator<never, void, unknown>
73+
>function* (state: State) {} : (state: State) => Generator<never, void, undefined>
7474
>state : State
7575

7676
});
@@ -80,7 +80,7 @@ export const Nothing2: Strategy<State> = strategy("Nothing", function* (state: S
8080
>strategy("Nothing", function* (state: State) { return 1;}) : (a: State) => IterableIterator<State>
8181
>strategy : <T extends StrategicState>(stratName: string, gen: (a: T) => IterableIterator<T>) => (a: T) => IterableIterator<T>
8282
>"Nothing" : "Nothing"
83-
>function* (state: State) { return 1;} : (state: State) => Generator<never, number, unknown>
83+
>function* (state: State) { return 1;} : (state: State) => Generator<never, number, undefined>
8484
>state : State
8585

8686
return 1;
@@ -93,7 +93,7 @@ export const Nothing3: Strategy<State> = strategy("Nothing", function* (state: S
9393
>strategy("Nothing", function* (state: State) { yield state; return 1;}) : (a: State) => IterableIterator<State>
9494
>strategy : <T extends StrategicState>(stratName: string, gen: (a: T) => IterableIterator<T>) => (a: T) => IterableIterator<T>
9595
>"Nothing" : "Nothing"
96-
>function* (state: State) { yield state; return 1;} : (state: State) => Generator<State, number, unknown>
96+
>function* (state: State) { yield state; return 1;} : (state: State) => Generator<State, number, undefined>
9797
>state : State
9898

9999
yield state;

tests/baselines/reference/generatorYieldContextualType.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ declare function f1<T, R, S>(gen: () => Generator<R, T, S>): void;
66
f1<0, 0, 1>(function* () {
77
>f1<0, 0, 1>(function* () { const a = yield 0; return 0;}) : void
88
>f1 : <T, R, S>(gen: () => Generator<R, T, S>) => void
9-
>function* () { const a = yield 0; return 0;} : () => Generator<0, 0, unknown>
9+
>function* () { const a = yield 0; return 0;} : () => Generator<0, 0, 1>
1010

1111
const a = yield 0;
1212
>a : 1
@@ -25,7 +25,7 @@ declare function f2<T, R, S>(gen: () => Generator<R, T, S> | AsyncGenerator<R, T
2525
f2<0, 0, 1>(async function* () {
2626
>f2<0, 0, 1>(async function* () { const a = yield 0; return 0;}) : void
2727
>f2 : <T, R, S>(gen: () => Generator<R, T, S> | AsyncGenerator<R, T, S>) => void
28-
>async function* () { const a = yield 0; return 0;} : () => AsyncGenerator<0, 0, unknown>
28+
>async function* () { const a = yield 0; return 0;} : () => AsyncGenerator<0, 0, 1>
2929

3030
const a = yield 0;
3131
>a : 1

tests/baselines/reference/types.asyncGenerators.es2018.1.types

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ async function * inferReturnType8() {
7575
}
7676
const assignability1: () => AsyncIterableIterator<number> = async function * () {
7777
>assignability1 : () => AsyncIterableIterator<number>
78-
>async function * () { yield 1;} : () => AsyncGenerator<number, void, unknown>
78+
>async function * () { yield 1;} : () => AsyncGenerator<number, void, undefined>
7979

8080
yield 1;
8181
>yield 1 : undefined
@@ -84,7 +84,7 @@ const assignability1: () => AsyncIterableIterator<number> = async function * ()
8484
};
8585
const assignability2: () => AsyncIterableIterator<number> = async function * () {
8686
>assignability2 : () => AsyncIterableIterator<number>
87-
>async function * () { yield Promise.resolve(1);} : () => AsyncGenerator<number, void, unknown>
87+
>async function * () { yield Promise.resolve(1);} : () => AsyncGenerator<number, void, undefined>
8888

8989
yield Promise.resolve(1);
9090
>yield Promise.resolve(1) : undefined
@@ -135,7 +135,7 @@ const assignability5: () => AsyncIterableIterator<number> = async function * ()
135135
};
136136
const assignability6: () => AsyncIterable<number> = async function * () {
137137
>assignability6 : () => AsyncIterable<number>
138-
>async function * () { yield 1;} : () => AsyncGenerator<number, void, unknown>
138+
>async function * () { yield 1;} : () => AsyncGenerator<number, void, undefined>
139139

140140
yield 1;
141141
>yield 1 : undefined
@@ -144,7 +144,7 @@ const assignability6: () => AsyncIterable<number> = async function * () {
144144
};
145145
const assignability7: () => AsyncIterable<number> = async function * () {
146146
>assignability7 : () => AsyncIterable<number>
147-
>async function * () { yield Promise.resolve(1);} : () => AsyncGenerator<number, void, unknown>
147+
>async function * () { yield Promise.resolve(1);} : () => AsyncGenerator<number, void, undefined>
148148

149149
yield Promise.resolve(1);
150150
>yield Promise.resolve(1) : undefined
@@ -195,7 +195,7 @@ const assignability10: () => AsyncIterable<number> = async function * () {
195195
};
196196
const assignability11: () => AsyncIterator<number> = async function * () {
197197
>assignability11 : () => AsyncIterator<number, any, undefined>
198-
>async function * () { yield 1;} : () => AsyncGenerator<number, void, unknown>
198+
>async function * () { yield 1;} : () => AsyncGenerator<number, void, undefined>
199199

200200
yield 1;
201201
>yield 1 : undefined
@@ -204,7 +204,7 @@ const assignability11: () => AsyncIterator<number> = async function * () {
204204
};
205205
const assignability12: () => AsyncIterator<number> = async function * () {
206206
>assignability12 : () => AsyncIterator<number, any, undefined>
207-
>async function * () { yield Promise.resolve(1);} : () => AsyncGenerator<number, void, unknown>
207+
>async function * () { yield Promise.resolve(1);} : () => AsyncGenerator<number, void, undefined>
208208

209209
yield Promise.resolve(1);
210210
>yield Promise.resolve(1) : undefined

0 commit comments

Comments
 (0)