@@ -111,6 +111,7 @@ module ts {
111
111
let globalTemplateStringsArrayType: ObjectType;
112
112
let globalESSymbolType: ObjectType;
113
113
let globalIterableType: GenericType;
114
+ let globalIteratorType: GenericType;
114
115
let globalIterableIteratorType: GenericType;
115
116
116
117
let anyArrayType: Type;
@@ -2119,7 +2120,7 @@ module ts {
2119
2120
// checkRightHandSideOfForOf will return undefined if the for-of expression type was
2120
2121
// missing properties/signatures required to get its iteratedType (like
2121
2122
// [Symbol.iterator] or next). This may be because we accessed properties from anyType,
2122
- // or it may have led to an error inside getIteratedType .
2123
+ // or it may have led to an error inside getElementTypeFromIterable .
2123
2124
return checkRightHandSideOfForOf((<ForOfStatement>declaration.parent.parent).expression) || anyType;
2124
2125
}
2125
2126
if (isBindingPattern(declaration.parent)) {
@@ -5854,7 +5855,7 @@ module ts {
5854
5855
let index = indexOf(arrayLiteral.elements, node);
5855
5856
return getTypeOfPropertyOfContextualType(type, "" + index)
5856
5857
|| getIndexTypeOfContextualType(type, IndexKind.Number)
5857
- || (languageVersion >= ScriptTarget.ES6 ? getIteratedType (type, /*expressionForError*/ undefined) : undefined);
5858
+ || (languageVersion >= ScriptTarget.ES6 ? getElementTypeFromIterable (type, /*expressionForError*/ undefined) : undefined);
5858
5859
}
5859
5860
return undefined;
5860
5861
}
@@ -6041,7 +6042,7 @@ module ts {
6041
6042
// if there is no index type / iterated type.
6042
6043
let restArrayType = checkExpression((<SpreadElementExpression>e).expression, contextualMapper);
6043
6044
let restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
6044
- (languageVersion >= ScriptTarget.ES6 ? getIteratedType (restArrayType, /*expressionForError*/ undefined) : undefined);
6045
+ (languageVersion >= ScriptTarget.ES6 ? getElementTypeFromIterable (restArrayType, /*expressionForError*/ undefined) : undefined);
6045
6046
6046
6047
if (restElementType) {
6047
6048
elementTypes.push(restElementType);
@@ -8188,6 +8189,22 @@ module ts {
8188
8189
break;
8189
8190
}
8190
8191
}
8192
+
8193
+ if (node.type) {
8194
+ if (languageVersion >= ScriptTarget.ES6 && isSyntacticallyValidGenerator(node)) {
8195
+ let returnType = getTypeFromTypeNode(node.type);
8196
+ let generatorElementType = getElementTypeFromIterableIterator(returnType, /*errorNode*/ undefined) || anyType;
8197
+ let iterableIteratorInstantiation = createIterableIteratorType(generatorElementType);
8198
+
8199
+ // Naively, one could check that IterableIterator<any> is assignable to the return type annotation.
8200
+ // However, that would not catch the error in the following case.
8201
+ //
8202
+ // interface BadGenerator extends Iterable<number>, Iterator<string> { }
8203
+ // function* g(): BadGenerator { } // Iterable and Iterator have different types!
8204
+ //
8205
+ checkTypeAssignableTo(iterableIteratorInstantiation, returnType, node.type);
8206
+ }
8207
+ }
8191
8208
}
8192
8209
8193
8210
checkSpecializedSignatureDeclaration(node);
@@ -9385,7 +9402,7 @@ module ts {
9385
9402
// iteratedType will be undefined if the rightType was missing properties/signatures
9386
9403
// required to get its iteratedType (like [Symbol.iterator] or next). This may be
9387
9404
// because we accessed properties from anyType, or it may have led to an error inside
9388
- // getIteratedType .
9405
+ // getElementTypeFromIterable .
9389
9406
if (iteratedType) {
9390
9407
checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined);
9391
9408
}
@@ -9483,30 +9500,24 @@ module ts {
9483
9500
* When errorNode is undefined, it means we should not report any errors.
9484
9501
*/
9485
9502
function checkIteratedType(iterable: Type, errorNode: Node): Type {
9486
- let iteratedType = getIteratedType (iterable, errorNode);
9503
+ let elementType = getElementTypeFromIterable (iterable, errorNode);
9487
9504
// Now even though we have extracted the iteratedType, we will have to validate that the type
9488
9505
// passed in is actually an Iterable.
9489
- if (errorNode && iteratedType ) {
9490
- checkTypeAssignableTo(iterable, createIterableType(iteratedType ), errorNode);
9506
+ if (errorNode && elementType ) {
9507
+ checkTypeAssignableTo(iterable, createIterableType(elementType ), errorNode);
9491
9508
}
9492
9509
9493
- return iteratedType ;
9510
+ return elementType ;
9494
9511
}
9495
9512
9496
- function getIteratedType (iterable: Type, errorNode: Node) {
9513
+ function getElementTypeFromIterable (iterable: Type, errorNode: Node): Type {
9497
9514
Debug.assert(languageVersion >= ScriptTarget.ES6);
9498
9515
// We want to treat type as an iterable, and get the type it is an iterable of. The iterable
9499
9516
// must have the following structure (annotated with the names of the variables below):
9500
9517
//
9501
9518
// { // iterable
9502
9519
// [Symbol.iterator]: { // iteratorFunction
9503
- // (): { // iterator
9504
- // next: { // iteratorNextFunction
9505
- // (): { // iteratorNextResult
9506
- // value: T // iteratorNextValue
9507
- // }
9508
- // }
9509
- // }
9520
+ // (): Iterator<T>
9510
9521
// }
9511
9522
// }
9512
9523
//
@@ -9544,11 +9555,31 @@ module ts {
9544
9555
return undefined;
9545
9556
}
9546
9557
9547
- let iterator = getUnionType(map(iteratorFunctionSignatures, getReturnTypeOfSignature));
9558
+ return getElementTypeFromIterator(getUnionType(map(iteratorFunctionSignatures, getReturnTypeOfSignature)), errorNode);
9559
+ }
9560
+
9561
+ function getElementTypeFromIterator(iterator: Type, errorNode: Node): Type {
9562
+ // This function has very similar logic as getElementTypeFromIterable, except that it operates on
9563
+ // Iterators instead of Iterables. Here is the structure:
9564
+ //
9565
+ // { // iterator
9566
+ // next: { // iteratorNextFunction
9567
+ // (): { // iteratorNextResult
9568
+ // value: T // iteratorNextValue
9569
+ // }
9570
+ // }
9571
+ // }
9572
+ //
9548
9573
if (allConstituentTypesHaveKind(iterator, TypeFlags.Any)) {
9549
9574
return undefined;
9550
9575
}
9551
9576
9577
+ // As an optimization, if the type is instantiated directly using the globalIteratorType (Iterator<number>),
9578
+ // then just grab its type argument.
9579
+ if ((iterator.flags & TypeFlags.Reference) && (<GenericType>iterator).target === globalIteratorType) {
9580
+ return (<GenericType>iterator).typeArguments[0];
9581
+ }
9582
+
9552
9583
let iteratorNextFunction = getTypeOfPropertyOfType(iterator, "next");
9553
9584
if (iteratorNextFunction && allConstituentTypesHaveKind(iteratorNextFunction, TypeFlags.Any)) {
9554
9585
return undefined;
@@ -9578,6 +9609,21 @@ module ts {
9578
9609
return iteratorNextValue;
9579
9610
}
9580
9611
9612
+ function getElementTypeFromIterableIterator(iterableIterator: Type, errorNode: Node): Type {
9613
+ if (allConstituentTypesHaveKind(iterableIterator, TypeFlags.Any)) {
9614
+ return undefined;
9615
+ }
9616
+
9617
+ // As an optimization, if the type is instantiated directly using the globalIterableIteratorType (IterableIterator<number>),
9618
+ // then just grab its type argument.
9619
+ if ((iterableIterator.flags & TypeFlags.Reference) && (<GenericType>iterableIterator).target === globalIterableIteratorType) {
9620
+ return (<GenericType>iterableIterator).typeArguments[0];
9621
+ }
9622
+
9623
+ return getElementTypeFromIterable(iterableIterator, errorNode) ||
9624
+ getElementTypeFromIterator(iterableIterator, errorNode);
9625
+ }
9626
+
9581
9627
/**
9582
9628
* This function does the following steps:
9583
9629
* 1. Break up arrayOrStringType (possibly a union) into its string constituents and array constituents.
@@ -12000,6 +12046,7 @@ module ts {
12000
12046
globalESSymbolType = getGlobalType("Symbol");
12001
12047
globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol");
12002
12048
globalIterableType = <GenericType>getGlobalType("Iterable", /*arity*/ 1);
12049
+ globalIteratorType = <GenericType>getGlobalType("Iterator", /*arity*/ 1);
12003
12050
globalIterableIteratorType = <GenericType>getGlobalType("IterableIterator", /*arity*/ 1);
12004
12051
}
12005
12052
else {
0 commit comments