Skip to content

Commit

Permalink
Improve typing for Generators and Async Generators
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Apr 7, 2019
1 parent 645853a commit 8204898
Show file tree
Hide file tree
Showing 266 changed files with 2,949 additions and 1,556 deletions.
793 changes: 566 additions & 227 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace ts {
["es2017.string", "lib.es2017.string.d.ts"],
["es2017.intl", "lib.es2017.intl.d.ts"],
["es2017.typedarrays", "lib.es2017.typedarrays.d.ts"],
["es2018.asyncgenerator", "lib.es2018.asyncgenerator.d.ts"],
["es2018.asynciterable", "lib.es2018.asynciterable.d.ts"],
["es2018.intl", "lib.es2018.intl.d.ts"],
["es2018.promise", "lib.es2018.promise.d.ts"],
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3899,6 +3899,10 @@
"category": "Message",
"code": 6217
},
"Enable strict checking of generator types.": {
"category": "Message",
"code": 6218
},

"Projects to reference": {
"category": "Message",
Expand Down Expand Up @@ -4256,6 +4260,10 @@
"category": "Error",
"code": 7051
},
"Generator implicitly has type '{0}' because it does not yield or return any values. Consider supplying a return type.": {
"category": "Error",
"code": 7052
},

"You cannot rename this element.": {
"category": "Error",
Expand Down
16 changes: 12 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4226,13 +4226,21 @@ namespace ts {
regularType: ResolvedType; // Regular version of fresh type
}

/* @internal */
export interface IterationTypes {
yieldType?: Type;
returnType?: Type;
nextType?: Type;
}

// Just a place to cache element types of iterables and iterators
/* @internal */
export interface IterableOrIteratorType extends ObjectType, UnionType {
iteratedTypeOfIterable?: Type;
iteratedTypeOfIterator?: Type;
iteratedTypeOfAsyncIterable?: Type;
iteratedTypeOfAsyncIterator?: Type;
iterationTypesOfIterable?: IterationTypes;
iterationTypesOfIterator?: IterationTypes;
iterationTypesOfAsyncIterable?: IterationTypes;
iterationTypesOfAsyncIterator?: IterationTypes;
iterationTypesOfIteratorResult?: IterationTypes;
}

/* @internal */
Expand Down
4 changes: 2 additions & 2 deletions src/harness/vfs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ namespace vfs {

if (isDirectory(node)) throw createIOError("EISDIR");
if (!isFile(node)) throw createIOError("EBADF");
node.buffer = Buffer.isBuffer(data) ? data.slice() : ts.sys.bufferFrom!("" + data, encoding || "utf8");
node.buffer = Buffer.isBuffer(data) ? data.slice() : ts.sys.bufferFrom!("" + data, encoding || "utf8") as Buffer;
node.size = node.buffer.byteLength;
node.mtimeMs = time;
node.ctimeMs = time;
Expand Down Expand Up @@ -1204,7 +1204,7 @@ namespace vfs {
}
},
readFileSync(path: string): Buffer {
return ts.sys.bufferFrom!(host.readFile(path)!, "utf8"); // TODO: GH#18217
return ts.sys.bufferFrom!(host.readFile(path)!, "utf8") as Buffer; // TODO: GH#18217
}
};
}
Expand Down
9 changes: 8 additions & 1 deletion src/lib/es2015.generator.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
interface Generator extends Iterator<any> { }
/// <reference lib="es2015.iterable" />

interface Generator<TYield = unknown, TReturn = void, TNext = unknown> {
next(value?: TNext): IteratorResult<TYield, TReturn>;
return(value: TReturn): IteratorResult<TYield, TReturn>;
throw(e: any): IteratorResult<TYield, TReturn>;
[Symbol.iterator](): Generator<TYield, TReturn, TNext>;
}

interface GeneratorFunction {
/**
Expand Down
13 changes: 10 additions & 3 deletions src/lib/es2015.iterable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@ interface SymbolConstructor {
readonly iterator: symbol;
}

interface IteratorResult<T> {
done: boolean;
value: T;
interface IteratorYieldResult<TYield> {
done: false;
value: TYield;
}

interface IteratorReturnResult<TReturn> {
done: true;
value: TReturn;
}

type IteratorResult<T, TReturn = T | void> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;

interface Iterator<T> {
next(value?: any): IteratorResult<T>;
return?(value?: any): IteratorResult<T>;
Expand Down
58 changes: 58 additions & 0 deletions src/lib/es2018.asyncgenerator.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/// <reference lib="es2018.asynciterable" />

interface AsyncGenerator<TYield = unknown, TReturn = void, TNext = unknown> {
next(value?: TNext): Promise<IteratorResult<TYield, TReturn>>;
return(value: TReturn): Promise<IteratorResult<TYield, TReturn>>;
throw(e: unknown): Promise<IteratorResult<TYield, TReturn>>;
[Symbol.asyncIterator](): AsyncGenerator<TYield, TReturn, TNext>;
}

interface AsyncGeneratorFunction {
/**
* Creates a new AsyncGenerator object.
* @param args A list of arguments the function accepts.
*/
new (...args: any[]): AsyncGenerator;
/**
* Creates a new AsyncGenerator object.
* @param args A list of arguments the function accepts.
*/
(...args: any[]): AsyncGenerator;
/**
* The length of the arguments.
*/
readonly length: number;
/**
* Returns the name of the function.
*/
readonly name: string;
/**
* A reference to the prototype.
*/
readonly prototype: AsyncGenerator;
}

interface AsyncGeneratorFunctionConstructor {
/**
* Creates a new AsyncGenerator function.
* @param args A list of arguments the function accepts.
*/
new (...args: string[]): AsyncGeneratorFunction;
/**
* Creates a new AsyncGenerator function.
* @param args A list of arguments the function accepts.
*/
(...args: string[]): AsyncGeneratorFunction;
/**
* The length of the arguments.
*/
readonly length: number;
/**
* Returns the name of the function.
*/
readonly name: string;
/**
* A reference to the prototype.
*/
readonly prototype: AsyncGeneratorFunction;
}
1 change: 1 addition & 0 deletions src/lib/es2018.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// <reference lib="es2017" />
/// <reference lib="es2018.asyncgenerator" />
/// <reference lib="es2018.asynciterable" />
/// <reference lib="es2018.promise" />
/// <reference lib="es2018.regexp" />
Expand Down
1 change: 1 addition & 0 deletions src/lib/libs.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"es2017.string",
"es2017.intl",
"es2017.typedarrays",
"es2018.asyncgenerator",
"es2018.asynciterable",
"es2018.regexp",
"es2018.promise",
Expand Down
4 changes: 2 additions & 2 deletions src/testRunner/parallel/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ namespace Harness.Parallel.Host {
worker.accumulatedOutput += d.toString();
console.log(`[Worker ${i}]`, d.toString());
};
worker.process.stderr.on("data", appendOutput);
worker.process.stdout.on("data", appendOutput);
worker.process.stderr!.on("data", appendOutput);
worker.process.stdout!.on("data", appendOutput);
const killChild = (timeout: TaskTimeout) => {
worker.process.kill();
console.error(`Worker exceeded ${timeout.duration}ms timeout ${worker.currentTasks && worker.currentTasks.length ? `while running test '${worker.currentTasks[0].file}'.` : `during test setup.`}`);
Expand Down
6 changes: 3 additions & 3 deletions src/testRunner/unittests/config/commandLineParsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace ts {
assertParseResult(["--lib", "es5,invalidOption", "0.ts"],
{
errors: [{
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
file: undefined,
Expand Down Expand Up @@ -259,7 +259,7 @@ namespace ts {
assertParseResult(["--lib", "es5,", "es7", "0.ts"],
{
errors: [{
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
file: undefined,
Expand All @@ -278,7 +278,7 @@ namespace ts {
assertParseResult(["--lib", "es5, ", "es7", "0.ts"],
{
errors: [{
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
file: undefined,
Expand Down
2 changes: 1 addition & 1 deletion src/tsconfig-base.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"pretty": true,
"lib": ["es2015.iterable", "es5"],
"lib": ["es2015.iterable", "es2015.generator", "es5"],
"target": "es5",
"rootDir": ".",

Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/FunctionDeclaration11_es6.types
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
=== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration11_es6.ts ===
function * yield() {
>yield : () => IterableIterator<any>
>yield : () => Generator<never, void, unknown>
}
2 changes: 1 addition & 1 deletion tests/baselines/reference/FunctionDeclaration13_es6.types
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration13_es6.ts ===
function * foo() {
>foo : () => IterableIterator<any>
>foo : () => Generator<never, void, unknown>

// Legal to use 'yield' in a type context.
var v: yield;
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/FunctionDeclaration1_es6.types
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
=== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration1_es6.ts ===
function * foo() {
>foo : () => IterableIterator<any>
>foo : () => Generator<never, void, unknown>
}
2 changes: 1 addition & 1 deletion tests/baselines/reference/FunctionDeclaration6_es6.types
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration6_es6.ts ===
function*foo(a = yield) {
>foo : (a?: any) => IterableIterator<any>
>foo : (a?: any) => Generator<never, void, unknown>
>a : any
>yield : any
}
4 changes: 2 additions & 2 deletions tests/baselines/reference/FunctionDeclaration7_es6.types
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
=== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration7_es6.ts ===
function*bar() {
>bar : () => IterableIterator<any>
>bar : () => Generator<never, void, unknown>

// 'yield' here is an identifier, and not a yield expression.
function*foo(a = yield) {
>foo : (a?: any) => IterableIterator<any>
>foo : (a?: any) => Generator<never, void, unknown>
>a : any
>yield : any
}
Expand Down
10 changes: 5 additions & 5 deletions tests/baselines/reference/FunctionDeclaration9_es6.types
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
=== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration9_es6.ts ===
function * foo() {
>foo : () => IterableIterator<any>
>foo : () => Generator<any, void, unknown>

var v = { [yield]: foo }
>v : { [x: number]: () => IterableIterator<any>; }
>{ [yield]: foo } : { [x: number]: () => IterableIterator<any>; }
>[yield] : () => IterableIterator<any>
>v : { [x: number]: () => Generator<any, void, unknown>; }
>{ [yield]: foo } : { [x: number]: () => Generator<any, void, unknown>; }
>[yield] : () => Generator<any, void, unknown>
>yield : any
>foo : () => IterableIterator<any>
>foo : () => Generator<any, void, unknown>
}
4 changes: 2 additions & 2 deletions tests/baselines/reference/FunctionExpression1_es6.types
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
=== tests/cases/conformance/es6/functionExpressions/FunctionExpression1_es6.ts ===
var v = function * () { }
>v : () => IterableIterator<any>
>function * () { } : () => IterableIterator<any>
>v : () => Generator<never, void, unknown>
>function * () { } : () => Generator<never, void, unknown>

6 changes: 3 additions & 3 deletions tests/baselines/reference/FunctionExpression2_es6.types
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/es6/functionExpressions/FunctionExpression2_es6.ts ===
var v = function * foo() { }
>v : () => IterableIterator<any>
>function * foo() { } : () => IterableIterator<any>
>foo : () => IterableIterator<any>
>v : () => Generator<never, void, unknown>
>function * foo() { } : () => Generator<never, void, unknown>
>foo : () => Generator<never, void, unknown>

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/es6/functionPropertyAssignments/FunctionPropertyAssignments1_es6.ts ===
var v = { *foo() { } }
>v : { foo(): IterableIterator<any>; }
>{ *foo() { } } : { foo(): IterableIterator<any>; }
>foo : () => IterableIterator<any>
>v : { foo(): Generator<never, void, unknown>; }
>{ *foo() { } } : { foo(): Generator<never, void, unknown>; }
>foo : () => Generator<never, void, unknown>

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/es6/functionPropertyAssignments/FunctionPropertyAssignments2_es6.ts ===
var v = { *() { } }
>v : { (Missing)(): IterableIterator<any>; }
>{ *() { } } : { (Missing)(): IterableIterator<any>; }
> : () => IterableIterator<any>
>v : { (Missing)(): Generator<never, void, unknown>; }
>{ *() { } } : { (Missing)(): Generator<never, void, unknown>; }
> : () => Generator<never, void, unknown>

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/es6/functionPropertyAssignments/FunctionPropertyAssignments3_es6.ts ===
var v = { *{ } }
>v : { (Missing)(): IterableIterator<any>; }
>{ *{ } } : { (Missing)(): IterableIterator<any>; }
> : () => IterableIterator<any>
>v : { (Missing)(): Generator<never, void, unknown>; }
>{ *{ } } : { (Missing)(): Generator<never, void, unknown>; }
> : () => Generator<never, void, unknown>

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
=== tests/cases/conformance/es6/functionPropertyAssignments/FunctionPropertyAssignments5_es6.ts ===
var v = { *[foo()]() { } }
>v : { [x: number]: () => IterableIterator<any>; }
>{ *[foo()]() { } } : { [x: number]: () => IterableIterator<any>; }
>[foo()] : () => IterableIterator<any>
>v : { [x: number]: () => Generator<never, void, unknown>; }
>{ *[foo()]() { } } : { [x: number]: () => Generator<never, void, unknown>; }
>[foo()] : () => Generator<never, void, unknown>
>foo() : any
>foo : any

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/es6/functionPropertyAssignments/FunctionPropertyAssignments6_es6.ts ===
var v = { *<T>() { } }
>v : { (Missing)<T>(): IterableIterator<any>; }
>{ *<T>() { } } : { (Missing)<T>(): IterableIterator<any>; }
> : <T>() => IterableIterator<any>
>v : { (Missing)<T>(): Generator<never, void, unknown>; }
>{ *<T>() { } } : { (Missing)<T>(): Generator<never, void, unknown>; }
> : <T>() => Generator<never, void, unknown>

Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ class C {
>C : C

*foo() { }
>foo : () => IterableIterator<any>
>foo : () => Generator<never, void, unknown>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ class C {
>C : C

public * foo() { }
>foo : () => IterableIterator<any>
>foo : () => Generator<never, void, unknown>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ class C {
>C : C

*[foo]() { }
>[foo] : () => IterableIterator<any>
>[foo] : () => Generator<never, void, unknown>
>foo : any
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ class C {
>C : C

*() { }
> : () => IterableIterator<any>
> : () => Generator<never, void, unknown>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ class C {
>C : C

*foo<T>() { }
>foo : <T>() => IterableIterator<any>
>foo : <T>() => Generator<never, void, unknown>
}
Loading

0 comments on commit 8204898

Please sign in to comment.