Skip to content

Support spreading and destructuring of iterators in ES6 #2498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
abe4076
Change error message to be more general
JsonFreeman Mar 24, 2015
3497e27
Add spread to typeWriter
JsonFreeman Mar 24, 2015
b7f2990
Refactor checkSpreadElementExpression to get the element type internally
JsonFreeman Mar 24, 2015
2288946
Support iterators in spread element
JsonFreeman Mar 24, 2015
376574d
Add tests for iterator spread in an array literal
JsonFreeman Mar 24, 2015
4a0af76
Add tests for iterator spread in call
JsonFreeman Mar 24, 2015
8c2cd26
Add createIterableType
JsonFreeman Mar 25, 2015
42ed6aa
getTypeFromArrayBindingPattern returns an iterable in ES6
JsonFreeman Mar 25, 2015
806c9ce
Refactor iterable or array checks into checkIteratedTypeOrElementType
JsonFreeman Mar 25, 2015
06d6717
Type of an array binding element is the iterated type of its parent i…
JsonFreeman Mar 25, 2015
17d201f
Use iterated type in checkArrayLiteralAssignment
JsonFreeman Mar 25, 2015
6b2d5ce
Wrap elementType in createArrayType for rest element in checkArrayLit…
JsonFreeman Mar 25, 2015
a477b63
Adjust getTypeFromArrayBindingPattern to return an array if inside a …
JsonFreeman Mar 26, 2015
e1f2fbf
Add tests for array destructuring of iterables
JsonFreeman Mar 26, 2015
197a42a
Optimize direct Iterable reference in getIteratedType
JsonFreeman Mar 26, 2015
17719e8
Fix comment to be more accurate
JsonFreeman Mar 26, 2015
de8de7a
Merge branch 'master' into iteratorSpreadDestructure
JsonFreeman Mar 26, 2015
903c1d8
Add clarifying comment about checkExpressionCached
JsonFreeman Mar 26, 2015
d459c59
Merge branch 'master' of https://github.com/Microsoft/TypeScript into…
JsonFreeman Apr 8, 2015
846c225
Update baselines for preserving newlines
JsonFreeman Apr 8, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 109 additions & 63 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,8 @@ 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." },
Type_must_have_a_Symbol_iterator_method_that_returns_an_iterator: { code: 2488, category: DiagnosticCategory.Error, key: "Type must have a '[Symbol.iterator]()' method that returns an iterator." },
An_iterator_must_have_a_next_method: { code: 2489, category: DiagnosticCategory.Error, key: "An iterator must have a 'next()' method." },
The_type_returned_by_the_next_method_of_an_iterator_must_have_a_value_property: { code: 2490, category: DiagnosticCategory.Error, key: "The type returned by the 'next()' method of an iterator must have a 'value' property." },
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" },
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1367,11 +1367,11 @@
"category": "Error",
"code": 2487
},
"The right-hand side of a 'for...of' statement must have a '[Symbol.iterator]()' method that returns an iterator.": {
"Type 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.": {
"An iterator must have a 'next()' method.": {
"category": "Error",
"code": 2489
},
Expand Down
1 change: 1 addition & 0 deletions src/harness/typeWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class TypeWriterWalker {
case ts.SyntaxKind.PostfixUnaryExpression:
case ts.SyntaxKind.BinaryExpression:
case ts.SyntaxKind.ConditionalExpression:
case ts.SyntaxKind.SpreadElementExpression:
this.log(node, this.getTypeOfNode(node));
break;

Expand Down
8 changes: 7 additions & 1 deletion tests/baselines/reference/ES5For-of30.errors.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,6): error TS2461: Type 'string | number' is not an array type.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,7): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,14): error TS2322: Type 'string' is not assignable to type 'number'.


==== tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts (1 errors) ====
==== tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts (3 errors) ====
var a: string, b: number;
var tuple: [number, string] = [2, "3"];
for ([a = 1, b = ""] of tuple) {
~~~~~~~~~~~~~~~
!!! error TS2461: Type 'string | number' is not an array type.
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~
!!! error TS2322: Type 'string' is not assignable to type 'number'.
a;
b;
}
22 changes: 22 additions & 0 deletions tests/baselines/reference/arrayLiteralSpread.types
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,55 @@ function f0() {
var a1 = [...a];
>a1 : number[]
>[...a] : number[]
>...a : number
>a : number[]

var a2 = [1, ...a];
>a2 : number[]
>[1, ...a] : number[]
>...a : number
>a : number[]

var a3 = [1, 2, ...a];
>a3 : number[]
>[1, 2, ...a] : number[]
>...a : number
>a : number[]

var a4 = [...a, 1];
>a4 : number[]
>[...a, 1] : number[]
>...a : number
>a : number[]

var a5 = [...a, 1, 2];
>a5 : number[]
>[...a, 1, 2] : number[]
>...a : number
>a : number[]

var a6 = [1, 2, ...a, 1, 2];
>a6 : number[]
>[1, 2, ...a, 1, 2] : number[]
>...a : number
>a : number[]

var a7 = [1, ...a, 2, ...a];
>a7 : number[]
>[1, ...a, 2, ...a] : number[]
>...a : number
>a : number[]
>...a : number
>a : number[]

var a8 = [...a, ...a, ...a];
>a8 : number[]
>[...a, ...a, ...a] : number[]
>...a : number
>a : number[]
>...a : number
>a : number[]
>...a : number
>a : number[]
}

Expand All @@ -60,6 +71,7 @@ function f1() {
var b = ["hello", ...a, true];
>b : (string | number | boolean)[]
>["hello", ...a, true] : (string | number | boolean)[]
>...a : number
>a : number[]

var b: (string | number | boolean)[];
Expand All @@ -72,19 +84,29 @@ function f2() {
var a = [...[...[...[...[...[]]]]]];
>a : any[]
>[...[...[...[...[...[]]]]]] : undefined[]
>...[...[...[...[...[]]]]] : undefined
>[...[...[...[...[]]]]] : undefined[]
>...[...[...[...[]]]] : undefined
>[...[...[...[]]]] : undefined[]
>...[...[...[]]] : undefined
>[...[...[]]] : undefined[]
>...[...[]] : undefined
>[...[]] : undefined[]
>...[] : undefined
>[] : undefined[]

var b = [...[...[...[...[...[5]]]]]];
>b : number[]
>[...[...[...[...[...[5]]]]]] : number[]
>...[...[...[...[...[5]]]]] : number
>[...[...[...[...[5]]]]] : number[]
>...[...[...[...[5]]]] : number
>[...[...[...[5]]]] : number[]
>...[...[...[5]]] : number
>[...[...[5]]] : number[]
>...[...[5]] : number
>[...[5]] : number[]
>...[5] : number
>[5] : number[]
}

13 changes: 13 additions & 0 deletions tests/baselines/reference/callWithSpreadES6.types
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ foo(1, 2, "abc");
foo(1, 2, ...a);
>foo(1, 2, ...a) : void
>foo : (x: number, y: number, ...z: string[]) => void
>...a : string
>a : string[]

foo(1, 2, ...a, "abc");
>foo(1, 2, ...a, "abc") : void
>foo : (x: number, y: number, ...z: string[]) => void
>...a : string
>a : string[]

obj.foo(1, 2, "abc");
Expand All @@ -56,13 +58,15 @@ obj.foo(1, 2, ...a);
>obj.foo : (x: number, y: number, ...z: string[]) => any
>obj : X
>foo : (x: number, y: number, ...z: string[]) => any
>...a : string
>a : string[]

obj.foo(1, 2, ...a, "abc");
>obj.foo(1, 2, ...a, "abc") : any
>obj.foo : (x: number, y: number, ...z: string[]) => any
>obj : X
>foo : (x: number, y: number, ...z: string[]) => any
>...a : string
>a : string[]

(obj.foo)(1, 2, "abc");
Expand All @@ -78,6 +82,7 @@ obj.foo(1, 2, ...a, "abc");
>obj.foo : (x: number, y: number, ...z: string[]) => any
>obj : X
>foo : (x: number, y: number, ...z: string[]) => any
>...a : string
>a : string[]

(obj.foo)(1, 2, ...a, "abc");
Expand All @@ -86,6 +91,7 @@ obj.foo(1, 2, ...a, "abc");
>obj.foo : (x: number, y: number, ...z: string[]) => any
>obj : X
>foo : (x: number, y: number, ...z: string[]) => any
>...a : string
>a : string[]

xa[1].foo(1, 2, "abc");
Expand All @@ -101,6 +107,7 @@ xa[1].foo(1, 2, ...a);
>xa[1] : X
>xa : X[]
>foo : (x: number, y: number, ...z: string[]) => any
>...a : string
>a : string[]

xa[1].foo(1, 2, ...a, "abc");
Expand All @@ -109,6 +116,7 @@ xa[1].foo(1, 2, ...a, "abc");
>xa[1] : X
>xa : X[]
>foo : (x: number, y: number, ...z: string[]) => any
>...a : string
>a : string[]

(<Function>xa[1].foo)(...[1, 2, "abc"]);
Expand All @@ -120,6 +128,7 @@ xa[1].foo(1, 2, ...a, "abc");
>xa[1] : X
>xa : X[]
>foo : (x: number, y: number, ...z: string[]) => any
>...[1, 2, "abc"] : string | number
>[1, 2, "abc"] : (string | number)[]

class C {
Expand All @@ -145,6 +154,7 @@ class C {
>foo : (x: number, y: number, ...z: string[]) => void
>x : number
>y : number
>...z : string
>z : string[]
}
foo(x: number, y: number, ...z: string[]) {
Expand All @@ -167,6 +177,7 @@ class D extends C {
super(1, 2, ...a);
>super(1, 2, ...a) : void
>super : typeof C
>...a : string
>a : string[]
}
foo() {
Expand All @@ -183,6 +194,7 @@ class D extends C {
>super.foo : (x: number, y: number, ...z: string[]) => void
>super : C
>foo : (x: number, y: number, ...z: string[]) => void
>...a : string
>a : string[]
}
}
Expand All @@ -192,5 +204,6 @@ var c = new C(1, 2, ...a);
>c : C
>new C(1, 2, ...a) : C
>C : typeof C
>...a : string
>a : string[]

4 changes: 2 additions & 2 deletions tests/baselines/reference/for-of14.errors.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
tests/cases/conformance/es6/for-ofStatements/for-of14.ts(2,11): error TS2488: The right-hand side of a 'for...of' statement must have a '[Symbol.iterator]()' method that returns an iterator.
tests/cases/conformance/es6/for-ofStatements/for-of14.ts(2,11): error TS2488: Type must have a '[Symbol.iterator]()' method that returns an iterator.


==== tests/cases/conformance/es6/for-ofStatements/for-of14.ts (1 errors) ====
var v: string;
for (v of new StringIterator) { } // Should fail because the iterator is not iterable
~~~~~~~~~~~~~~~~~~
!!! error TS2488: The right-hand side of a 'for...of' statement must have a '[Symbol.iterator]()' method that returns an iterator.
!!! error TS2488: Type must have a '[Symbol.iterator]()' method that returns an iterator.

class StringIterator {
next() {
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/for-of16.errors.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
tests/cases/conformance/es6/for-ofStatements/for-of16.ts(2,11): error TS2489: The iterator returned by the right-hand side of a 'for...of' statement must have a 'next()' method.
tests/cases/conformance/es6/for-ofStatements/for-of16.ts(2,11): error TS2489: An iterator must have a 'next()' method.


==== tests/cases/conformance/es6/for-ofStatements/for-of16.ts (1 errors) ====
var v: string;
for (v of new StringIterator) { } // Should fail
~~~~~~~~~~~~~~~~~~
!!! error TS2489: The iterator returned by the right-hand side of a 'for...of' statement must have a 'next()' method.
!!! error TS2489: An iterator must have a 'next()' method.

class StringIterator {
[Symbol.iterator]() {
Expand Down
7 changes: 7 additions & 0 deletions tests/baselines/reference/for-of57.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//// [for-of57.ts]
var iter: Iterable<number>;
for (let num of iter) { }

//// [for-of57.js]
var iter;
for (let num of iter) { }
9 changes: 9 additions & 0 deletions tests/baselines/reference/for-of57.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== tests/cases/conformance/es6/for-ofStatements/for-of57.ts ===
var iter: Iterable<number>;
>iter : Iterable<number>
>Iterable : Iterable<T>

for (let num of iter) { }
>num : number
>iter : Iterable<number>

28 changes: 28 additions & 0 deletions tests/baselines/reference/iterableArrayPattern1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//// [iterableArrayPattern1.ts]
var [a, b] = new SymbolIterator;
class SymbolIterator {
next() {
return {
value: Symbol(),
done: false
};
}

[Symbol.iterator]() {
return this;
}
}

//// [iterableArrayPattern1.js]
var [a, b] = new SymbolIterator;
class SymbolIterator {
next() {
return {
value: Symbol(),
done: false
};
}
[Symbol.iterator]() {
return this;
}
}
36 changes: 36 additions & 0 deletions tests/baselines/reference/iterableArrayPattern1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
=== tests/cases/conformance/es6/destructuring/iterableArrayPattern1.ts ===
var [a, b] = new SymbolIterator;
>a : symbol
>b : symbol
>new SymbolIterator : SymbolIterator
>SymbolIterator : typeof SymbolIterator

class SymbolIterator {
>SymbolIterator : SymbolIterator

next() {
>next : () => { value: symbol; done: boolean; }

return {
>{ value: Symbol(), done: false } : { value: symbol; done: boolean; }

value: Symbol(),
>value : symbol
>Symbol() : symbol
>Symbol : SymbolConstructor

done: false
>done : boolean

};
}

[Symbol.iterator]() {
>Symbol.iterator : symbol
>Symbol : SymbolConstructor
>iterator : symbol

return this;
>this : SymbolIterator
}
}
24 changes: 24 additions & 0 deletions tests/baselines/reference/iterableArrayPattern10.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts(2,5): error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.
Property '0' is missing in type 'FooIterator'.


==== tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts (1 errors) ====
function fun([a, b]) { }
fun(new FooIterator);
~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.
!!! error TS2345: Property '0' is missing in type 'FooIterator'.
class Bar { x }
class Foo extends Bar { y }
class FooIterator {
next() {
return {
value: new Foo,
done: false
};
}

[Symbol.iterator]() {
return this;
}
}
Loading