Check for assignability to the relevant iteratable type
This commit is contained in:
parent
732637dd54
commit
0049b21d6c
|
@ -97,6 +97,7 @@ module ts {
|
|||
var globalRegExpType: ObjectType;
|
||||
var globalTemplateStringsArrayType: ObjectType;
|
||||
var globalESSymbolType: ObjectType;
|
||||
var globalIterableType: ObjectType;
|
||||
|
||||
var anyArrayType: Type;
|
||||
|
||||
|
@ -3156,8 +3157,8 @@ module ts {
|
|||
return resolveName(undefined, name, meaning, diagnostic, name);
|
||||
}
|
||||
|
||||
function getGlobalType(name: string): ObjectType {
|
||||
return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), 0);
|
||||
function getGlobalType(name: string, arity = 0): ObjectType {
|
||||
return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), arity);
|
||||
}
|
||||
|
||||
function getGlobalESSymbolConstructorSymbol() {
|
||||
|
@ -8844,70 +8845,79 @@ module ts {
|
|||
}
|
||||
|
||||
function getIteratedType(iterable: Type, expressionForError: Expression): Type {
|
||||
Debug.assert(languageVersion >= ScriptTarget.ES6);
|
||||
if (allConstituentTypesHaveKind(iterable, TypeFlags.Any)) {
|
||||
return iterable; // any or unknown
|
||||
}
|
||||
|
||||
// We want to treat type as an iterable, and get the type it is an iterable of. The iterable
|
||||
// must have the following structure (annotated with the names of the variables below):
|
||||
//
|
||||
// { // iterable
|
||||
// [Symbol.iterator]: { // iteratorFunction
|
||||
// (): { // iterator
|
||||
// next: { // iteratorNextFunction
|
||||
// (): { // iteratorNextResult
|
||||
// value: T // iteratorNextValue
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// 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"));
|
||||
if (iteratorFunction && allConstituentTypesHaveKind(iteratorFunction, TypeFlags.Any)) {
|
||||
return iteratorFunction; // any or unknown
|
||||
}
|
||||
|
||||
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));
|
||||
if (allConstituentTypesHaveKind(iterator, TypeFlags.Any)) {
|
||||
return iterator; // any or unknown
|
||||
}
|
||||
|
||||
var iteratorNextFunction = getTypeOfPropertyOfType(iterator, "next");
|
||||
if (iteratorNextFunction && allConstituentTypesHaveKind(iteratorNextFunction, TypeFlags.Any)) {
|
||||
return iteratorNextFunction; // any or unknown
|
||||
}
|
||||
|
||||
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));
|
||||
if (allConstituentTypesHaveKind(iteratorNextResult, TypeFlags.Any)) {
|
||||
return iteratorNextResult; // any or unknown
|
||||
}
|
||||
|
||||
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
|
||||
// Now even though we have extracted the iteratorNextValue, we will have to validate that the type
|
||||
var iteratedType = getIteratedTypeSubroutine(iterable, expressionForError);
|
||||
// Now even though we have extracted the iteratedType, we will have to validate that the type
|
||||
// passed in is actually an Iterable.
|
||||
if (iteratedType !== unknownType) {
|
||||
var completeIterableType = globalIterableType !== emptyObjectType ? createTypeReference(<GenericType>globalIterableType, [iteratedType]) : emptyObjectType;
|
||||
checkTypeAssignableTo(iterable, completeIterableType, expressionForError);
|
||||
}
|
||||
|
||||
return iteratedType;
|
||||
|
||||
function getIteratedTypeSubroutine(iterable: Type, expressionForError: Expression) {
|
||||
Debug.assert(languageVersion >= ScriptTarget.ES6);
|
||||
if (allConstituentTypesHaveKind(iterable, TypeFlags.Any)) {
|
||||
return iterable; // any or unknown
|
||||
}
|
||||
|
||||
// We want to treat type as an iterable, and get the type it is an iterable of. The iterable
|
||||
// must have the following structure (annotated with the names of the variables below):
|
||||
//
|
||||
// { // iterable
|
||||
// [Symbol.iterator]: { // iteratorFunction
|
||||
// (): { // iterator
|
||||
// next: { // iteratorNextFunction
|
||||
// (): { // iteratorNextResult
|
||||
// value: T // iteratorNextValue
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// 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"));
|
||||
if (iteratorFunction && allConstituentTypesHaveKind(iteratorFunction, TypeFlags.Any)) {
|
||||
return iteratorFunction; // any or unknown
|
||||
}
|
||||
|
||||
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));
|
||||
if (allConstituentTypesHaveKind(iterator, TypeFlags.Any)) {
|
||||
return iterator; // any or unknown
|
||||
}
|
||||
|
||||
var iteratorNextFunction = getTypeOfPropertyOfType(iterator, "next");
|
||||
if (iteratorNextFunction && allConstituentTypesHaveKind(iteratorNextFunction, TypeFlags.Any)) {
|
||||
return iteratorNextFunction; // any or unknown
|
||||
}
|
||||
|
||||
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));
|
||||
if (allConstituentTypesHaveKind(iteratorNextResult, TypeFlags.Any)) {
|
||||
return iteratorNextResult; // any or unknown
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
function checkBreakOrContinueStatement(node: BreakOrContinueStatement) {
|
||||
|
@ -10856,6 +10866,7 @@ module ts {
|
|||
globalTemplateStringsArrayType = getGlobalType("TemplateStringsArray");
|
||||
globalESSymbolType = getGlobalType("Symbol");
|
||||
globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol");
|
||||
globalIterableType = getGlobalType("Iterable", 1);
|
||||
}
|
||||
else {
|
||||
globalTemplateStringsArrayType = unknownType;
|
||||
|
|
14
tests/baselines/reference/for-of29.errors.txt
Normal file
14
tests/baselines/reference/for-of29.errors.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
tests/cases/conformance/es6/for-ofStatements/for-of29.ts(5,15): error TS2322: Type '{ [Symbol.iterator]?(): Iterator<string>; }' is not assignable to type 'Iterable<string>'.
|
||||
Property '[Symbol.iterator]' is optional in type '{ [Symbol.iterator]?(): Iterator<string>; }' but required in type 'Iterable<string>'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/for-ofStatements/for-of29.ts (1 errors) ====
|
||||
var iterableWithOptionalIterator: {
|
||||
[Symbol.iterator]?(): Iterator<string>
|
||||
};
|
||||
|
||||
for (var v of iterableWithOptionalIterator) { }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ [Symbol.iterator]?(): Iterator<string>; }' is not assignable to type 'Iterable<string>'.
|
||||
!!! error TS2322: Property '[Symbol.iterator]' is optional in type '{ [Symbol.iterator]?(): Iterator<string>; }' but required in type 'Iterable<string>'.
|
||||
|
11
tests/baselines/reference/for-of29.js
Normal file
11
tests/baselines/reference/for-of29.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
//// [for-of29.ts]
|
||||
var iterableWithOptionalIterator: {
|
||||
[Symbol.iterator]?(): Iterator<string>
|
||||
};
|
||||
|
||||
for (var v of iterableWithOptionalIterator) { }
|
||||
|
||||
|
||||
//// [for-of29.js]
|
||||
var iterableWithOptionalIterator;
|
||||
for (var v of iterableWithOptionalIterator) { }
|
32
tests/baselines/reference/for-of30.errors.txt
Normal file
32
tests/baselines/reference/for-of30.errors.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
tests/cases/conformance/es6/for-ofStatements/for-of30.ts(1,15): error TS2322: Type 'StringIterator' is not assignable to type 'Iterable<string>'.
|
||||
Types of property '[Symbol.iterator]' are incompatible.
|
||||
Type '() => StringIterator' is not assignable to type '() => Iterator<string>'.
|
||||
Type 'StringIterator' is not assignable to type 'Iterator<string>'.
|
||||
Types of property 'return' are incompatible.
|
||||
Type 'number' is not assignable to type '(value?: any) => IteratorResult<string>'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/for-ofStatements/for-of30.ts (1 errors) ====
|
||||
for (var v of new StringIterator) { }
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'StringIterator' is not assignable to type 'Iterable<string>'.
|
||||
!!! error TS2322: Types of property '[Symbol.iterator]' are incompatible.
|
||||
!!! error TS2322: Type '() => StringIterator' is not assignable to type '() => Iterator<string>'.
|
||||
!!! error TS2322: Type 'StringIterator' is not assignable to type 'Iterator<string>'.
|
||||
!!! error TS2322: Types of property 'return' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type '(value?: any) => IteratorResult<string>'.
|
||||
|
||||
class StringIterator {
|
||||
next() {
|
||||
return {
|
||||
done: false,
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
|
||||
return = 0;
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
}
|
||||
}
|
35
tests/baselines/reference/for-of30.js
Normal file
35
tests/baselines/reference/for-of30.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
//// [for-of30.ts]
|
||||
for (var v of new StringIterator) { }
|
||||
|
||||
class StringIterator {
|
||||
next() {
|
||||
return {
|
||||
done: false,
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
|
||||
return = 0;
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
//// [for-of30.js]
|
||||
for (var v of new StringIterator) { }
|
||||
var StringIterator = (function () {
|
||||
function StringIterator() {
|
||||
this.return = 0;
|
||||
}
|
||||
StringIterator.prototype.next = function () {
|
||||
return {
|
||||
done: false,
|
||||
value: ""
|
||||
};
|
||||
};
|
||||
StringIterator.prototype[Symbol.iterator] = function () {
|
||||
return this;
|
||||
};
|
||||
return StringIterator;
|
||||
})();
|
34
tests/baselines/reference/for-of31.errors.txt
Normal file
34
tests/baselines/reference/for-of31.errors.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
tests/cases/conformance/es6/for-ofStatements/for-of31.ts(1,15): error TS2322: Type 'StringIterator' is not assignable to type 'Iterable<string>'.
|
||||
Types of property '[Symbol.iterator]' are incompatible.
|
||||
Type '() => StringIterator' is not assignable to type '() => Iterator<string>'.
|
||||
Type 'StringIterator' is not assignable to type 'Iterator<string>'.
|
||||
Types of property 'next' are incompatible.
|
||||
Type '() => { value: string; }' is not assignable to type '() => IteratorResult<string>'.
|
||||
Type '{ value: string; }' is not assignable to type 'IteratorResult<string>'.
|
||||
Property 'done' is missing in type '{ value: string; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/for-ofStatements/for-of31.ts (1 errors) ====
|
||||
for (var v of new StringIterator) { }
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'StringIterator' is not assignable to type 'Iterable<string>'.
|
||||
!!! error TS2322: Types of property '[Symbol.iterator]' are incompatible.
|
||||
!!! error TS2322: Type '() => StringIterator' is not assignable to type '() => Iterator<string>'.
|
||||
!!! error TS2322: Type 'StringIterator' is not assignable to type 'Iterator<string>'.
|
||||
!!! error TS2322: Types of property 'next' are incompatible.
|
||||
!!! error TS2322: Type '() => { value: string; }' is not assignable to type '() => IteratorResult<string>'.
|
||||
!!! error TS2322: Type '{ value: string; }' is not assignable to type 'IteratorResult<string>'.
|
||||
!!! error TS2322: Property 'done' is missing in type '{ value: string; }'.
|
||||
|
||||
class StringIterator {
|
||||
next() {
|
||||
return {
|
||||
// no done property
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
}
|
||||
}
|
32
tests/baselines/reference/for-of31.js
Normal file
32
tests/baselines/reference/for-of31.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
//// [for-of31.ts]
|
||||
for (var v of new StringIterator) { }
|
||||
|
||||
class StringIterator {
|
||||
next() {
|
||||
return {
|
||||
// no done property
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
//// [for-of31.js]
|
||||
for (var v of new StringIterator) { }
|
||||
var StringIterator = (function () {
|
||||
function StringIterator() {
|
||||
}
|
||||
StringIterator.prototype.next = function () {
|
||||
return {
|
||||
// no done property
|
||||
value: ""
|
||||
};
|
||||
};
|
||||
StringIterator.prototype[Symbol.iterator] = function () {
|
||||
return this;
|
||||
};
|
||||
return StringIterator;
|
||||
})();
|
6
tests/cases/conformance/es6/for-ofStatements/for-of29.ts
Normal file
6
tests/cases/conformance/es6/for-ofStatements/for-of29.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
//@target: ES6
|
||||
var iterableWithOptionalIterator: {
|
||||
[Symbol.iterator]?(): Iterator<string>
|
||||
};
|
||||
|
||||
for (var v of iterableWithOptionalIterator) { }
|
17
tests/cases/conformance/es6/for-ofStatements/for-of30.ts
Normal file
17
tests/cases/conformance/es6/for-ofStatements/for-of30.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
//@target: ES6
|
||||
for (var v of new StringIterator) { }
|
||||
|
||||
class StringIterator {
|
||||
next() {
|
||||
return {
|
||||
done: false,
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
|
||||
return = 0;
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
}
|
||||
}
|
15
tests/cases/conformance/es6/for-ofStatements/for-of31.ts
Normal file
15
tests/cases/conformance/es6/for-ofStatements/for-of31.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
//@target: ES6
|
||||
for (var v of new StringIterator) { }
|
||||
|
||||
class StringIterator {
|
||||
next() {
|
||||
return {
|
||||
// no done property
|
||||
value: ""
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue