diff --git a/Jakefile.js b/Jakefile.js index 9249f13a3c4..fc2b6359355 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -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) { diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2d7134c3854..91630fbc53b 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -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); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b5670f91f65..ffea8491bf6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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((declaration.parent.parent).expression) || anyType; + const isForAwaitOf = (declaration.parent.parent).awaitKeyword !== undefined; + return checkRightHandSideOfForOf((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((parent).expression) || unknownType; + return checkRightHandSideOfForOf((parent).expression, (parent).awaitKeyword !== undefined) || unknownType; case SyntaxKind.BinaryExpression: return getAssignedTypeOfBinaryExpression(parent); case SyntaxKind.DeleteExpression: @@ -8675,7 +8676,8 @@ namespace ts { return stringType; } if (node.parent.parent.kind === SyntaxKind.ForOfStatement) { - return checkRightHandSideOfForOf((node.parent.parent).expression) || unknownType; + const isForAwaitOf = (node.parent.parent).awaitKeyword !== undefined; + return checkRightHandSideOfForOf((node.parent.parent).expression, isForAwaitOf) || unknownType; } return unknownType; } @@ -16667,7 +16669,7 @@ namespace ts { } else { const varExpr = 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((expr.parent).expression); + const iteratedType = checkRightHandSideOfForOf((expr.parent).expression, (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 = forInOrOfStatement.initializer; if (!checkGrammarVariableDeclarationList(variableList)) { diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 50399fd5c38..f2b239057f2 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -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 diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ae61d48fd6d..fe42a589120 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -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 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index baf5fc7c422..19cd521581c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -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 "); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index f7696841462..7d183087444 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -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; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 92a3dcbef11..189ae7f05e7 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -233,7 +233,8 @@ namespace ts { visitNode(cbNode, (node).expression) || visitNode(cbNode, (node).statement); case SyntaxKind.ForOfStatement: - return visitNode(cbNode, (node).initializer) || + return visitNode(cbNode, (node).awaitKeyword) || + visitNode(cbNode, (node).initializer) || visitNode(cbNode, (node).expression) || visitNode(cbNode, (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 = 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 = createNode(SyntaxKind.ForInStatement, pos); forInStatement.initializer = initializer; forInStatement.expression = allowInAnd(parseExpression); parseExpected(SyntaxKind.CloseParenToken); forOrForInOrForOfStatement = forInStatement; } - else if (parseOptional(SyntaxKind.OfKeyword)) { - const forOfStatement = createNode(SyntaxKind.ForOfStatement, pos); - forOfStatement.initializer = initializer; - forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher); - parseExpected(SyntaxKind.CloseParenToken); - forOrForInOrForOfStatement = forOfStatement; - } else { const forStatement = createNode(SyntaxKind.ForStatement, pos); forStatement.initializer = initializer; diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index a3347872ff5..65e3a24674e 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -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), diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 2e69677ce24..b8842588ca4 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -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), diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index c9e6a4fa5c6..0e16e7ef67a 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -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), diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index a3338786c3e..a570b172e98 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -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), diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 78a0ba0530c..cf42271e81c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -520,6 +520,7 @@ namespace ts { export type EqualsGreaterThanToken = Token; export type EndOfFileToken = Token; export type AtToken = Token; + export type AwaitKeywordToken = Token; export type Modifier = Token @@ -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; + awaitKeyword?: AwaitKeywordToken; initializer: ForInitializer; expression: Expression; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 3fa797426c3..5d804887c90 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4220,7 +4220,6 @@ namespace ts { return "lib.es2016.d.ts"; case ScriptTarget.ES2015: return "lib.es6.d.ts"; - default: return "lib.d.ts"; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 05e65aa251d..2d15b650f97 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -761,6 +761,7 @@ namespace ts { return updateMethod(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), + (node).asteriskToken, visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), visitParameterList((node).parameters, visitor, context), @@ -849,6 +850,7 @@ namespace ts { case SyntaxKind.FunctionExpression: return updateFunctionExpression(node, visitNodes((node).modifiers, visitor, isModifier), + (node).asteriskToken, visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), visitParameterList((node).parameters, visitor, context), @@ -1030,6 +1032,7 @@ namespace ts { return updateFunctionDeclaration(node, visitNodes((node).decorators, visitor, isDecorator), visitNodes((node).modifiers, visitor, isModifier), + (node).asteriskToken, visitNode((node).name, visitor, isPropertyName), visitNodes((node).typeParameters, visitor, isTypeParameter), visitParameterList((node).parameters, visitor, context), diff --git a/src/lib/es2017.d.ts b/src/lib/es2017.d.ts index a4145fb5cbf..13f9d93f444 100644 --- a/src/lib/es2017.d.ts +++ b/src/lib/es2017.d.ts @@ -1,4 +1,3 @@ /// /// -/// -/// \ No newline at end of file +/// \ No newline at end of file diff --git a/src/lib/es2017.asynciterable.d.ts b/src/lib/esnext.asynciterable.d.ts similarity index 100% rename from src/lib/es2017.asynciterable.d.ts rename to src/lib/esnext.asynciterable.d.ts diff --git a/src/lib/esnext.d.ts b/src/lib/esnext.d.ts new file mode 100644 index 00000000000..71fab82a866 --- /dev/null +++ b/src/lib/esnext.d.ts @@ -0,0 +1,2 @@ +/// +///