Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect parameter types for AsyncIterator next/return #33354

Merged
merged 1 commit into from
Sep 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28740,11 +28740,13 @@ namespace ts {
let nextType: Type | undefined;
if (methodName !== "throw") {
const methodParameterType = methodParameterTypes ? getUnionType(methodParameterTypes) : unknownType;
const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) || anyType;
if (methodName === "next") {
nextType = resolvedMethodParameterType;
// The value of `next(value)` is *not* awaited by async generators
nextType = methodParameterType;
}
else if (methodName === "return") {
// The value of `return(value)` *is* awaited by async generators
const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) || anyType;
returnTypes = append(returnTypes, resolvedMethodParameterType);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/es2018.asyncgenerator.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> extends AsyncIterator<T, TReturn, TNext> {
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
next(...args: [] | [TNext | PromiseLike<TNext>]): Promise<IteratorResult<T, TReturn>>;
next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>>;
return(value: TReturn | PromiseLike<TReturn>): Promise<IteratorResult<T, TReturn>>;
rbuckton marked this conversation as resolved.
Show resolved Hide resolved
throw(e: any): Promise<IteratorResult<T, TReturn>>;
[Symbol.asyncIterator](): AsyncGenerator<T, TReturn, TNext>;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/es2018.asynciterable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface SymbolConstructor {

interface AsyncIterator<T, TReturn = any, TNext = undefined> {
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
next(...args: [] | [TNext | PromiseLike<TNext>]): Promise<IteratorResult<T, TReturn>>;
next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>>;
return?(value?: TReturn | PromiseLike<TReturn>): Promise<IteratorResult<T, TReturn>>;
throw?(e?: any): Promise<IteratorResult<T, TReturn>>;
}
Expand Down
26 changes: 26 additions & 0 deletions tests/baselines/reference/customAsyncIterator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//// [customAsyncIterator.ts]
// GH: https://github.com/microsoft/TypeScript/issues/33239
class ConstantIterator<T> implements AsyncIterator<T, undefined, T | undefined> {
constructor(private constant: T) {
}
async next(value?: T): Promise<IteratorResult<T>> {
if (value != null) {
throw new Error("ConstantIterator.prototype.next may not take any values");
}
return { value: this.constant, done: false };
}
}

//// [customAsyncIterator.js]
// GH: https://github.com/microsoft/TypeScript/issues/33239
class ConstantIterator {
constructor(constant) {
this.constant = constant;
}
async next(value) {
if (value != null) {
throw new Error("ConstantIterator.prototype.next may not take any values");
}
return { value: this.constant, done: false };
}
}
35 changes: 35 additions & 0 deletions tests/baselines/reference/customAsyncIterator.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
=== tests/cases/compiler/customAsyncIterator.ts ===
// GH: https://github.com/microsoft/TypeScript/issues/33239
class ConstantIterator<T> implements AsyncIterator<T, undefined, T | undefined> {
>ConstantIterator : Symbol(ConstantIterator, Decl(customAsyncIterator.ts, 0, 0))
>T : Symbol(T, Decl(customAsyncIterator.ts, 1, 23))
>AsyncIterator : Symbol(AsyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
>T : Symbol(T, Decl(customAsyncIterator.ts, 1, 23))
>T : Symbol(T, Decl(customAsyncIterator.ts, 1, 23))

constructor(private constant: T) {
>constant : Symbol(ConstantIterator.constant, Decl(customAsyncIterator.ts, 2, 16))
>T : Symbol(T, Decl(customAsyncIterator.ts, 1, 23))
}
async next(value?: T): Promise<IteratorResult<T>> {
>next : Symbol(ConstantIterator.next, Decl(customAsyncIterator.ts, 3, 5))
>value : Symbol(value, Decl(customAsyncIterator.ts, 4, 15))
>T : Symbol(T, Decl(customAsyncIterator.ts, 1, 23))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(customAsyncIterator.ts, 1, 23))

if (value != null) {
>value : Symbol(value, Decl(customAsyncIterator.ts, 4, 15))

throw new Error("ConstantIterator.prototype.next may not take any values");
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
}
return { value: this.constant, done: false };
>value : Symbol(value, Decl(customAsyncIterator.ts, 8, 16))
>this.constant : Symbol(ConstantIterator.constant, Decl(customAsyncIterator.ts, 2, 16))
>this : Symbol(ConstantIterator, Decl(customAsyncIterator.ts, 0, 0))
>constant : Symbol(ConstantIterator.constant, Decl(customAsyncIterator.ts, 2, 16))
>done : Symbol(done, Decl(customAsyncIterator.ts, 8, 38))
}
}
32 changes: 32 additions & 0 deletions tests/baselines/reference/customAsyncIterator.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
=== tests/cases/compiler/customAsyncIterator.ts ===
// GH: https://github.com/microsoft/TypeScript/issues/33239
class ConstantIterator<T> implements AsyncIterator<T, undefined, T | undefined> {
>ConstantIterator : ConstantIterator<T>

constructor(private constant: T) {
>constant : T
}
async next(value?: T): Promise<IteratorResult<T>> {
>next : (value?: T) => Promise<IteratorResult<T, any>>
>value : T

if (value != null) {
>value != null : boolean
>value : T
>null : null

throw new Error("ConstantIterator.prototype.next may not take any values");
>new Error("ConstantIterator.prototype.next may not take any values") : Error
>Error : ErrorConstructor
>"ConstantIterator.prototype.next may not take any values" : "ConstantIterator.prototype.next may not take any values"
}
return { value: this.constant, done: false };
>{ value: this.constant, done: false } : { value: T; done: false; }
>value : T
>this.constant : T
>this : this
>constant : T
>done : false
>false : false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -289,4 +289,13 @@ async function * awaitedType2() {
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
}
async function * nextType1(): { next(...args: [] | [number | PromiseLike<number>]): any } {
>nextType1 : Symbol(nextType1, Decl(types.asyncGenerators.es2018.1.ts, 122, 1))
>next : Symbol(next, Decl(types.asyncGenerators.es2018.1.ts, 123, 31))
>args : Symbol(args, Decl(types.asyncGenerators.es2018.1.ts, 123, 37))
>PromiseLike : Symbol(PromiseLike, Decl(lib.es5.d.ts, --, --))

const x = yield; // `number | PromiseLike<number>` (should not await TNext)
>x : Symbol(x, Decl(types.asyncGenerators.es2018.1.ts, 124, 9))
}

Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,13 @@ async function * awaitedType2() {
>resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
>1 : 1
}
async function * nextType1(): { next(...args: [] | [number | PromiseLike<number>]): any } {
>nextType1 : () => { next(...args: [] | [number | PromiseLike<number>]): any; }
>next : (...args: [] | [number | PromiseLike<number>]) => any
>args : [] | [number | PromiseLike<number>]

const x = yield; // `number | PromiseLike<number>` (should not await TNext)
>x : number | PromiseLike<number>
>yield : number | PromiseLike<number>
}

20 changes: 10 additions & 10 deletions tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(10,7): error TS2322: Type '() => AsyncGenerator<string, void, undefined>' is not assignable to type '() => AsyncIterableIterator<number>'.
Type 'AsyncGenerator<string, void, undefined>' is not assignable to type 'AsyncIterableIterator<number>'.
Types of property 'next' are incompatible.
Type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
Type '(...args: [] | [undefined]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
Type 'IteratorResult<string, void>' is not assignable to type 'IteratorResult<number, any>'.
Type 'IteratorYieldResult<string>' is not assignable to type 'IteratorResult<number, any>'.
Expand All @@ -14,15 +14,15 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(16,7): error TS2322: Type '() => AsyncGenerator<string, void, unknown>' is not assignable to type '() => AsyncIterableIterator<number>'.
Type 'AsyncGenerator<string, void, unknown>' is not assignable to type 'AsyncIterableIterator<number>'.
Types of property 'next' are incompatible.
Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(19,7): error TS2322: Type '() => AsyncGenerator<string, void, undefined>' is not assignable to type '() => AsyncIterable<number>'.
Type 'AsyncGenerator<string, void, undefined>' is not assignable to type 'AsyncIterable<number>'.
Types of property '[Symbol.asyncIterator]' are incompatible.
Type '() => AsyncGenerator<string, void, undefined>' is not assignable to type '() => AsyncIterator<number, any, undefined>'.
Type 'AsyncGenerator<string, void, undefined>' is not assignable to type 'AsyncIterator<number, any, undefined>'.
Types of property 'next' are incompatible.
Type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
Type '(...args: [] | [undefined]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(22,7): error TS2322: Type '() => AsyncGenerator<string, void, undefined>' is not assignable to type '() => AsyncIterable<number>'.
Type 'AsyncGenerator<string, void, undefined>' is not assignable to type 'AsyncIterable<number>'.
Expand All @@ -32,7 +32,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
Type '() => AsyncGenerator<string, void, unknown>' is not assignable to type '() => AsyncIterator<number, any, undefined>'.
Type 'AsyncGenerator<string, void, unknown>' is not assignable to type 'AsyncIterator<number, any, undefined>'.
Types of property 'next' are incompatible.
Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(28,7): error TS2322: Type '() => AsyncGenerator<string, void, undefined>' is not assignable to type '() => AsyncIterator<number, any, undefined>'.
Type 'AsyncGenerator<string, void, undefined>' is not assignable to type 'AsyncIterator<number, any, undefined>'.
Expand All @@ -53,7 +53,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(67,42): error TS2741: Property '[Symbol.iterator]' is missing in type 'AsyncGenerator<any, any, any>' but required in type 'Iterable<number>'.
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(70,42): error TS2322: Type 'AsyncGenerator<number, any, undefined>' is not assignable to type 'Iterator<number, any, undefined>'.
Types of property 'next' are incompatible.
Type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<number, any>'.
Type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<number, any>'.
Type 'Promise<IteratorResult<number, any>>' is not assignable to type 'IteratorResult<number, any>'.
Property 'value' is missing in type 'Promise<IteratorResult<number, any>>' but required in type 'IteratorYieldResult<number>'.
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(74,12): error TS2504: Type '{}' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
Expand All @@ -79,7 +79,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
!!! error TS2322: Type '() => AsyncGenerator<string, void, undefined>' is not assignable to type '() => AsyncIterableIterator<number>'.
!!! error TS2322: Type 'AsyncGenerator<string, void, undefined>' is not assignable to type 'AsyncIterableIterator<number>'.
!!! error TS2322: Types of property 'next' are incompatible.
!!! error TS2322: Type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type '(...args: [] | [undefined]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type 'IteratorResult<string, void>' is not assignable to type 'IteratorResult<number, any>'.
!!! error TS2322: Type 'IteratorYieldResult<string>' is not assignable to type 'IteratorResult<number, any>'.
Expand All @@ -98,7 +98,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
!!! error TS2322: Type '() => AsyncGenerator<string, void, unknown>' is not assignable to type '() => AsyncIterableIterator<number>'.
!!! error TS2322: Type 'AsyncGenerator<string, void, unknown>' is not assignable to type 'AsyncIterableIterator<number>'.
!!! error TS2322: Types of property 'next' are incompatible.
!!! error TS2322: Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
yield* (async function * () { yield "a"; })();
};
Expand All @@ -110,7 +110,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
!!! error TS2322: Type '() => AsyncGenerator<string, void, undefined>' is not assignable to type '() => AsyncIterator<number, any, undefined>'.
!!! error TS2322: Type 'AsyncGenerator<string, void, undefined>' is not assignable to type 'AsyncIterator<number, any, undefined>'.
!!! error TS2322: Types of property 'next' are incompatible.
!!! error TS2322: Type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type '(...args: [] | [undefined]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
yield "a";
};
Expand All @@ -128,7 +128,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
!!! error TS2322: Type '() => AsyncGenerator<string, void, unknown>' is not assignable to type '() => AsyncIterator<number, any, undefined>'.
!!! error TS2322: Type 'AsyncGenerator<string, void, unknown>' is not assignable to type 'AsyncIterator<number, any, undefined>'.
!!! error TS2322: Types of property 'next' are incompatible.
!!! error TS2322: Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type '(...args: [] | [unknown]) => Promise<IteratorResult<string, void>>' is not assignable to type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>'.
!!! error TS2322: Type 'Promise<IteratorResult<string, void>>' is not assignable to type 'Promise<IteratorResult<number, any>>'.
yield* (async function * () { yield "a"; })();
};
Expand Down Expand Up @@ -211,7 +211,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'AsyncGenerator<number, any, undefined>' is not assignable to type 'Iterator<number, any, undefined>'.
!!! error TS2322: Types of property 'next' are incompatible.
!!! error TS2322: Type '(...args: [] | [PromiseLike<undefined>]) => Promise<IteratorResult<number, any>>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<number, any>'.
!!! error TS2322: Type '(...args: [] | [undefined]) => Promise<IteratorResult<number, any>>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<number, any>'.
!!! error TS2322: Type 'Promise<IteratorResult<number, any>>' is not assignable to type 'IteratorResult<number, any>'.
!!! error TS2322: Property 'value' is missing in type 'Promise<IteratorResult<number, any>>' but required in type 'IteratorYieldResult<number>'.
!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:33:5: 'value' is declared here.
Expand Down
13 changes: 13 additions & 0 deletions tests/cases/compiler/customAsyncIterator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @target: esnext

// GH: https://github.com/microsoft/TypeScript/issues/33239
class ConstantIterator<T> implements AsyncIterator<T, undefined, T | undefined> {
constructor(private constant: T) {
}
async next(value?: T): Promise<IteratorResult<T>> {
if (value != null) {
throw new Error("ConstantIterator.prototype.next may not take any values");
}
return { value: this.constant, done: false };
}
}
Loading