Support assignment patterns in 'for...of' statements

This commit is contained in:
Jason Freeman 2015-02-26 15:32:37 -08:00
parent 9faa09b5d7
commit f8150d3734
10 changed files with 146 additions and 10 deletions

View file

@ -7411,7 +7411,7 @@ module ts {
return rightType;
}
// Return type is true if there was no error, false if there was an error.
// Return true if there was no error, false if there was an error.
function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean {
var offendingSymbolOperand =
someConstituentTypeHasKind(leftType, TypeFlags.ESSymbol) ? node.left :
@ -8758,7 +8758,7 @@ module ts {
grammarErrorOnFirstToken(node, Diagnostics.for_of_statements_are_only_available_when_targeting_ECMAScript_6_or_higher);
return;
}
checkGrammarForInOrForOfStatement(node)
// Check the LHS and RHS
@ -8769,17 +8769,27 @@ module ts {
}
else {
var varExpr = <Expression>node.initializer;
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, node.expression);
// iteratedType will be undefined if the rightType was missing properties/signatures
// required to get it's 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.
if (iteratedType) {
checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined);
// There may be a destructuring assignment on the left side
if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) {
// iteratedType may be undefined. In this case, we still want to check the structure of
// varExpr, in particular making sure it's a valid LeftHandSideExpression. But we'd like
// to short circuit the type relation checking as much as possible, so we pass the unknownType.
checkDestructuringAssignment(varExpr, iteratedType || unknownType);
}
else {
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);
// iteratedType will be undefined if the rightType was missing properties/signatures
// required to get it's 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.
if (iteratedType) {
checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined);
}
}
}

View file

@ -0,0 +1,15 @@
//// [for-of45.ts]
var k: string, v: boolean;
var map = new Map([["", true]]);
for ([k = "", v = false] of map) {
k;
v;
}
//// [for-of45.js]
var k, v;
var map = new Map([["", true]]);
for ([k = "", v = false] of map) {
k;
v;
}

View file

@ -0,0 +1,26 @@
=== tests/cases/conformance/es6/for-ofStatements/for-of45.ts ===
var k: string, v: boolean;
>k : string
>v : boolean
var map = new Map([["", true]]);
>map : Map<string, boolean>
>new Map([["", true]]) : Map<string, boolean>
>Map : MapConstructor
>[["", true]] : [string, boolean][]
>["", true] : [string, boolean]
for ([k = "", v = false] of map) {
>[k = "", v = false] : (string | boolean)[]
>k = "" : string
>k : string
>v = false : boolean
>v : boolean
>map : Map<string, boolean>
k;
>k : string
v;
>v : boolean
}

View file

@ -0,0 +1,15 @@
tests/cases/conformance/es6/for-ofStatements/for-of46.ts(3,7): error TS2322: Type 'boolean' is not assignable to type 'string'.
tests/cases/conformance/es6/for-ofStatements/for-of46.ts(3,18): error TS2322: Type 'string' is not assignable to type 'boolean'.
==== tests/cases/conformance/es6/for-ofStatements/for-of46.ts (2 errors) ====
var k: string, v: boolean;
var map = new Map([["", true]]);
for ([k = false, v = ""] of map) {
~
!!! error TS2322: Type 'boolean' is not assignable to type 'string'.
~
!!! error TS2322: Type 'string' is not assignable to type 'boolean'.
k;
v;
}

View file

@ -0,0 +1,15 @@
//// [for-of46.ts]
var k: string, v: boolean;
var map = new Map([["", true]]);
for ([k = false, v = ""] of map) {
k;
v;
}
//// [for-of46.js]
var k, v;
var map = new Map([["", true]]);
for ([k = false, v = ""] of map) {
k;
v;
}

View file

@ -0,0 +1,13 @@
tests/cases/conformance/es6/for-ofStatements/for-of47.ts(4,13): error TS2322: Type 'boolean' is not assignable to type 'number'.
==== tests/cases/conformance/es6/for-ofStatements/for-of47.ts (1 errors) ====
var x: string, y: number;
var array = [{ x: "", y: true }]
enum E { x }
for ({x, y: y = E.x} of array) {
~
!!! error TS2322: Type 'boolean' is not assignable to type 'number'.
x;
y;
}

View file

@ -0,0 +1,20 @@
//// [for-of47.ts]
var x: string, y: number;
var array = [{ x: "", y: true }]
enum E { x }
for ({x, y: y = E.x} of array) {
x;
y;
}
//// [for-of47.js]
var x, y;
var array = [{ x: "", y: true }];
var E;
(function (E) {
E[E["x"] = 0] = "x";
})(E || (E = {}));
for ({ x, y: y = 0 /* x */ } of array) {
x;
y;
}

View file

@ -0,0 +1,7 @@
//@target: ES6
var k: string, v: boolean;
var map = new Map([["", true]]);
for ([k = "", v = false] of map) {
k;
v;
}

View file

@ -0,0 +1,7 @@
//@target: ES6
var k: string, v: boolean;
var map = new Map([["", true]]);
for ([k = false, v = ""] of map) {
k;
v;
}

View file

@ -0,0 +1,8 @@
//@target: ES6
var x: string, y: number;
var array = [{ x: "", y: true }]
enum E { x }
for ({x, y: y = E.x} of array) {
x;
y;
}