Introduce checkElementTypeOfArrayOrString for downlevel for..of type checking

This commit is contained in:
Jason Freeman
2015-03-11 16:34:08 -07:00
parent 5b46f5f9ae
commit 61cd2a7543
39 changed files with 685 additions and 954 deletions
+51 -16
View File
@@ -1869,7 +1869,11 @@ module ts {
return anyType;
}
if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
return getTypeForVariableDeclarationInForOfStatement(<ForOfStatement>declaration.parent.parent);
// checkRightHandSideOfForOf will return undefined if the for-of expression type was
// 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 getIteratedType.
return checkRightHandSideOfForOf((<ForOfStatement>declaration.parent.parent).expression) || anyType;
}
if (isBindingPattern(declaration.parent)) {
return getTypeForBindingElement(<BindingElement>declaration);
@@ -8781,7 +8785,7 @@ module ts {
// Check the LHS and RHS
// If the LHS is a declaration, just check it as a variable declaration, which will in turn check the RHS
// via getTypeForVariableDeclarationInForOfStatement.
// via checkRightHandSideOfForOf.
// If the LHS is an expression, check the LHS, as a destructuring assignment or as a reference.
// Then check that the RHS is assignable to it.
if (node.initializer.kind === SyntaxKind.VariableDeclarationList) {
@@ -8789,8 +8793,7 @@ module ts {
}
else {
var varExpr = <Expression>node.initializer;
var rightType = checkExpression(node.expression);
var iteratedType = checkIteratedType(rightType, node.expression);
var iteratedType = checkRightHandSideOfForOf(node.expression);
// There may be a destructuring assignment on the left side
if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) {
@@ -8872,18 +8875,11 @@ module ts {
}
}
function getTypeForVariableDeclarationInForOfStatement(forOfStatement: ForOfStatement): Type {
// Temporarily return 'any' below ES6
if (languageVersion < ScriptTarget.ES6) {
return anyType;
}
// iteratedType will be undefined if the for-of expression type was 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
// getIteratedType.
var expressionType = getTypeOfExpression(forOfStatement.expression);
return checkIteratedType(expressionType, forOfStatement.expression) || anyType;
function checkRightHandSideOfForOf(rhsExpression: Expression): Type {
var expressionType = getTypeOfExpression(rhsExpression);
return languageVersion >= ScriptTarget.ES6
? checkIteratedType(expressionType, rhsExpression)
: checkElementTypeOfArrayOrString(expressionType, rhsExpression);
}
/**
@@ -8982,6 +8978,45 @@ module ts {
}
}
function checkElementTypeOfArrayOrString(arrayOrStringType: Type, expressionForError: Expression): Type {
Debug.assert(languageVersion < ScriptTarget.ES6);
var isJustString = allConstituentTypesHaveKind(arrayOrStringType, TypeFlags.StringLike);
// Check isJustString because removeTypesFromUnionType will only remove types if it doesn't result
// in an emptyObjectType. In this case, we actually do want the emptyObjectType.
var arrayType = isJustString ? emptyObjectType : removeTypesFromUnionType(arrayOrStringType, TypeFlags.StringLike, /*isTypeOfKind*/ true);
var hasStringConstituent = arrayOrStringType !== emptyObjectType && arrayOrStringType !== arrayType;
var reportedError = false;
if (hasStringConstituent && languageVersion < ScriptTarget.ES5) {
error(expressionForError, Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher);
reportedError = true;
}
if (isJustString) {
return stringType;
}
if (!isArrayLikeType(arrayType)) {
if (!reportedError) {
error(expressionForError, Diagnostics.Type_0_is_not_an_array_type, typeToString(arrayType));
}
return hasStringConstituent ? stringType : unknownType;
}
var arrayElementType = getIndexTypeOfType(arrayType, IndexKind.Number) || unknownType;
if (hasStringConstituent) {
// This is just an optimization for the case where arrayOrStringType is string | string[]
if (arrayElementType.flags & TypeFlags.StringLike) {
return stringType;
}
return getUnionType([arrayElementType, stringType]);
}
return arrayElementType;
}
function checkBreakOrContinueStatement(node: BreakOrContinueStatement) {
// Grammar checking
checkGrammarStatementInAmbientContext(node) || checkGrammarBreakOrContinueStatement(node);
@@ -338,6 +338,7 @@ module ts {
The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern: { code: 2491, category: DiagnosticCategory.Error, key: "The left-hand side of a 'for...in' statement cannot be a destructuring pattern." },
Cannot_redeclare_identifier_0_in_catch_clause: { code: 2492, category: DiagnosticCategory.Error, key: "Cannot redeclare identifier '{0}' in catch clause" },
Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2: { code: 2493, category: DiagnosticCategory.Error, key: "Tuple type '{0}' with length '{1}' cannot be assigned to tuple with length '{2}'." },
Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher: { code: 2494, category: DiagnosticCategory.Error, key: "Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher." },
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}'." },
+4
View File
@@ -1343,6 +1343,10 @@
"category": "Error",
"code": 2493
},
"Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher.": {
"category": "Error",
"code": 2494
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",