Parse, check, and downlevel emit for for-await-of

This commit is contained in:
Ron Buckton 2016-11-09 17:40:17 -08:00
parent 4b5686a52f
commit 4f3fb80b98
18 changed files with 101 additions and 37 deletions

View File

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

View File

@ -929,6 +929,9 @@ namespace ts {
const postLoopLabel = createBranchLabel();
addAntecedent(preLoopLabel, currentFlow);
currentFlow = preLoopLabel;
if (node.kind === SyntaxKind.ForOfStatement) {
bind(node.awaitKeyword);
}
bind(node.expression);
addAntecedent(postLoopLabel, currentFlow);
bind(node.initializer);

View File

@ -3155,7 +3155,8 @@ namespace ts {
// missing properties/signatures required to get its iteratedType (like
// [Symbol.iterator] or next). This may be because we accessed properties from anyType,
// or it may have led to an error inside getElementTypeOfIterable.
return checkRightHandSideOfForOf((<ForOfStatement>declaration.parent.parent).expression) || anyType;
const isForAwaitOf = (<ForOfStatement>declaration.parent.parent).awaitKeyword !== undefined;
return checkRightHandSideOfForOf((<ForOfStatement>declaration.parent.parent).expression, isForAwaitOf) || anyType;
}
if (isBindingPattern(declaration.parent)) {
@ -8631,7 +8632,7 @@ namespace ts {
case SyntaxKind.ForInStatement:
return stringType;
case SyntaxKind.ForOfStatement:
return checkRightHandSideOfForOf((<ForOfStatement>parent).expression) || unknownType;
return checkRightHandSideOfForOf((<ForOfStatement>parent).expression, (<ForOfStatement>parent).awaitKeyword !== undefined) || unknownType;
case SyntaxKind.BinaryExpression:
return getAssignedTypeOfBinaryExpression(<BinaryExpression>parent);
case SyntaxKind.DeleteExpression:
@ -8675,7 +8676,8 @@ namespace ts {
return stringType;
}
if (node.parent.parent.kind === SyntaxKind.ForOfStatement) {
return checkRightHandSideOfForOf((<ForOfStatement>node.parent.parent).expression) || unknownType;
const isForAwaitOf = (<ForOfStatement>node.parent.parent).awaitKeyword !== undefined;
return checkRightHandSideOfForOf((<ForOfStatement>node.parent.parent).expression, isForAwaitOf) || unknownType;
}
return unknownType;
}
@ -16667,7 +16669,7 @@ namespace ts {
}
else {
const varExpr = <Expression>node.initializer;
const iteratedType = checkRightHandSideOfForOf(node.expression);
const iteratedType = checkRightHandSideOfForOf(node.expression, node.awaitKeyword !== undefined);
// There may be a destructuring assignment on the left side
if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) {
@ -16754,9 +16756,11 @@ namespace ts {
}
}
function checkRightHandSideOfForOf(rhsExpression: Expression): Type {
function checkRightHandSideOfForOf(rhsExpression: Expression, isForAwaitOf: boolean): Type {
const expressionType = checkNonNullExpression(rhsExpression);
return checkIteratedTypeOrElementType(expressionType, rhsExpression, /*allowStringInput*/ true);
return isForAwaitOf
? checkIteratedTypeOfIterableOrAsyncIterable(expressionType, rhsExpression)
: checkIteratedTypeOrElementType(expressionType, rhsExpression, /*allowStringInput*/ true);
}
function checkIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean): Type {
@ -19327,7 +19331,7 @@ namespace ts {
// for ( { a } of elems) {
// }
if (expr.parent.kind === SyntaxKind.ForOfStatement) {
const iteratedType = checkRightHandSideOfForOf((<ForOfStatement>expr.parent).expression);
const iteratedType = checkRightHandSideOfForOf((<ForOfStatement>expr.parent).expression, (<ForOfStatement>expr.parent).awaitKeyword !== undefined);
return checkDestructuringAssignment(expr, iteratedType || unknownType);
}
// If this is from "for" initializer
@ -20794,6 +20798,12 @@ namespace ts {
return true;
}
if (forInOrOfStatement.kind === SyntaxKind.ForOfStatement && forInOrOfStatement.awaitKeyword) {
if ((forInOrOfStatement.flags & NodeFlags.AwaitContext) === NodeFlags.None) {
return grammarErrorOnNode(forInOrOfStatement.awaitKeyword, Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator);
}
}
if (forInOrOfStatement.initializer.kind === SyntaxKind.VariableDeclarationList) {
const variableList = <VariableDeclarationList>forInOrOfStatement.initializer;
if (!checkGrammarVariableDeclarationList(variableList)) {

View File

@ -264,7 +264,7 @@ namespace ts {
"es6": ScriptTarget.ES2015,
"es2015": ScriptTarget.ES2015,
"es2016": ScriptTarget.ES2016,
"es2017": ScriptTarget.ES2017,
"es2017": ScriptTarget.ES2017
}),
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015,
paramType: Diagnostics.VERSION,
@ -428,7 +428,7 @@ namespace ts {
"es2015.symbol.wellknown": "lib.es2015.symbol.wellknown.d.ts",
"es2016.array.include": "lib.es2016.array.include.d.ts",
"es2017.object": "lib.es2017.object.d.ts",
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts"
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts",
}),
},
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon

View File

@ -291,14 +291,18 @@
"category": "Error",
"code": 1102
},
"A 'continue' statement can only be used within an enclosing iteration statement.": {
"A 'for-await-of' statement is only allowed within an async function or async generator.": {
"category": "Error",
"code": 1104
},
"A 'break' statement can only be used within an enclosing iteration or switch statement.": {
"A 'continue' statement can only be used within an enclosing iteration statement.": {
"category": "Error",
"code": 1105
},
"A 'break' statement can only be used within an enclosing iteration or switch statement.": {
"category": "Error",
"code": 1106
},
"Jump target cannot cross function boundary.": {
"category": "Error",
"code": 1107

View File

@ -1341,6 +1341,7 @@ namespace ts {
function emitForOfStatement(node: ForOfStatement) {
const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos);
write(" ");
emitWithSuffix(node.awaitKeyword, " ");
writeToken(SyntaxKind.OpenParenToken, openParenPos);
emitForBinding(node.initializer);
write(" of ");

View File

@ -280,9 +280,9 @@ namespace ts {
return node;
}
export function updateMethod(node: MethodDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
return updateNode(createMethod(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
export function updateMethod(node: MethodDeclaration, decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
if (node.decorators !== decorators || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
return updateNode(createMethod(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
}
return node;
}
@ -525,9 +525,9 @@ namespace ts {
return node;
}
export function updateFunctionExpression(node: FunctionExpression, modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
if (node.name !== name || node.modifiers !== modifiers || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
return updateNode(createFunctionExpression(modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
export function updateFunctionExpression(node: FunctionExpression, modifiers: Modifier[], asteriskToken: AsteriskToken, name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
if (node.modifiers !== modifiers || node.asteriskToken !== asteriskToken || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
return updateNode(createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
}
return node;
}
@ -1068,9 +1068,9 @@ namespace ts {
return node;
}
export function updateFunctionDeclaration(node: FunctionDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
return updateNode(createFunctionDeclaration(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
export function updateFunctionDeclaration(node: FunctionDeclaration, decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
if (node.decorators !== decorators || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) {
return updateNode(createFunctionDeclaration(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node), node);
}
return node;
}
@ -1825,6 +1825,28 @@ namespace ts {
return node;
}
export function createForOfBindingStatement(node: ForInitializer, boundValue: Expression): Statement {
if (isVariableDeclarationList(node)) {
const firstDeclaration = firstOrUndefined(node.declarations);
const updatedDeclaration = updateVariableDeclaration(
firstDeclaration,
firstDeclaration.name,
/*typeNode*/ undefined,
boundValue
);
return createVariableStatement(
/*modifiers*/ undefined,
updateVariableDeclarationList(node, [updatedDeclaration]),
/*location*/ node
);
}
else {
const expression = node;
const updatedExpression = createAssignment(expression, boundValue, /*location*/ expression);
return createStatement(updatedExpression, /*location*/ expression);
}
}
export interface CallBinding {
target: LeftHandSideExpression;
thisArg: Expression;

View File

@ -233,7 +233,8 @@ namespace ts {
visitNode(cbNode, (<ForInStatement>node).expression) ||
visitNode(cbNode, (<ForInStatement>node).statement);
case SyntaxKind.ForOfStatement:
return visitNode(cbNode, (<ForOfStatement>node).initializer) ||
return visitNode(cbNode, (<ForOfStatement>node).awaitKeyword) ||
visitNode(cbNode, (<ForOfStatement>node).initializer) ||
visitNode(cbNode, (<ForOfStatement>node).expression) ||
visitNode(cbNode, (<ForOfStatement>node).statement);
case SyntaxKind.ContinueStatement:
@ -4362,6 +4363,7 @@ namespace ts {
function parseForOrForInOrForOfStatement(): Statement {
const pos = getNodePos();
parseExpected(SyntaxKind.ForKeyword);
const awaitKeyword = parseOptionalToken(SyntaxKind.AwaitKeyword);
parseExpected(SyntaxKind.OpenParenToken);
let initializer: VariableDeclarationList | Expression = undefined;
@ -4374,20 +4376,21 @@ namespace ts {
}
}
let forOrForInOrForOfStatement: IterationStatement;
if (parseOptional(SyntaxKind.InKeyword)) {
if (awaitKeyword ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {
const forOfStatement = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, pos);
forOfStatement.awaitKeyword = awaitKeyword;
forOfStatement.initializer = initializer;
forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher);
parseExpected(SyntaxKind.CloseParenToken);
forOrForInOrForOfStatement = forOfStatement;
}
else if (parseOptional(SyntaxKind.InKeyword)) {
const forInStatement = <ForInStatement>createNode(SyntaxKind.ForInStatement, pos);
forInStatement.initializer = initializer;
forInStatement.expression = allowInAnd(parseExpression);
parseExpected(SyntaxKind.CloseParenToken);
forOrForInOrForOfStatement = forInStatement;
}
else if (parseOptional(SyntaxKind.OfKeyword)) {
const forOfStatement = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, pos);
forOfStatement.initializer = initializer;
forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher);
parseExpected(SyntaxKind.CloseParenToken);
forOrForInOrForOfStatement = forOfStatement;
}
else {
const forStatement = <ForStatement>createNode(SyntaxKind.ForStatement, pos);
forStatement.initializer = initializer;

View File

@ -1529,6 +1529,7 @@ namespace ts {
return updateFunctionExpression(
node,
/*modifiers*/ undefined,
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
@ -1549,6 +1550,7 @@ namespace ts {
node,
/*decorators*/ undefined,
node.modifiers,
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),

View File

@ -175,8 +175,17 @@ namespace ts {
const iteratorRecord = isIdentifier(node.expression)
? getGeneratedNameForNode(node.expression)
: createUniqueName("iterator");
const expression = visitNode(node.expression, visitor, isExpression);
const statements: Statement[] = [];
const binding = createForOfBindingStatement(
node.initializer,
createPropertyAccess(
createPropertyAccess(iteratorRecord, "result"),
"value"
)
);
statements.push(visitNode(binding, visitor, isStatement));
const statement = visitNode(node.statement, visitor, isStatement);
if (isBlock(statement)) {
addRange(statements, statement.statements);
@ -330,6 +339,7 @@ namespace ts {
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, visitor, isModifier),
enclosingFunctionFlags & FunctionFlags.Async ? undefined : node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
@ -359,6 +369,7 @@ namespace ts {
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, visitor, isModifier),
enclosingFunctionFlags & FunctionFlags.Async ? undefined : node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
@ -387,6 +398,7 @@ namespace ts {
const updated = updateFunctionExpression(
node,
visitNodes(node.modifiers, visitor, isModifier),
enclosingFunctionFlags & FunctionFlags.Async ? undefined : node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),

View File

@ -675,6 +675,7 @@ namespace ts {
node,
node.decorators,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
visitNodes(node.parameters, destructuringVisitor, isParameterDeclaration),

View File

@ -2028,6 +2028,7 @@ namespace ts {
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
visitPropertyNameOfClassElement(node),
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
@ -2132,6 +2133,7 @@ namespace ts {
node,
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
@ -2161,6 +2163,7 @@ namespace ts {
const updated = updateFunctionExpression(
node,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),

View File

@ -520,6 +520,7 @@ namespace ts {
export type EqualsGreaterThanToken = Token<SyntaxKind.EqualsGreaterThanToken>;
export type EndOfFileToken = Token<SyntaxKind.EndOfFileToken>;
export type AtToken = Token<SyntaxKind.AtToken>;
export type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
export type Modifier
= Token<SyntaxKind.AbstractKeyword>
@ -658,14 +659,14 @@ namespace ts {
export interface PropertySignature extends TypeElement {
kind: SyntaxKind.PropertySignature | SyntaxKind.JSDocRecordMember;
name: PropertyName; // Declared property name
questionToken?: QuestionToken; // Present on optional property
questionToken?: QuestionToken; // Present on optional property
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
export interface PropertyDeclaration extends ClassElement {
kind: SyntaxKind.PropertyDeclaration;
questionToken?: QuestionToken; // Present for use with reporting a grammar error
questionToken?: QuestionToken; // Present for use with reporting a grammar error
name: PropertyName;
type?: TypeNode;
initializer?: Expression; // Optional initializer
@ -1563,7 +1564,7 @@ namespace ts {
export interface ForOfStatement extends IterationStatement {
kind: SyntaxKind.ForOfStatement;
awaitKeyword?: Token<SyntaxKind.AwaitKeyword>;
awaitKeyword?: AwaitKeywordToken;
initializer: ForInitializer;
expression: Expression;
}

View File

@ -4220,7 +4220,6 @@ namespace ts {
return "lib.es2016.d.ts";
case ScriptTarget.ES2015:
return "lib.es6.d.ts";
default:
return "lib.d.ts";
}

View File

@ -761,6 +761,7 @@ namespace ts {
return updateMethod(<MethodDeclaration>node,
visitNodes((<MethodDeclaration>node).decorators, visitor, isDecorator),
visitNodes((<MethodDeclaration>node).modifiers, visitor, isModifier),
(<MethodDeclaration>node).asteriskToken,
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
visitNodes((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<MethodDeclaration>node).parameters, visitor, context),
@ -849,6 +850,7 @@ namespace ts {
case SyntaxKind.FunctionExpression:
return updateFunctionExpression(<FunctionExpression>node,
visitNodes((<FunctionExpression>node).modifiers, visitor, isModifier),
(<FunctionExpression>node).asteriskToken,
visitNode((<FunctionExpression>node).name, visitor, isPropertyName),
visitNodes((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<FunctionExpression>node).parameters, visitor, context),
@ -1030,6 +1032,7 @@ namespace ts {
return updateFunctionDeclaration(<FunctionDeclaration>node,
visitNodes((<FunctionDeclaration>node).decorators, visitor, isDecorator),
visitNodes((<FunctionDeclaration>node).modifiers, visitor, isModifier),
(<FunctionDeclaration>node).asteriskToken,
visitNode((<FunctionDeclaration>node).name, visitor, isPropertyName),
visitNodes((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context),

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

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

2
src/lib/esnext.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
/// <reference path="lib.es2017.d.ts" />
/// <reference path="lib.esnext.asynciterable.d.ts" />