Check iterable structure of the right hand side of 'for...of' statement

This commit is contained in:
Jason Freeman 2015-02-23 19:07:29 -08:00
parent 1043d8703f
commit 2858771a54
3 changed files with 34 additions and 5 deletions

View file

@ -8768,7 +8768,7 @@ module ts {
var leftType = checkExpression(varExpr);
checkReferenceExpression(varExpr, Diagnostics.Invalid_left_hand_side_in_for_of_statement, Diagnostics.The_left_hand_side_of_a_for_of_statement_cannot_be_a_previously_defined_constant);
var rightType = checkExpression(node.expression);
var iteratedType = getIteratedType(rightType);
var iteratedType = getIteratedType(rightType, node.expression);
checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined);
}
@ -8831,7 +8831,7 @@ module ts {
var links = getNodeLinks(variable);
if (!links.resolvedType) {
links.resolvedType = resolvingType;
var type = getIteratedType(getTypeOfExpression(forOfStatement.expression));
var type = getIteratedType(getTypeOfExpression(forOfStatement.expression), forOfStatement.expression);
if (links.resolvedType === resolvingType) {
links.resolvedType = type;
}
@ -8843,7 +8843,7 @@ module ts {
return links.resolvedType;
}
function getIteratedType(iterable: Type): Type {
function getIteratedType(iterable: Type, expressionForError: Expression): Type {
Debug.assert(languageVersion >= ScriptTarget.ES6);
if (allConstituentTypesHaveKind(iterable, TypeFlags.Any)) {
return anyType;
@ -8867,14 +8867,28 @@ module ts {
// T is the type we are after. At every level that involves analyzing return types
// of signatures, we union the return types of all the signatures.
var iteratorFunction = getTypeOfPropertyOfType(iterable, getPropertyNameForKnownSymbolName("iterator"));
var iteratorFunctionSignatures = getSignaturesOfType(iteratorFunction, SignatureKind.Call);
var iteratorFunctionSignatures = iteratorFunction ? getSignaturesOfType(iteratorFunction, SignatureKind.Call) : emptyArray;
if (iteratorFunctionSignatures.length === 0) {
error(expressionForError, Diagnostics.The_right_hand_side_of_a_for_of_statement_must_have_a_Symbol_iterator_method_that_returns_an_iterator);
return unknownType;
}
var iterator = getUnionType(map(iteratorFunctionSignatures, getReturnTypeOfSignature));
var iteratorNextFunction = getTypeOfPropertyOfType(iterator, "next");
var iteratorNextFunctionSignatures = getSignaturesOfType(iteratorNextFunction, SignatureKind.Call);
var iteratorNextFunctionSignatures = iteratorNextFunction ? getSignaturesOfType(iteratorNextFunction, SignatureKind.Call) : emptyArray;
if (iteratorNextFunctionSignatures.length === 0) {
error(expressionForError, Diagnostics.The_iterator_returned_by_the_right_hand_side_of_a_for_of_statement_must_have_a_next_method);
return unknownType;
}
var iteratorNextResult = getUnionType(map(iteratorNextFunctionSignatures, getReturnTypeOfSignature));
var iteratorNextValue = getTypeOfPropertyOfType(iteratorNextResult, "value");
if (!iteratorNextValue) {
error(expressionForError, Diagnostics.The_object_returned_by_the_next_method_of_the_iterator_must_have_a_value_property);
return unknownType;
}
return iteratorNextValue;
// TODO

View file

@ -329,6 +329,9 @@ module ts {
The_left_hand_side_of_a_for_of_statement_cannot_be_a_previously_defined_constant: { code: 2485, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...of' statement cannot be a previously defined constant." },
The_left_hand_side_of_a_for_in_statement_cannot_be_a_previously_defined_constant: { code: 2486, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot be a previously defined constant." },
Invalid_left_hand_side_in_for_of_statement: { code: 2487, category: DiagnosticCategory.Error, key: "Invalid left-hand side in 'for...of' statement." },
The_right_hand_side_of_a_for_of_statement_must_have_a_Symbol_iterator_method_that_returns_an_iterator: { code: 2488, category: DiagnosticCategory.Error, key: "The right-hand side of a 'for...of' statement must have a '[Symbol.iterator]()' method that returns an iterator." },
The_iterator_returned_by_the_right_hand_side_of_a_for_of_statement_must_have_a_next_method: { code: 2489, category: DiagnosticCategory.Error, key: "The iterator returned by the right-hand side of a 'for...of' statement must have a 'next()' method." },
The_object_returned_by_the_next_method_of_the_iterator_must_have_a_value_property: { code: 2490, category: DiagnosticCategory.Error, key: "The object returned by the next method of the iterator must have a 'value' property." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },

View file

@ -1308,6 +1308,18 @@
"category": "Error",
"code": 2487
},
"The right-hand side of a 'for...of' statement must have a '[Symbol.iterator]()' method that returns an iterator.": {
"category": "Error",
"code": 2488
},
"The iterator returned by the right-hand side of a 'for...of' statement must have a 'next()' method.": {
"category": "Error",
"code": 2489
},
"The object returned by the next method of the iterator must have a 'value' property.": {
"category": "Error",
"code": 2490
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",