Add for-await-of, always use Symbol for iterables.

This commit is contained in:
Ron Buckton
2016-11-16 14:22:42 -08:00
parent d6a5e39c3a
commit 28d23ce8de
20 changed files with 223 additions and 169 deletions
+19 -5
View File
@@ -954,7 +954,7 @@ namespace ts {
addAntecedent(preLoopLabel, currentFlow);
currentFlow = preLoopLabel;
if (node.kind === SyntaxKind.ForOfStatement) {
bind(node.awaitKeyword);
bind(node.modifierToken);
}
bind(node.expression);
addAntecedent(postLoopLabel, currentFlow);
@@ -3125,9 +3125,13 @@ namespace ts {
break;
case SyntaxKind.ForOfStatement:
// for-of might be ESNext if it has a rest destructuring
transformFlags |= TransformFlags.AssertESNext;
// FALLTHROUGH
if ((<ForOfStatement>node).modifierToken) {
transformFlags |= TransformFlags.AssertES2017;
}
transformFlags |= TransformFlags.AssertES2015;
break;
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateHead:
case SyntaxKind.TemplateMiddle:
@@ -3142,7 +3146,17 @@ namespace ts {
case SyntaxKind.ForOfStatement:
// This node is either ES2015 syntax or ES2017 syntax (if it is a for-await-of).
transformFlags |= (<ForOfStatement>node).awaitKeyword ? TransformFlags.AssertES2017 : TransformFlags.AssertES2015;
switch (getForOfModifierKind(<ForOfStatement>node)) {
case SyntaxKind.AwaitKeyword:
transformFlags |= TransformFlags.AssertES2017;
break;
case SyntaxKind.EachKeyword:
transformFlags |= TransformFlags.AssertTypeScript;
break;
default:
transformFlags |= TransformFlags.AssertES2015;
break;
}
break;
case SyntaxKind.YieldExpression:
+107 -99
View File
@@ -189,6 +189,13 @@ namespace ts {
let globalNumberType: ObjectType;
let globalBooleanType: ObjectType;
let globalRegExpType: ObjectType;
let globalESSymbolType: ObjectType;
let globalIterableType: GenericType;
let globalIteratorType: GenericType;
let globalIterableIteratorType: GenericType;
let globalAsyncIterableType: GenericType;
let globalAsyncIteratorType: GenericType;
let globalAsyncIterableIteratorType: GenericType;
let anyArrayType: Type;
let autoArrayType: Type;
let anyReadonlyArrayType: Type;
@@ -198,14 +205,6 @@ namespace ts {
// and they will not get an error from not having unrelated library files
let getGlobalTemplateStringsArrayType: () => ObjectType;
let getGlobalESSymbolType: () => ObjectType;
let getGlobalIterableType: () => GenericType;
let getGlobalIteratorType: () => GenericType;
let getGlobalIterableIteratorType: () => GenericType;
let getGlobalAsyncIterableType: () => GenericType;
let getGlobalAsyncIteratorType: () => GenericType;
let getGlobalAsyncIterableIteratorType: () => GenericType;
let getGlobalTypedPropertyDescriptorType: () => GenericType;
let getGlobalPromiseType: () => GenericType;
let tryGetGlobalPromiseType: () => GenericType;
@@ -3213,8 +3212,8 @@ namespace ts {
// 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 getElementTypeOfIterable.
const isForAwaitOf = (<ForOfStatement>declaration.parent.parent).awaitKeyword !== undefined;
return checkRightHandSideOfForOf((<ForOfStatement>declaration.parent.parent).expression, isForAwaitOf) || anyType;
const forOfStatement = <ForOfStatement>declaration.parent.parent;
return checkRightHandSideOfForOf(forOfStatement.expression, getForOfModifierKind(forOfStatement)) || anyType;
}
if (isBindingPattern(declaration.parent)) {
@@ -3631,7 +3630,9 @@ namespace ts {
}
function isReferenceToType(type: Type, target: Type) {
return (getObjectFlags(type) & ObjectFlags.Reference) !== 0
return type !== undefined
&& target !== undefined
&& (getObjectFlags(type) & ObjectFlags.Reference) !== 0
&& (<TypeReference>type).target === target;
}
@@ -4668,7 +4669,7 @@ namespace ts {
return t.flags & TypeFlags.StringLike ? globalStringType :
t.flags & TypeFlags.NumberLike ? globalNumberType :
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() :
t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType(/*checked*/ languageVersion >= ScriptTarget.ES2015) :
t.flags & TypeFlags.Index ? stringOrNumberType :
t;
}
@@ -5499,22 +5500,51 @@ namespace ts {
return <ObjectType>type;
}
function getGlobalValueSymbol(name: string): Symbol {
return getGlobalSymbol(name, SymbolFlags.Value, Diagnostics.Cannot_find_global_value_0);
function getGlobalValueSymbol(name: string, unchecked?: boolean): Symbol {
return getGlobalSymbol(name, SymbolFlags.Value, unchecked ? undefined : Diagnostics.Cannot_find_global_value_0);
}
function getGlobalTypeSymbol(name: string): Symbol {
return getGlobalSymbol(name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0);
function getGlobalTypeSymbol(name: string, unchecked?: boolean): Symbol {
return getGlobalSymbol(name, SymbolFlags.Type, unchecked ? undefined : Diagnostics.Cannot_find_global_type_0);
}
function getGlobalSymbol(name: string, meaning: SymbolFlags, diagnostic: DiagnosticMessage): Symbol {
return resolveName(undefined, name, meaning, diagnostic, name);
}
function getGlobalType(name: string, arity?: 0): ObjectType;
function getGlobalType(name: string, arity: number): GenericType;
function getGlobalType(name: string, arity = 0): ObjectType {
return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), arity);
function getGlobalType(name: string, arity?: 0, unchecked?: boolean): ObjectType;
function getGlobalType(name: string, arity: number, unchecked?: boolean): GenericType;
function getGlobalType(name: string, arity = 0, unchecked?: boolean): ObjectType {
const symbol = getGlobalTypeSymbol(name, unchecked);
return symbol || !unchecked ? getTypeOfGlobalSymbol(symbol, arity) : undefined;
}
function getGlobalESSymbolType(checked: boolean) {
return globalESSymbolType || (globalESSymbolType = getGlobalType("Symbol", 0, !checked)) || emptyObjectType;
}
function getGlobalAsyncIterableType(checked: boolean) {
return globalAsyncIterableType || (globalAsyncIterableType = getGlobalType("AsyncIterable", 1, !checked)) || emptyGenericType;
}
function getGlobalAsyncIteratorType(checked: boolean) {
return globalAsyncIteratorType || (globalAsyncIteratorType = getGlobalType("AsyncIterator", 1, !checked)) || emptyGenericType;
}
function getGlobalAsyncIterableIteratorType(checked: boolean) {
return globalAsyncIterableIteratorType || (globalAsyncIterableIteratorType = getGlobalType("AsyncIterableIterator", 1, !checked)) || emptyGenericType;
}
function getGlobalIterableType(checked: boolean) {
return globalIterableType || (globalIterableType = getGlobalType("Iterable", 1, !checked)) || emptyGenericType;
}
function getGlobalIteratorType(checked: boolean) {
return globalIteratorType || (globalIteratorType = getGlobalType("Iterator", 1, !checked)) || emptyGenericType;
}
function getGlobalIterableIteratorType(checked: boolean) {
return globalIterableIteratorType || (globalIterableIteratorType = getGlobalType("IterableIterator", 1, !checked)) || emptyGenericType;
}
/**
@@ -5545,19 +5575,19 @@ namespace ts {
}
function createAsyncIterableType(iteratedType: Type): Type {
return createTypeFromGenericGlobalType(getGlobalAsyncIterableType(), [iteratedType]);
return createTypeFromGenericGlobalType(getGlobalAsyncIterableType(/*checked*/ true), [iteratedType]);
}
function createAsyncIterableIteratorType(iteratedType: Type): Type {
return createTypeFromGenericGlobalType(getGlobalAsyncIterableIteratorType(), [iteratedType]);
return createTypeFromGenericGlobalType(getGlobalAsyncIterableIteratorType(/*checked*/ true), [iteratedType]);
}
function createIterableType(iteratedType: Type): Type {
return createTypeFromGenericGlobalType(getGlobalIterableType(), [iteratedType]);
return createTypeFromGenericGlobalType(getGlobalIterableType(/*checked*/ true), [iteratedType]);
}
function createIterableIteratorType(iteratedType: Type): Type {
return createTypeFromGenericGlobalType(getGlobalIterableIteratorType(), [iteratedType]);
return createTypeFromGenericGlobalType(getGlobalIterableIteratorType(/*checked*/ true), [iteratedType]);
}
function createArrayType(elementType: Type): ObjectType {
@@ -7061,7 +7091,7 @@ namespace ts {
if ((globalStringType === source && stringType === target) ||
(globalNumberType === source && numberType === target) ||
(globalBooleanType === source && booleanType === target) ||
(getGlobalESSymbolType() === source && esSymbolType === target)) {
(getGlobalESSymbolType(/*checked*/ false) === source && esSymbolType === target)) {
reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType);
}
}
@@ -8985,7 +9015,7 @@ namespace ts {
case SyntaxKind.ForInStatement:
return stringType;
case SyntaxKind.ForOfStatement:
return checkRightHandSideOfForOf((<ForOfStatement>parent).expression, (<ForOfStatement>parent).awaitKeyword !== undefined) || unknownType;
return checkRightHandSideOfForOf((<ForOfStatement>parent).expression, getForOfModifierKind(<ForOfStatement>parent)) || unknownType;
case SyntaxKind.BinaryExpression:
return getAssignedTypeOfBinaryExpression(<BinaryExpression>parent);
case SyntaxKind.DeleteExpression:
@@ -9029,8 +9059,7 @@ namespace ts {
return stringType;
}
if (node.parent.parent.kind === SyntaxKind.ForOfStatement) {
const isForAwaitOf = (<ForOfStatement>node.parent.parent).awaitKeyword !== undefined;
return checkRightHandSideOfForOf((<ForOfStatement>node.parent.parent).expression, isForAwaitOf) || unknownType;
return checkRightHandSideOfForOf((<ForOfStatement>node.parent.parent).expression, getForOfModifierKind(<ForOfStatement>node.parent.parent)) || unknownType;
}
return unknownType;
}
@@ -10838,7 +10867,7 @@ namespace ts {
const index = indexOf(arrayLiteral.elements, node);
return getTypeOfPropertyOfContextualType(type, "" + index)
|| getIndexTypeOfContextualType(type, IndexKind.Number)
|| getIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*checkAssignability*/ false);
|| getIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*checkAssignability*/ false, /*arrayLikeOnly*/ false);
}
return undefined;
}
@@ -11091,7 +11120,7 @@ namespace ts {
// if there is no index type / iterated type.
const restArrayType = checkExpression((<SpreadElement>e).expression, contextualMapper);
const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
getIteratedTypeOrElementType(restArrayType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*checkAssignability*/ false);
getIteratedTypeOrElementType(restArrayType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*checkAssignability*/ false, /*arrayLikeOnly*/ false);
if (restElementType) {
elementTypes.push(restElementType);
}
@@ -15207,8 +15236,12 @@ namespace ts {
error(node.type, Diagnostics.A_generator_cannot_have_a_void_type_annotation);
}
else {
const generatorElementType = getIteratedTypeOfIterableIterator(returnType) || anyType;
const iterableIteratorInstantiation = createIterableIteratorType(generatorElementType);
const generatorElementType = functionFlags & FunctionFlags.Async
? getIteratedTypeOfAsyncIterableIterator(returnType) || anyType // AsyncGenerator function
: getIteratedTypeOfIterableIterator(returnType) || anyType; // Generator function
const iterableIteratorInstantiation = functionFlags & FunctionFlags.Async
? createAsyncIterableIteratorType(generatorElementType) // AsyncGenerator function
: createIterableIteratorType(generatorElementType); // Generator function
// Naively, one could check that IterableIterator<any> is assignable to the return type annotation.
// However, that would not catch the error in the following case.
@@ -17108,7 +17141,7 @@ namespace ts {
checkGrammarForInOrForOfStatement(node);
if (node.kind === SyntaxKind.ForOfStatement) {
if ((<ForOfStatement>node).awaitKeyword) {
if (getForOfModifierKind(<ForOfStatement>node) === SyntaxKind.AwaitKeyword) {
if (languageVersion < ScriptTarget.ES2017) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.ForAwaitOfIncludes);
}
@@ -17128,7 +17161,7 @@ namespace ts {
}
else {
const varExpr = <Expression>node.initializer;
const iteratedType = checkRightHandSideOfForOf(node.expression, node.awaitKeyword !== undefined);
const iteratedType = checkRightHandSideOfForOf(node.expression, getForOfModifierKind(node));
// There may be a destructuring assignment on the left side
if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) {
@@ -17215,28 +17248,28 @@ namespace ts {
}
}
function checkRightHandSideOfForOf(rhsExpression: Expression, isForAwaitOf: boolean): Type {
function checkRightHandSideOfForOf(rhsExpression: Expression, modifierKind: SyntaxKind): Type {
const expressionType = checkNonNullExpression(rhsExpression);
return isForAwaitOf
return modifierKind === SyntaxKind.AwaitKeyword
? checkIteratedTypeOfIterableOrAsyncIterable(expressionType, rhsExpression)
: checkIteratedTypeOrElementType(expressionType, rhsExpression, /*allowStringInput*/ true);
: checkIteratedTypeOrElementType(expressionType, rhsExpression, /*allowStringInput*/ true, /*arrayLikeOnly*/ modifierKind === SyntaxKind.EachKeyword);
}
function checkIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean): Type {
function checkIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean, arrayLikeOnly?: boolean): Type {
if (isTypeAny(inputType)) {
return inputType;
}
return getIteratedTypeOrElementType(inputType, errorNode, allowStringInput, /*checkAssignability*/ true) || anyType;
return getIteratedTypeOrElementType(inputType, errorNode, allowStringInput, /*checkAssignability*/ true, arrayLikeOnly) || anyType;
}
/**
* When consuming an iterable type in a for..of, spread, or iterator destructuring assignment
* we want to get the iterated type of an iterable for ES2015 or later, or the iterated type
* of a pseudo-iterable or element type of an array like for ES2015 or earlier.
* of a iterable (if defined globally) or element type of an array like for ES2015 or earlier.
*/
function getIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean, checkAssignability: boolean): Type {
if (languageVersion >= ScriptTarget.ES2015) {
function getIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean, checkAssignability: boolean, arrayLikeOnly: boolean): Type {
if (!arrayLikeOnly && languageVersion >= ScriptTarget.ES2015) {
const iteratedType = getIteratedTypeOfIterable(inputType, errorNode);
if (checkAssignability && errorNode && iteratedType) {
checkTypeAssignableTo(inputType, createIterableType(iteratedType), errorNode);
@@ -17244,8 +17277,8 @@ namespace ts {
return iteratedType;
}
return allowStringInput
? getIteratedTypeOfPseudoIterableOrElementTypeOfArrayOrString(inputType, errorNode, checkAssignability)
: getIteratedTypeOfPseudoIterableOrElementTypeOfArray(inputType, errorNode, checkAssignability);
? getIteratedTypeOfIterableOrElementTypeOfArrayOrString(inputType, errorNode, checkAssignability, arrayLikeOnly)
: getIteratedTypeOfIterableOrElementTypeOfArray(inputType, errorNode, checkAssignability, arrayLikeOnly);
}
function checkIteratedTypeOfIterableOrAsyncIterable(asyncIterable: Type, errorNode: Node): Type {
@@ -17299,14 +17332,14 @@ namespace ts {
// As an optimization, if the type is instantiated directly using the
// globalAsyncIterableType (AsyncIterable<T>) or globalAsyncIterableIteratorType
// (AsyncIterableIterator<T>), then just grab its type argument.
if (isReferenceToType(type, getGlobalAsyncIterableType()) ||
isReferenceToType(type, getGlobalAsyncIterableIteratorType())) {
if (isReferenceToType(type, getGlobalAsyncIterableType(/*checked*/ false)) ||
isReferenceToType(type, getGlobalAsyncIterableIteratorType(/*checked*/ false))) {
return typeAsAsyncIterable.iteratedTypeOfAsyncIterable = (<GenericType>type).typeArguments[0];
}
if (allowIterables) {
if (isReferenceToType(type, getGlobalIterableType()) ||
isReferenceToType(type, getGlobalIterableIteratorType())) {
if (isReferenceToType(type, getGlobalIterableType(/*checked*/ false)) ||
isReferenceToType(type, getGlobalIterableIteratorType(/*checked*/ false))) {
return typeAsAsyncIterable.iteratedTypeOfAsyncIterable = (<GenericType>type).typeArguments[0];
}
}
@@ -17359,7 +17392,7 @@ namespace ts {
// As an optimization, if the type is instantiated directly using the
// globalAsyncIteratorType (AsyncIterator<number>), then just grab its type argument.
if (isReferenceToType(type, getGlobalAsyncIteratorType())) {
if (isReferenceToType(type, getGlobalAsyncIteratorType(/*checked*/ false))) {
return typeAsAsyncIterator.iteratedTypeOfAsyncIterator = (<GenericType>type).typeArguments[0];
}
@@ -17439,15 +17472,12 @@ namespace ts {
// As an optimization, if the type is instantiated directly using the
// globalIterableType (Iterable<T>) or globalIterableIteratorType (IterableIterator<T>),
// then just grab its type argument.
if (isReferenceToType(type, getGlobalIterableType()) ||
isReferenceToType(type, getGlobalIterableIteratorType())) {
if (isReferenceToType(type, getGlobalIterableType(/*checked*/ false)) ||
isReferenceToType(type, getGlobalIterableIteratorType(/*checked*/ false))) {
return typeAsIterable.iteratedTypeOfIterable = (<GenericType>type).typeArguments[0];
}
const propertyName = languageVersion >= ScriptTarget.ES2015
? getPropertyNameForKnownSymbolName("iterator")
: "___iterator__";
const propertyName = getPropertyNameForKnownSymbolName("iterator");
const iteratorMethod = getTypeOfPropertyOfType(type, propertyName);
if (isTypeAny(iteratorMethod)) {
return undefined;
@@ -17489,7 +17519,7 @@ namespace ts {
// As an optimization, if the type is instantiated directly using the globalIteratorType (Iterator<number>),
// then just grab its type argument.
if (isReferenceToType(type, getGlobalIteratorType())) {
if (isReferenceToType(type, getGlobalIteratorType(/*checked*/ false))) {
return typeAsIterator.iteratedTypeOfIterator = (<GenericType>type).typeArguments[0];
}
@@ -17523,10 +17553,9 @@ namespace ts {
}
/**
* A generator may have a return type of Iterator<T>, Iterable<T> (PseudoIterable<T> in
* ES5), or IterableIterator<T> (PseudoIterableIterator<T> in ES5). This function can be
* used to extract the iterated type from this return type for contextual typing and
* verifying signatures.
* A generator may have a return type of Iterator<T>, Iterable<T>, or IterableIterator<T>.
* This function can be used to extract the iterated type from this return type for
* contextual typing and verifying signatures.
*/
function getIteratedTypeOfIterableIterator(type: Type): Type {
if (isTypeAny(type)) {
@@ -17554,10 +17583,8 @@ namespace ts {
* 1. Some constituent is neither a string nor an array.
* 2. Some constituent is a string and target is less than ES5 (because in ES3 string is not indexable).
*/
function getIteratedTypeOfPseudoIterableOrElementTypeOfArrayOrString(arrayOrStringType: Type, errorNode: Node, checkAssignability: boolean): Type {
Debug.assert(languageVersion < ScriptTarget.ES2015);
const iteratedType = getIteratedTypeOfIterable(arrayOrStringType, /*errorNode*/ undefined);
function getIteratedTypeOfIterableOrElementTypeOfArrayOrString(arrayOrStringType: Type, errorNode: Node, checkAssignability: boolean, arrayLikeOnly: boolean): Type {
const iteratedType = !arrayLikeOnly && getIteratedTypeOfIterable(arrayOrStringType, /*errorNode*/ undefined);
if (iteratedType) {
if (checkAssignability && errorNode) {
checkTypeAssignableTo(arrayOrStringType, createIterableType(iteratedType), errorNode);
@@ -17578,6 +17605,7 @@ namespace ts {
else if (arrayOrStringType.flags & TypeFlags.StringLike) {
arrayType = neverType;
}
const hasStringConstituent = arrayOrStringType !== arrayType;
let reportedError = false;
if (hasStringConstituent) {
@@ -17603,8 +17631,12 @@ namespace ts {
// But if the input was just number, we want to say that number is not an array type
// or a string type.
const diagnostic = hasStringConstituent
? Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_an_iterator_method_that_returns_an_iterator
: Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_an_iterator_method_that_returns_an_iterator;
? arrayLikeOnly
? Diagnostics.Type_0_is_not_an_array_type
: Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator
: arrayLikeOnly
? Diagnostics.Type_0_is_not_an_array_type_or_a_string_type
: Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator;
error(errorNode, diagnostic, typeToString(arrayType));
}
}
@@ -17624,10 +17656,8 @@ namespace ts {
return arrayElementType;
}
function getIteratedTypeOfPseudoIterableOrElementTypeOfArray(inputType: Type, errorNode: Node, checkAssignability: boolean): Type {
Debug.assert(languageVersion < ScriptTarget.ES2015);
const iteratedType = getIteratedTypeOfIterable(inputType, /*errorNode*/ undefined);
function getIteratedTypeOfIterableOrElementTypeOfArray(inputType: Type, errorNode: Node, checkAssignability: boolean, arrayLikeOnly: boolean): Type {
const iteratedType = !arrayLikeOnly && getIteratedTypeOfIterable(inputType, /*errorNode*/ undefined);
if (iteratedType) {
if (checkAssignability && errorNode) {
checkTypeAssignableTo(inputType, createIterableType(iteratedType), errorNode);
@@ -17638,7 +17668,10 @@ namespace ts {
return getIndexTypeOfType(inputType, IndexKind.Number);
}
if (errorNode) {
error(errorNode, Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_an_iterator_method_that_returns_an_iterator, typeToString(inputType));
const diagnostic = arrayLikeOnly
? Diagnostics.Type_0_is_not_an_array_type
: Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator;
error(errorNode, diagnostic, typeToString(inputType));
}
return undefined;
}
@@ -19803,7 +19836,7 @@ namespace ts {
// for ( { a } of elems) {
// }
if (expr.parent.kind === SyntaxKind.ForOfStatement) {
const iteratedType = checkRightHandSideOfForOf((<ForOfStatement>expr.parent).expression, (<ForOfStatement>expr.parent).awaitKeyword !== undefined);
const iteratedType = checkRightHandSideOfForOf((<ForOfStatement>expr.parent).expression, getForOfModifierKind(<ForOfStatement>expr.parent));
return checkDestructuringAssignment(expr, iteratedType || unknownType);
}
// If this is from "for" initializer
@@ -20532,33 +20565,8 @@ namespace ts {
getGlobalPromiseConstructorSymbol = memoize(() => getGlobalValueSymbol("Promise"));
tryGetGlobalPromiseConstructorSymbol = memoize(() => getGlobalSymbol("Promise", SymbolFlags.Value, /*diagnostic*/ undefined) && getGlobalPromiseConstructorSymbol());
getGlobalPromiseConstructorLikeType = memoize(() => getGlobalType("PromiseConstructorLike"));
getGlobalTemplateStringsArrayType = memoize(() => getGlobalType("TemplateStringsArray"));
if (languageVersion >= ScriptTarget.ES2017) {
getGlobalAsyncIteratorType = memoize(() => getGlobalType("AsyncIterator", /*arity*/ 1));
getGlobalAsyncIterableType = memoize(() => getGlobalType("AsyncIterable", /*arity*/ 1));
getGlobalAsyncIterableIteratorType = memoize(() => getGlobalType("AsyncIterableIterator", /*arity*/ 1));
}
else {
getGlobalAsyncIteratorType = memoize(() => getGlobalType("PseudoAsyncIterator", /*arity*/ 1));
getGlobalAsyncIterableType = memoize(() => getGlobalType("PseudoAsyncIterable", /*arity*/ 1));
getGlobalAsyncIterableIteratorType = memoize(() => getGlobalType("PseudoAsyncIterableIterator", /*arity*/ 1));
}
if (languageVersion >= ScriptTarget.ES2015) {
getGlobalESSymbolType = memoize(() => getGlobalType("Symbol"));
getGlobalIterableType = memoize(() => getGlobalType("Iterable", /*arity*/ 1));
getGlobalIterableIteratorType = memoize(() => getGlobalType("IterableIterator", /*arity*/ 1));
}
else {
getGlobalESSymbolType = memoize(() => emptyObjectType);
getGlobalIterableType = memoize(() => getGlobalType("PseudoIterable", /*arity*/ 1));
getGlobalIterableIteratorType = memoize(() => getGlobalType("PseudoIterableIterator", /*arity*/ 1));
}
getGlobalIteratorType = memoize(() => getGlobalType("Iterator", /*arity*/ 1));
anyArrayType = createArrayType(anyType);
autoArrayType = createArrayType(autoType);
@@ -21277,9 +21285,9 @@ namespace ts {
return true;
}
if (forInOrOfStatement.kind === SyntaxKind.ForOfStatement && forInOrOfStatement.awaitKeyword) {
if (forInOrOfStatement.kind === SyntaxKind.ForOfStatement && getForOfModifierKind(forInOrOfStatement) === SyntaxKind.AwaitKeyword) {
if ((forInOrOfStatement.flags & NodeFlags.AwaitContext) === NodeFlags.None) {
return grammarErrorOnNode(forInOrOfStatement.awaitKeyword, Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator);
return grammarErrorOnNode(forInOrOfStatement.modifierToken, Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator);
}
}
+10 -2
View File
@@ -1463,7 +1463,7 @@
"category": "Error",
"code": 2460
},
"Type '{0}' is not an array type or does not have an '__iterator__()' method that returns an iterator.": {
"Type '{0}' is not an array type.": {
"category": "Error",
"code": 2461
},
@@ -1587,7 +1587,7 @@
"category": "Error",
"code": 2494
},
"Type '{0}' is not an array type or a string type or does not have an '__iterator__()' method that returns an iterator.": {
"Type '{0}' is not an array type or a string type.": {
"category": "Error",
"code": 2495
},
@@ -1783,6 +1783,14 @@
"category": "Error",
"code": 2543
},
"Type '{0}' is not an array type or does not have a '[Symbol.iterator]()' method that returns an iterator.": {
"category": "Error",
"code": 2544
},
"Type '{0}' is not an array type or a string type or does not have a '[Symbol.iterator]()' method that returns an iterator.": {
"category": "Error",
"code": 2545
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
+1 -1
View File
@@ -1368,7 +1368,7 @@ namespace ts {
function emitForOfStatement(node: ForOfStatement) {
const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos);
write(" ");
emitWithSuffix(node.awaitKeyword, " ");
emitWithSuffix(node.modifierToken, " ");
writeToken(SyntaxKind.OpenParenToken, openParenPos);
emitForBinding(node.initializer);
write(" of ");
+15 -8
View File
@@ -926,17 +926,18 @@ namespace ts {
return node;
}
export function createForOf(initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) {
export function createForOf(modifierToken: AwaitKeywordToken | EachKeywordToken, initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) {
const node = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, location);
node.modifierToken = modifierToken;
node.initializer = initializer;
node.expression = expression;
node.statement = statement;
return node;
}
export function updateForOf(node: ForOfStatement, initializer: ForInitializer, expression: Expression, statement: Statement) {
if (node.initializer !== initializer || node.expression !== expression || node.statement !== statement) {
return updateNode(createForOf(initializer, expression, statement, node), node);
export function updateForOf(node: ForOfStatement, modifierToken: AwaitKeywordToken | EachKeywordToken, initializer: ForInitializer, expression: Expression, statement: Statement) {
if (node.modifierToken !== modifierToken || node.initializer !== initializer || node.expression !== expression || node.statement !== statement) {
return updateNode(createForOf(modifierToken, initializer, expression, statement, node), node);
}
return node;
}
@@ -1768,7 +1769,7 @@ namespace ts {
scoped: false,
text: `
var __values = (this && this.__values) || function (o) {
var i = o.__iterator__ || 0, d;
var i = typeof Symbol === "function" && o[Symbol.iterator] || 0, d;
return i ? i.call(o) : { next: function () { return { done: d = d || i >= o.length, value: d ? void 0 : o[i++] }; } };
};`
};
@@ -1827,7 +1828,7 @@ namespace ts {
scoped: false,
text: `
var __read = (this && this.__read) || function (o, n) {
if (!(m = o.__iterator__)) return o;
if (!(m = typeof Symbol === "function" && o[Symbol.iterator])) return o;
var m, i = m.call(o), ar = [], r, e;
try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); }
catch (error) { e = { error: error }; }
@@ -1906,8 +1907,14 @@ namespace ts {
}
}
// Utilities
export function insertLeadingStatement(dest: Statement, source: Statement) {
if (isBlock(dest)) {
return updateBlock(dest, createNodeArray([source, ...dest.statements], dest.statements));
}
else {
return createBlock(createNodeArray([dest, source]), /*location*/ undefined, /*multiLine*/ true);
}
}
export interface CallBinding {
target: LeftHandSideExpression;
+4 -4
View File
@@ -240,7 +240,7 @@ namespace ts {
visitNode(cbNode, (<ForInStatement>node).expression) ||
visitNode(cbNode, (<ForInStatement>node).statement);
case SyntaxKind.ForOfStatement:
return visitNode(cbNode, (<ForOfStatement>node).awaitKeyword) ||
return visitNode(cbNode, (<ForOfStatement>node).modifierToken) ||
visitNode(cbNode, (<ForOfStatement>node).initializer) ||
visitNode(cbNode, (<ForOfStatement>node).expression) ||
visitNode(cbNode, (<ForOfStatement>node).statement);
@@ -4427,7 +4427,7 @@ namespace ts {
function parseForOrForInOrForOfStatement(): Statement {
const pos = getNodePos();
parseExpected(SyntaxKind.ForKeyword);
const awaitKeyword = parseOptionalToken(SyntaxKind.AwaitKeyword);
const modifierToken = parseOptionalToken(SyntaxKind.AwaitKeyword) || parseOptionalToken(SyntaxKind.EachKeyword);
parseExpected(SyntaxKind.OpenParenToken);
let initializer: VariableDeclarationList | Expression = undefined;
@@ -4440,9 +4440,9 @@ namespace ts {
}
}
let forOrForInOrForOfStatement: IterationStatement;
if (awaitKeyword ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {
if (modifierToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {
const forOfStatement = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, pos);
forOfStatement.awaitKeyword = awaitKeyword;
forOfStatement.modifierToken = modifierToken;
forOfStatement.initializer = initializer;
forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher);
parseExpected(SyntaxKind.CloseParenToken);
+1
View File
@@ -126,6 +126,7 @@ namespace ts {
"yield": SyntaxKind.YieldKeyword,
"async": SyntaxKind.AsyncKeyword,
"await": SyntaxKind.AwaitKeyword,
"each": SyntaxKind.EachKeyword,
"of": SyntaxKind.OfKeyword,
"{": SyntaxKind.OpenBraceToken,
"}": SyntaxKind.CloseBraceToken,
+9 -9
View File
@@ -154,7 +154,7 @@ namespace ts {
function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
const enclosedStatement = getEnclosedStatement(node);
if (enclosedStatement.statement.kind === SyntaxKind.ForOfStatement &&
(<ForOfStatement>enclosedStatement.statement).awaitKeyword) {
(<ForOfStatement>enclosedStatement.statement).modifierToken) {
return visitForOfStatement(<ForOfStatement>node.statement, enclosedStatement.enclosingLabeledStatements);
}
@@ -162,7 +162,7 @@ namespace ts {
}
function visitForOfStatement(node: ForOfStatement, enclosingLabeledStatements: LabeledStatement[]): VisitResult<Statement> {
if (!node.awaitKeyword) return visitEachChild(node, visitor, context);
if (!node.modifierToken) return visitEachChild(node, visitor, context);
let bodyLocation: TextRange;
let statementsLocation: TextRange;
@@ -774,8 +774,8 @@ namespace ts {
scoped: false,
text: `
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
var g = generator.apply(thisArg, _arguments || []), q = [], c;
return { next: verb("next"), "throw": verb("throw"), "return": verb("return"), __asyncIterator__: function () { return this; } };
var g = generator.apply(thisArg, _arguments || []), q = [], c, i;
return i = { next: verb("next"), "throw": verb("throw"), "return": verb("return") }, i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { return function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]), next(); }); }; }
function next() { if (!c && q.length) resume((c = q.shift())[0], c[1]); }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(c[3], e); } }
@@ -808,9 +808,9 @@ namespace ts {
name: "typescript:asyncValues",
scoped: false,
text: `
var __asyncValues = (this && this.__asyncIterator) || function (o, iterator) {
var m;
return (m = o.__asyncIterator__) ? m.call(o) : typeof __values === "function" ? __values(o) : o[iterator || Symbol.iterator]();
var __asyncValues = (this && this.__asyncIterator) || function (o) {
var m = o[Symbol.asyncIterator];
return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator]();
};`
};
@@ -832,9 +832,9 @@ namespace ts {
name: "typescript:asyncDelegator",
scoped: false,
text: `
var __asyncDelegator = (this && this.__asyncDelegator) || function (o, iterator) {
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
var i = { next: verb("next"), "throw": verb("throw", function (e) { throw e; }), "return": verb("return", function (v) { return { value: v, done: true }; }) };
return o = __asyncValues(o, iterator), i[iterator || Symbol.iterator] = function () { return this; }, i;
return o = __asyncValues(o), i[Symbol.iterator] = function () { return this; }, i;
function verb(n, f) { return function (v) { return { value: ["delegate", (o[n] || f).call(o, v)], done: false }; }; }
};`
};
+1
View File
@@ -234,6 +234,7 @@ namespace ts {
: createBlock(append(leadingStatements, statement), statement, /*multiLine*/ true);
return updateForOf(
node,
node.modifierToken,
createVariableDeclarationList(
[
createVariableDeclaration(temp, /*type*/ undefined, /*initializer*/ undefined, node.initializer)
+2 -2
View File
@@ -3169,8 +3169,8 @@ namespace ts {
priority: 6,
text: `
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
return { next: verb(0), "throw": verb(1), "return": verb(2), __iterator__: function () { return this; } };
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
@@ -1261,6 +1261,7 @@ namespace ts {
node = updateForOf(
node,
node.modifierToken,
visitForInitializer(node.initializer),
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock)
+30
View File
@@ -464,6 +464,9 @@ namespace ts {
// TypeScript namespace or external module import.
return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
case SyntaxKind.ForOfStatement:
return visitForOfStatement(<ForOfStatement>node);
default:
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);
@@ -2218,6 +2221,33 @@ namespace ts {
return parameter;
}
function visitForOfStatement(node: ForOfStatement): Statement {
if (getForOfModifierKind(node) !== SyntaxKind.EachKeyword) {
return visitEachChild(node, visitor, context);
}
const counter = createLoopVariable();
const rhsReference = node.expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>node.expression).text)
: createTempVariable(/*recordTempVariable*/ undefined);
const binding = createForOfBindingStatement(node.initializer, createElementAccess(rhsReference, counter));
const newNode = createFor(
createVariableDeclarationList([
createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)),
createVariableDeclaration(rhsReference, /*type*/ undefined, node.expression, /*location*/ node.expression)
]),
createLessThan(
counter,
createPropertyAccess(rhsReference, "length"),
/*location*/ node.expression
),
createPostfixIncrement(counter, /*location*/ node.expression),
insertLeadingStatement(node.statement, binding)
);
return visitNode(newNode, visitor, isStatement);
}
/**
* Visits a variable statement in a namespace.
*
+3 -1
View File
@@ -166,6 +166,7 @@ namespace ts {
BooleanKeyword,
ConstructorKeyword,
DeclareKeyword,
EachKeyword,
GetKeyword,
IsKeyword,
KeyOfKeyword,
@@ -519,6 +520,7 @@ namespace ts {
export type AtToken = Token<SyntaxKind.AtToken>;
export type ReadonlyToken = Token<SyntaxKind.ReadonlyKeyword>;
export type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
export type EachKeywordToken = Token<SyntaxKind.EachKeyword>;
export type Modifier
= Token<SyntaxKind.AbstractKeyword>
@@ -1617,7 +1619,7 @@ namespace ts {
export interface ForOfStatement extends IterationStatement {
kind: SyntaxKind.ForOfStatement;
awaitKeyword?: AwaitKeywordToken;
modifierToken?: AwaitKeywordToken | EachKeywordToken;
initializer: ForInitializer;
expression: Expression;
}
+5 -4
View File
@@ -874,6 +874,11 @@ namespace ts {
return false;
}
export function getForOfModifierKind(node: ForOfStatement) {
return node.modifierToken
&& node.modifierToken.kind;
}
export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement {
switch (node.kind) {
case SyntaxKind.ForStatement:
@@ -3668,10 +3673,6 @@ namespace ts {
return node.symbol && getDeclarationOfKind(node.symbol, kind) === node;
}
export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) {
return isExternalModule(node) || compilerOptions.isolatedModules;
}
// Node tests
//
// All node tests in the following list should *not* reference parent pointers so that
+1
View File
@@ -989,6 +989,7 @@ namespace ts {
case SyntaxKind.ForOfStatement:
return updateForOf(<ForOfStatement>node,
(<ForOfStatement>node).modifierToken,
visitNode((<ForOfStatement>node).initializer, visitor, isForInitializer),
visitNode((<ForOfStatement>node).expression, visitor, isExpression),
visitNode((<ForOfStatement>node).statement, visitor, isStatement, /*optional*/ false, liftToBlock));
+11
View File
@@ -8,6 +8,17 @@ interface SymbolConstructor {
readonly iterator: symbol;
}
interface IteratorResult<T> {
done: boolean;
value: T;
}
interface Iterator<T> {
next(value?: any): IteratorResult<T>;
return?(value?: any): IteratorResult<T>;
throw?(e?: any): IteratorResult<T>;
}
interface Iterable<T> {
[Symbol.iterator](): Iterator<T>;
}
@@ -1,4 +1,5 @@
/// <reference path="lib.es2015.symbol.d.ts" />
/// <reference path="lib.es2015.iterable.d.ts" />
interface SymbolConstructor {
/**
+1
View File
@@ -2,3 +2,4 @@
/// <reference path="lib.es2017.object.d.ts" />
/// <reference path="lib.es2017.sharedmemory.d.ts" />
/// <reference path="lib.es2017.string.d.ts" />
/// <reference path="lib.es2017.asynciterable.d.ts" />
-33
View File
@@ -1338,39 +1338,6 @@ interface PromiseLike<T> {
onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>;
}
interface IteratorResult<T> {
done: boolean;
value: T;
}
interface Iterator<T> {
next(value?: any): IteratorResult<T>;
return?(value?: any): IteratorResult<T>;
throw?(e?: any): IteratorResult<T>;
}
interface PseudoIterable<T> {
__iterator__(): Iterator<T>;
}
interface PseudoIterableIterator<T> extends Iterator<T> {
__iterator__(): PseudoIterableIterator<T>;
}
interface PseudoAsyncIterator<T> {
next(value?: any): PromiseLike<IteratorResult<T>>;
return?(value?: any): PromiseLike<IteratorResult<T>>;
throw?(e?: any): PromiseLike<IteratorResult<T>>;
}
interface PseudoAsyncIterable<T> {
__asyncIterator__(): PseudoAsyncIterator<T>;
}
interface PseudoAsyncIterableIterator<T> extends PseudoAsyncIterator<T> {
__asyncIterator__(): PseudoAsyncIterableIterator<T>;
}
interface ArrayLike<T> {
readonly length: number;
readonly [n: number]: T;
+1 -1
View File
@@ -1,2 +1,2 @@
/// <reference path="lib.es2017.d.ts" />
/// <reference path="lib.esnext.asynciterable.d.ts" />
/// <reference path="lib.es2017.asynciterable.d.ts" />