Skip to content

Commit 28d23ce

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

20 files changed

+223
-169
lines changed
 

‎src/compiler/binder.ts

+19-5
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

+107-99
Large diffs are not rendered by default.

‎src/compiler/diagnosticMessages.json

+10-2
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

+1-1
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

+15-8
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

+4-4
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

+1
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

+9-9
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

+1
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

+2-2
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.");

‎src/compiler/transformers/module/system.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,7 @@ namespace ts {
12611261

12621262
node = updateForOf(
12631263
node,
1264+
node.modifierToken,
12641265
visitForInitializer(node.initializer),
12651266
visitNode(node.expression, destructuringVisitor, isExpression),
12661267
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock)

‎src/compiler/transformers/ts.ts

+30
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,9 @@ namespace ts {
464464
// TypeScript namespace or external module import.
465465
return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
466466

467+
case SyntaxKind.ForOfStatement:
468+
return visitForOfStatement(<ForOfStatement>node);
469+
467470
default:
468471
Debug.failBadSyntaxKind(node);
469472
return visitEachChild(node, visitor, context);
@@ -2218,6 +2221,33 @@ namespace ts {
22182221
return parameter;
22192222
}
22202223

2224+
function visitForOfStatement(node: ForOfStatement): Statement {
2225+
if (getForOfModifierKind(node) !== SyntaxKind.EachKeyword) {
2226+
return visitEachChild(node, visitor, context);
2227+
}
2228+
2229+
const counter = createLoopVariable();
2230+
const rhsReference = node.expression.kind === SyntaxKind.Identifier
2231+
? createUniqueName((<Identifier>node.expression).text)
2232+
: createTempVariable(/*recordTempVariable*/ undefined);
2233+
const binding = createForOfBindingStatement(node.initializer, createElementAccess(rhsReference, counter));
2234+
const newNode = createFor(
2235+
createVariableDeclarationList([
2236+
createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)),
2237+
createVariableDeclaration(rhsReference, /*type*/ undefined, node.expression, /*location*/ node.expression)
2238+
]),
2239+
createLessThan(
2240+
counter,
2241+
createPropertyAccess(rhsReference, "length"),
2242+
/*location*/ node.expression
2243+
),
2244+
createPostfixIncrement(counter, /*location*/ node.expression),
2245+
insertLeadingStatement(node.statement, binding)
2246+
);
2247+
2248+
return visitNode(newNode, visitor, isStatement);
2249+
}
2250+
22212251
/**
22222252
* Visits a variable statement in a namespace.
22232253
*

‎src/compiler/types.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ namespace ts {
166166
BooleanKeyword,
167167
ConstructorKeyword,
168168
DeclareKeyword,
169+
EachKeyword,
169170
GetKeyword,
170171
IsKeyword,
171172
KeyOfKeyword,
@@ -519,6 +520,7 @@ namespace ts {
519520
export type AtToken = Token<SyntaxKind.AtToken>;
520521
export type ReadonlyToken = Token<SyntaxKind.ReadonlyKeyword>;
521522
export type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
523+
export type EachKeywordToken = Token<SyntaxKind.EachKeyword>;
522524

523525
export type Modifier
524526
= Token<SyntaxKind.AbstractKeyword>
@@ -1617,7 +1619,7 @@ namespace ts {
16171619

16181620
export interface ForOfStatement extends IterationStatement {
16191621
kind: SyntaxKind.ForOfStatement;
1620-
awaitKeyword?: AwaitKeywordToken;
1622+
modifierToken?: AwaitKeywordToken | EachKeywordToken;
16211623
initializer: ForInitializer;
16221624
expression: Expression;
16231625
}

‎src/compiler/utilities.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,11 @@ namespace ts {
874874
return false;
875875
}
876876

877+
export function getForOfModifierKind(node: ForOfStatement) {
878+
return node.modifierToken
879+
&& node.modifierToken.kind;
880+
}
881+
877882
export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement {
878883
switch (node.kind) {
879884
case SyntaxKind.ForStatement:
@@ -3668,10 +3673,6 @@ namespace ts {
36683673
return node.symbol && getDeclarationOfKind(node.symbol, kind) === node;
36693674
}
36703675

3671-
export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) {
3672-
return isExternalModule(node) || compilerOptions.isolatedModules;
3673-
}
3674-
36753676
// Node tests
36763677
//
36773678
// All node tests in the following list should *not* reference parent pointers so that

‎src/compiler/visitor.ts

+1
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,7 @@ namespace ts {
989989

990990
case SyntaxKind.ForOfStatement:
991991
return updateForOf(<ForOfStatement>node,
992+
(<ForOfStatement>node).modifierToken,
992993
visitNode((<ForOfStatement>node).initializer, visitor, isForInitializer),
993994
visitNode((<ForOfStatement>node).expression, visitor, isExpression),
994995
visitNode((<ForOfStatement>node).statement, visitor, isStatement, /*optional*/ false, liftToBlock));

‎src/lib/es2015.iterable.d.ts

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ interface SymbolConstructor {
88
readonly iterator: symbol;
99
}
1010

11+
interface IteratorResult<T> {
12+
done: boolean;
13+
value: T;
14+
}
15+
16+
interface Iterator<T> {
17+
next(value?: any): IteratorResult<T>;
18+
return?(value?: any): IteratorResult<T>;
19+
throw?(e?: any): IteratorResult<T>;
20+
}
21+
1122
interface Iterable<T> {
1223
[Symbol.iterator](): Iterator<T>;
1324
}

‎src/lib/esnext.asynciterable.d.ts ‎src/lib/es2017.asynciterable.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/// <reference path="lib.es2015.symbol.d.ts" />
2+
/// <reference path="lib.es2015.iterable.d.ts" />
23

34
interface SymbolConstructor {
45
/**

‎src/lib/es2017.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/// <reference path="lib.es2017.object.d.ts" />
33
/// <reference path="lib.es2017.sharedmemory.d.ts" />
44
/// <reference path="lib.es2017.string.d.ts" />
5+
/// <reference path="lib.es2017.asynciterable.d.ts" />

0 commit comments

Comments
 (0)