Skip to content

Commit 28d23ce

Browse files
committed
Add for-await-of, always use Symbol for iterables.
1 parent d6a5e39 commit 28d23ce

20 files changed

Lines changed: 223 additions & 169 deletions

src/compiler/binder.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ namespace ts {
954954
addAntecedent(preLoopLabel, currentFlow);
955955
currentFlow = preLoopLabel;
956956
if (node.kind === SyntaxKind.ForOfStatement) {
957-
bind(node.awaitKeyword);
957+
bind(node.modifierToken);
958958
}
959959
bind(node.expression);
960960
addAntecedent(postLoopLabel, currentFlow);
@@ -3125,9 +3125,13 @@ namespace ts {
31253125
break;
31263126

31273127
case SyntaxKind.ForOfStatement:
3128-
// for-of might be ESNext if it has a rest destructuring
3129-
transformFlags |= TransformFlags.AssertESNext;
3130-
// FALLTHROUGH
3128+
if ((<ForOfStatement>node).modifierToken) {
3129+
transformFlags |= TransformFlags.AssertES2017;
3130+
}
3131+
3132+
transformFlags |= TransformFlags.AssertES2015;
3133+
break;
3134+
31313135
case SyntaxKind.NoSubstitutionTemplateLiteral:
31323136
case SyntaxKind.TemplateHead:
31333137
case SyntaxKind.TemplateMiddle:
@@ -3142,7 +3146,17 @@ namespace ts {
31423146

31433147
case SyntaxKind.ForOfStatement:
31443148
// This node is either ES2015 syntax or ES2017 syntax (if it is a for-await-of).
3145-
transformFlags |= (<ForOfStatement>node).awaitKeyword ? TransformFlags.AssertES2017 : TransformFlags.AssertES2015;
3149+
switch (getForOfModifierKind(<ForOfStatement>node)) {
3150+
case SyntaxKind.AwaitKeyword:
3151+
transformFlags |= TransformFlags.AssertES2017;
3152+
break;
3153+
case SyntaxKind.EachKeyword:
3154+
transformFlags |= TransformFlags.AssertTypeScript;
3155+
break;
3156+
default:
3157+
transformFlags |= TransformFlags.AssertES2015;
3158+
break;
3159+
}
31463160
break;
31473161

31483162
case SyntaxKind.YieldExpression:

src/compiler/checker.ts

Lines changed: 107 additions & 99 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,7 @@
14631463
"category": "Error",
14641464
"code": 2460
14651465
},
1466-
"Type '{0}' is not an array type or does not have an '__iterator__()' method that returns an iterator.": {
1466+
"Type '{0}' is not an array type.": {
14671467
"category": "Error",
14681468
"code": 2461
14691469
},
@@ -1587,7 +1587,7 @@
15871587
"category": "Error",
15881588
"code": 2494
15891589
},
1590-
"Type '{0}' is not an array type or a string type or does not have an '__iterator__()' method that returns an iterator.": {
1590+
"Type '{0}' is not an array type or a string type.": {
15911591
"category": "Error",
15921592
"code": 2495
15931593
},
@@ -1783,6 +1783,14 @@
17831783
"category": "Error",
17841784
"code": 2543
17851785
},
1786+
"Type '{0}' is not an array type or does not have a '[Symbol.iterator]()' method that returns an iterator.": {
1787+
"category": "Error",
1788+
"code": 2544
1789+
},
1790+
"Type '{0}' is not an array type or a string type or does not have a '[Symbol.iterator]()' method that returns an iterator.": {
1791+
"category": "Error",
1792+
"code": 2545
1793+
},
17861794
"JSX element attributes type '{0}' may not be a union type.": {
17871795
"category": "Error",
17881796
"code": 2600

src/compiler/emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1368,7 +1368,7 @@ namespace ts {
13681368
function emitForOfStatement(node: ForOfStatement) {
13691369
const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos);
13701370
write(" ");
1371-
emitWithSuffix(node.awaitKeyword, " ");
1371+
emitWithSuffix(node.modifierToken, " ");
13721372
writeToken(SyntaxKind.OpenParenToken, openParenPos);
13731373
emitForBinding(node.initializer);
13741374
write(" of ");

src/compiler/factory.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -926,17 +926,18 @@ namespace ts {
926926
return node;
927927
}
928928

929-
export function createForOf(initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) {
929+
export function createForOf(modifierToken: AwaitKeywordToken | EachKeywordToken, initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) {
930930
const node = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, location);
931+
node.modifierToken = modifierToken;
931932
node.initializer = initializer;
932933
node.expression = expression;
933934
node.statement = statement;
934935
return node;
935936
}
936937

937-
export function updateForOf(node: ForOfStatement, initializer: ForInitializer, expression: Expression, statement: Statement) {
938-
if (node.initializer !== initializer || node.expression !== expression || node.statement !== statement) {
939-
return updateNode(createForOf(initializer, expression, statement, node), node);
938+
export function updateForOf(node: ForOfStatement, modifierToken: AwaitKeywordToken | EachKeywordToken, initializer: ForInitializer, expression: Expression, statement: Statement) {
939+
if (node.modifierToken !== modifierToken || node.initializer !== initializer || node.expression !== expression || node.statement !== statement) {
940+
return updateNode(createForOf(modifierToken, initializer, expression, statement, node), node);
940941
}
941942
return node;
942943
}
@@ -1768,7 +1769,7 @@ namespace ts {
17681769
scoped: false,
17691770
text: `
17701771
var __values = (this && this.__values) || function (o) {
1771-
var i = o.__iterator__ || 0, d;
1772+
var i = typeof Symbol === "function" && o[Symbol.iterator] || 0, d;
17721773
return i ? i.call(o) : { next: function () { return { done: d = d || i >= o.length, value: d ? void 0 : o[i++] }; } };
17731774
};`
17741775
};
@@ -1827,7 +1828,7 @@ namespace ts {
18271828
scoped: false,
18281829
text: `
18291830
var __read = (this && this.__read) || function (o, n) {
1830-
if (!(m = o.__iterator__)) return o;
1831+
if (!(m = typeof Symbol === "function" && o[Symbol.iterator])) return o;
18311832
var m, i = m.call(o), ar = [], r, e;
18321833
try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); }
18331834
catch (error) { e = { error: error }; }
@@ -1906,8 +1907,14 @@ namespace ts {
19061907
}
19071908
}
19081909

1909-
1910-
// Utilities
1910+
export function insertLeadingStatement(dest: Statement, source: Statement) {
1911+
if (isBlock(dest)) {
1912+
return updateBlock(dest, createNodeArray([source, ...dest.statements], dest.statements));
1913+
}
1914+
else {
1915+
return createBlock(createNodeArray([dest, source]), /*location*/ undefined, /*multiLine*/ true);
1916+
}
1917+
}
19111918

19121919
export interface CallBinding {
19131920
target: LeftHandSideExpression;

src/compiler/parser.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ namespace ts {
240240
visitNode(cbNode, (<ForInStatement>node).expression) ||
241241
visitNode(cbNode, (<ForInStatement>node).statement);
242242
case SyntaxKind.ForOfStatement:
243-
return visitNode(cbNode, (<ForOfStatement>node).awaitKeyword) ||
243+
return visitNode(cbNode, (<ForOfStatement>node).modifierToken) ||
244244
visitNode(cbNode, (<ForOfStatement>node).initializer) ||
245245
visitNode(cbNode, (<ForOfStatement>node).expression) ||
246246
visitNode(cbNode, (<ForOfStatement>node).statement);
@@ -4427,7 +4427,7 @@ namespace ts {
44274427
function parseForOrForInOrForOfStatement(): Statement {
44284428
const pos = getNodePos();
44294429
parseExpected(SyntaxKind.ForKeyword);
4430-
const awaitKeyword = parseOptionalToken(SyntaxKind.AwaitKeyword);
4430+
const modifierToken = parseOptionalToken(SyntaxKind.AwaitKeyword) || parseOptionalToken(SyntaxKind.EachKeyword);
44314431
parseExpected(SyntaxKind.OpenParenToken);
44324432

44334433
let initializer: VariableDeclarationList | Expression = undefined;
@@ -4440,9 +4440,9 @@ namespace ts {
44404440
}
44414441
}
44424442
let forOrForInOrForOfStatement: IterationStatement;
4443-
if (awaitKeyword ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {
4443+
if (modifierToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {
44444444
const forOfStatement = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, pos);
4445-
forOfStatement.awaitKeyword = awaitKeyword;
4445+
forOfStatement.modifierToken = modifierToken;
44464446
forOfStatement.initializer = initializer;
44474447
forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher);
44484448
parseExpected(SyntaxKind.CloseParenToken);

src/compiler/scanner.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ namespace ts {
126126
"yield": SyntaxKind.YieldKeyword,
127127
"async": SyntaxKind.AsyncKeyword,
128128
"await": SyntaxKind.AwaitKeyword,
129+
"each": SyntaxKind.EachKeyword,
129130
"of": SyntaxKind.OfKeyword,
130131
"{": SyntaxKind.OpenBraceToken,
131132
"}": SyntaxKind.CloseBraceToken,

src/compiler/transformers/es2017.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,15 @@ namespace ts {
154154
function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
155155
const enclosedStatement = getEnclosedStatement(node);
156156
if (enclosedStatement.statement.kind === SyntaxKind.ForOfStatement &&
157-
(<ForOfStatement>enclosedStatement.statement).awaitKeyword) {
157+
(<ForOfStatement>enclosedStatement.statement).modifierToken) {
158158
return visitForOfStatement(<ForOfStatement>node.statement, enclosedStatement.enclosingLabeledStatements);
159159
}
160160

161161
return restoreEnclosingLabels(visitEachChild(node, visitor, context), enclosedStatement.enclosingLabeledStatements);
162162
}
163163

164164
function visitForOfStatement(node: ForOfStatement, enclosingLabeledStatements: LabeledStatement[]): VisitResult<Statement> {
165-
if (!node.awaitKeyword) return visitEachChild(node, visitor, context);
165+
if (!node.modifierToken) return visitEachChild(node, visitor, context);
166166

167167
let bodyLocation: TextRange;
168168
let statementsLocation: TextRange;
@@ -774,8 +774,8 @@ namespace ts {
774774
scoped: false,
775775
text: `
776776
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
777-
var g = generator.apply(thisArg, _arguments || []), q = [], c;
778-
return { next: verb("next"), "throw": verb("throw"), "return": verb("return"), __asyncIterator__: function () { return this; } };
777+
var g = generator.apply(thisArg, _arguments || []), q = [], c, i;
778+
return i = { next: verb("next"), "throw": verb("throw"), "return": verb("return") }, i[Symbol.asyncIterator] = function () { return this; }, i;
779779
function verb(n) { return function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]), next(); }); }; }
780780
function next() { if (!c && q.length) resume((c = q.shift())[0], c[1]); }
781781
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(c[3], e); } }
@@ -808,9 +808,9 @@ namespace ts {
808808
name: "typescript:asyncValues",
809809
scoped: false,
810810
text: `
811-
var __asyncValues = (this && this.__asyncIterator) || function (o, iterator) {
812-
var m;
813-
return (m = o.__asyncIterator__) ? m.call(o) : typeof __values === "function" ? __values(o) : o[iterator || Symbol.iterator]();
811+
var __asyncValues = (this && this.__asyncIterator) || function (o) {
812+
var m = o[Symbol.asyncIterator];
813+
return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator]();
814814
};`
815815
};
816816

@@ -832,9 +832,9 @@ namespace ts {
832832
name: "typescript:asyncDelegator",
833833
scoped: false,
834834
text: `
835-
var __asyncDelegator = (this && this.__asyncDelegator) || function (o, iterator) {
835+
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
836836
var i = { next: verb("next"), "throw": verb("throw", function (e) { throw e; }), "return": verb("return", function (v) { return { value: v, done: true }; }) };
837-
return o = __asyncValues(o, iterator), i[iterator || Symbol.iterator] = function () { return this; }, i;
837+
return o = __asyncValues(o), i[Symbol.iterator] = function () { return this; }, i;
838838
function verb(n, f) { return function (v) { return { value: ["delegate", (o[n] || f).call(o, v)], done: false }; }; }
839839
};`
840840
};

src/compiler/transformers/esnext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ namespace ts {
234234
: createBlock(append(leadingStatements, statement), statement, /*multiLine*/ true);
235235
return updateForOf(
236236
node,
237+
node.modifierToken,
237238
createVariableDeclarationList(
238239
[
239240
createVariableDeclaration(temp, /*type*/ undefined, /*initializer*/ undefined, node.initializer)

src/compiler/transformers/generators.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3169,8 +3169,8 @@ namespace ts {
31693169
priority: 6,
31703170
text: `
31713171
var __generator = (this && this.__generator) || function (thisArg, body) {
3172-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
3173-
return { next: verb(0), "throw": verb(1), "return": verb(2), __iterator__: function () { return this; } };
3172+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
3173+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
31743174
function verb(n) { return function (v) { return step([n, v]); }; }
31753175
function step(op) {
31763176
if (f) throw new TypeError("Generator is already executing.");

0 commit comments

Comments
 (0)