Type checking for async iterables and async generators.

This commit is contained in:
Ron Buckton
2016-11-05 18:48:33 -07:00
parent ed4fead087
commit c6ee25d95b
10 changed files with 595 additions and 327 deletions

View File

@@ -299,7 +299,8 @@ var es2016LibrarySourceMap = es2016LibrarySource.map(function (source) {
var es2017LibrarySource = [
"es2017.object.d.ts",
"es2017.sharedmemory.d.ts"
"es2017.sharedmemory.d.ts",
"es2017.asynciterable.d.ts"
];
var es2017LibrarySourceMap = es2017LibrarySource.map(function (source) {

View File

@@ -895,8 +895,8 @@ namespace ts {
const enclosingLabeledStatement = node.parent.kind === SyntaxKind.LabeledStatement
? lastOrUndefined(activeLabels)
: undefined;
// if do statement is wrapped in labeled statement then target labels for break/continue with or without
// label should be the same
// if do statement is wrapped in labeled statement then target labels for break/continue with or without
// label should be the same
const preConditionLabel = enclosingLabeledStatement ? enclosingLabeledStatement.continueTarget : createBranchLabel();
const postDoLabel = enclosingLabeledStatement ? enclosingLabeledStatement.breakTarget : createBranchLabel();
addAntecedent(preDoLabel, currentFlow);
@@ -2291,7 +2291,7 @@ namespace ts {
function bindFunctionDeclaration(node: FunctionDeclaration) {
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
if (isAsyncFunctionLike(node)) {
if (isAsyncFunction(node)) {
emitFlags |= NodeFlags.HasAsyncFunctions;
}
}
@@ -2308,7 +2308,7 @@ namespace ts {
function bindFunctionExpression(node: FunctionExpression) {
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
if (isAsyncFunctionLike(node)) {
if (isAsyncFunction(node)) {
emitFlags |= NodeFlags.HasAsyncFunctions;
}
}
@@ -2322,7 +2322,7 @@ namespace ts {
function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
if (!isDeclarationFile(file) && !isInAmbientContext(node)) {
if (isAsyncFunctionLike(node)) {
if (isAsyncFunction(node)) {
emitFlags |= NodeFlags.HasAsyncFunctions;
}
if (nodeIsDecorated(node)) {

File diff suppressed because it is too large Load Diff

View File

@@ -175,15 +175,15 @@
"category": "Error",
"code": 1057
},
"Operand for 'await' does not have a valid callable 'then' member.": {
"Type used as operand to 'await' or the return type of an async function must not contain a callable 'then' member if it is not a promise.": {
"category": "Error",
"code": 1058
},
"Return expression in async function does not have a valid callable 'then' member.": {
"A promise must have a 'then' method.": {
"category": "Error",
"code": 1059
},
"Expression body for async arrow function does not have a valid callable 'then' member.": {
"The first parameter of the 'then' method of a promise must be a callback.": {
"category": "Error",
"code": 1060
},
@@ -191,7 +191,7 @@
"category": "Error",
"code": 1061
},
"{0} is referenced directly or indirectly in the fulfillment callback of its own 'then' method.": {
"Type is referenced directly or indirectly in the fulfillment callback of its own 'then' method.": {
"category": "Error",
"code": 1062
},
@@ -1611,6 +1611,10 @@
"category": "Error",
"code": 2503
},
"Type must have a '[Symbol.asyncIterator]()' method that returns an async iterator.": {
"category": "Error",
"code": 2504
},
"A generator cannot have a 'void' type annotation.": {
"category": "Error",
"code": 2505
@@ -1667,6 +1671,10 @@
"category": "Error",
"code": 2518
},
"An async iterator must have a 'next()' method.": {
"category": "Error",
"code": 2519
},
"Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": {
"category": "Error",
"code": 2520
@@ -1759,6 +1767,10 @@
"category": "Error",
"code": 2542
},
"The type returned by the 'next()' method of an async iterator must be a promise for a type with a 'value' property.": {
"category": "Error",
"code": 2543
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600

View File

@@ -133,7 +133,7 @@ namespace ts {
* @param node The method node.
*/
function visitMethodDeclaration(node: MethodDeclaration) {
if (!isAsyncFunctionLike(node)) {
if (!isAsyncFunction(node)) {
return node;
}
const method = createMethod(
@@ -166,7 +166,7 @@ namespace ts {
* @param node The function node.
*/
function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> {
if (!isAsyncFunctionLike(node)) {
if (!isAsyncFunction(node)) {
return node;
}
const func = createFunctionDeclaration(
@@ -194,7 +194,7 @@ namespace ts {
* @param node The function expression node.
*/
function visitFunctionExpression(node: FunctionExpression): Expression {
if (!isAsyncFunctionLike(node)) {
if (!isAsyncFunction(node)) {
return node;
}
if (nodeIsMissing(node.body)) {
@@ -223,7 +223,7 @@ namespace ts {
* - The node is marked async
*/
function visitArrowFunction(node: ArrowFunction) {
if (!isAsyncFunctionLike(node)) {
if (!isAsyncFunction(node)) {
return node;
}
const func = createArrowFunction(

View File

@@ -1670,7 +1670,7 @@ namespace ts {
if (isFunctionLike(node) && node.type) {
return serializeTypeNode(node.type);
}
else if (isAsyncFunctionLike(node)) {
else if (isAsyncFunction(node)) {
return createIdentifier("Promise");
}

View File

@@ -2862,8 +2862,16 @@ namespace ts {
// Just a place to cache element types of iterables and iterators
/* @internal */
export interface IterableOrIteratorType extends ObjectType, UnionType {
iterableElementType?: Type;
iteratorElementType?: Type;
iteratedTypeOfIterable?: Type;
iteratedTypeOfIterator?: Type;
iteratedTypeOfAsyncIterable?: Type;
iteratedTypeOfAsyncIterator?: Type;
}
/* @internal */
export interface PromiseOrAwaitableType extends ObjectType, UnionType {
promisedTypeOfPromise?: Type;
awaitedTypeOfType?: Type;
}
// Type parameters (TypeFlags.TypeParameter)

View File

@@ -1855,8 +1855,50 @@ namespace ts {
return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken;
}
export function isAsyncFunctionLike(node: Node): boolean {
return isFunctionLike(node) && hasModifier(node, ModifierFlags.Async) && !isAccessor(node);
export const enum FunctionFlags {
Normal = 0,
Generator = 1 << 0,
Async = 1 << 1,
AsyncGenerator = Async | Generator,
Invalid = 1 << 2,
InvalidGenerator = Generator | Invalid,
}
export function getFunctionFlags(node: FunctionLikeDeclaration) {
let flags = FunctionFlags.Normal;
switch (node.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
if (node.asteriskToken) {
flags |= FunctionFlags.Generator;
}
// fall through
case SyntaxKind.ArrowFunction:
if (hasModifier(node, ModifierFlags.Async)) {
flags |= FunctionFlags.Async;
}
break;
}
if (!node.body) {
flags |= FunctionFlags.Invalid;
}
return flags;
}
export function isAsyncFunction(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.MethodDeclaration:
return (<FunctionLikeDeclaration>node).body !== undefined
&& (<FunctionLikeDeclaration>node).asteriskToken === undefined
&& hasModifier(node, ModifierFlags.Async);
}
return false;
}
export function isStringOrNumericLiteral(kind: SyntaxKind): boolean {

23
src/lib/es2017.asynciterable.d.ts vendored Normal file
View File

@@ -0,0 +1,23 @@
/// <reference path="lib.es2015.symbol.d.ts" />
interface SymbolConstructor {
/**
* A method that returns the default async iterator for an object. Called by the semantics of
* the for-await-of statement.
*/
readonly asyncIterator: symbol;
}
interface AsyncIterator<T> {
next(value?: any): Promise<IteratorResult<T>>;
return?(value?: any): Promise<IteratorResult<T>>;
throw?(e?: any): Promise<IteratorResult<T>>;
}
interface AsyncIterable<T> {
[Symbol.asyncIterator](): AsyncIterator<T>;
}
interface AsyncIterableIterator<T> extends AsyncIterator<T> {
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
}

3
src/lib/es2017.d.ts vendored
View File

@@ -1,3 +1,4 @@
/// <reference path="lib.es2016.d.ts" />
/// <reference path="lib.es2017.object.d.ts" />
/// <reference path="lib.es2017.sharedmemory.d.ts" />
/// <reference path="lib.es2017.sharedmemory.d.ts" />
/// <reference path="lib.es2017.asynciterable.d.ts" />