From bd867785bc199dabf0637f96510d3dc5e91b284c Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 9 Nov 2016 14:40:47 -0800 Subject: [PATCH] type checking for pseudoiterable --- src/compiler/checker.ts | 202 ++++++++++++++------- src/compiler/commandLineParser.ts | 2 + src/compiler/diagnosticMessages.json | 4 +- src/compiler/factory.ts | 23 +-- src/compiler/transformers/destructuring.ts | 47 +++-- src/compiler/transformers/es2015.ts | 3 +- src/compiler/transformers/generators.ts | 16 +- src/compiler/utilities.ts | 4 + src/lib/es2015.iterable.d.ts | 105 +++++------ src/lib/es5.d.ts | 10 +- 10 files changed, 240 insertions(+), 176 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f79f0e33d80..d8d6a7fff65 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10,6 +10,25 @@ namespace ts { let nextMergeId = 1; let nextFlowId = 1; + const enum EmitHelper { + Extends = 1 << 0, + Assign = 1 << 1, + Decorate = 1 << 2, + Metadata = 1 << 3, + Param = 1 << 4, + Awaiter = 1 << 5, + Generator = 1 << 6, + Values = 1 << 7, + Step = 1 << 8, + Close = 1 << 9, + Read = 1 << 10, + Spread = 1 << 11, + ForOfIncludes = Values | Step | Close, + SpreadIncludes = Read | Spread, + FirstEmitHelper = Extends, + LastEmitHelper = Spread + } + export function getNodeId(node: Node): number { if (!node.id) { node.id = nextNodeId; @@ -38,6 +57,8 @@ namespace ts { // is because diagnostics can be quite expensive, and we want to allow hosts to bail out if // they no longer need the information (for example, if the user started editing again). let cancellationToken: CancellationToken; + let requestedExternalHelpers: EmitHelper; + let externalHelpersModule: Symbol; const Symbol = objectAllocator.getSymbolConstructor(); const Type = objectAllocator.getTypeConstructor(); @@ -10430,7 +10451,7 @@ namespace ts { const index = indexOf(arrayLiteral.elements, node); return getTypeOfPropertyOfContextualType(type, "" + index) || getIndexTypeOfContextualType(type, IndexKind.Number) - || getIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false); + || getIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*checkAssignability*/ false); } return undefined; } @@ -10649,6 +10670,10 @@ namespace ts { // with this type. It is neither affected by it, nor does it propagate it to its operand. // So the fact that contextualMapper is passed is not important, because the operand of a spread // element is not contextually typed. + if (languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.SpreadIncludes); + } + const arrayOrIterableType = checkExpressionCached(node.expression, contextualMapper); return checkIteratedTypeOrElementType(arrayOrIterableType, node.expression, /*allowStringInput*/ false); } @@ -10679,7 +10704,7 @@ namespace ts { // if there is no index type / iterated type. const restArrayType = checkExpression((e).expression, contextualMapper); const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) || - getIteratedTypeOrElementType(restArrayType, /*errorNode*/ undefined, /*allowStringInput*/ false); + getIteratedTypeOrElementType(restArrayType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*checkAssignability*/ false); if (restElementType) { elementTypes.push(restElementType); } @@ -11024,6 +11049,10 @@ namespace ts { function checkJsxSpreadAttribute(node: JsxSpreadAttribute, elementAttributesType: Type, nameTable: Map) { const type = checkExpression(node.expression); const props = getPropertiesOfType(type); + if (compilerOptions.jsx === JsxEmit.React) { + checkEmitHelpers(node, EmitHelper.Assign); + } + for (const prop of props) { // Is there a corresponding property in the element attributes type? Skip checking of properties // that have already been assigned to, as these are not actually pushed into the resulting type @@ -13791,6 +13820,10 @@ namespace ts { } function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type { + if (languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.Read); + } + // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). @@ -14206,6 +14239,10 @@ namespace ts { } } + if (node.asteriskToken && languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.Values); + } + if (node.expression) { const func = getContainingFunction(node); // If the user's code is syntactically correct, the func should always have a star. After all, @@ -14666,6 +14703,17 @@ namespace ts { checkGrammarFunctionLikeDeclaration(node); } + if (isAsyncFunctionLike(node)) { + checkEmitHelpers(node, EmitHelper.Awaiter); + if (languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.Generator); + } + } + + if (isSyntacticallyValidGenerator(node) && languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.Generator); + } + checkTypeParameters(node.typeParameters); forEach(node.parameters, checkParameter); @@ -15792,7 +15840,15 @@ namespace ts { error(node, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning); } + checkEmitHelpers(node, EmitHelper.Decorate); + + if (node.kind === SyntaxKind.Parameter) { + checkEmitHelpers(node, EmitHelper.Param); + } + if (compilerOptions.emitDecoratorMetadata) { + checkEmitHelpers(node, EmitHelper.Metadata); + // we only need to perform these checks if we are emitting serialized type metadata for the target of a decorator. switch (node.kind) { case SyntaxKind.ClassDeclaration: @@ -16374,6 +16430,10 @@ namespace ts { // For a binding pattern, check contained binding elements if (isBindingPattern(node.name)) { + if (node.name.kind === SyntaxKind.ArrayBindingPattern && languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.Read); + } + forEach((node.name).elements, checkSourceElement); } // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body @@ -16545,6 +16605,10 @@ namespace ts { function checkForOfStatement(node: ForOfStatement): void { checkGrammarForInOrForOfStatement(node); + if (node.kind === SyntaxKind.ForOfStatement && languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.ForOfIncludes); + } + // 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 checkRightHandSideOfForOf. @@ -16651,7 +16715,8 @@ namespace ts { if (isTypeAny(inputType)) { return inputType; } - return getIteratedTypeOrElementType(inputType, errorNode, allowStringInput) || unknownType; + + return getIteratedTypeOrElementType(inputType, errorNode, allowStringInput, /*checkAssignability*/ true) || anyType; } /** @@ -16659,13 +16724,17 @@ namespace ts { * 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. */ - function getIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean): Type { + function getIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean, checkAssignability: boolean): Type { if (languageVersion >= ScriptTarget.ES2015) { - return getIteratedTypeOfIterable(inputType, errorNode); + const iteratedType = getIteratedTypeOfIterable(inputType, errorNode); + if (checkAssignability && errorNode && iteratedType) { + checkTypeAssignableTo(inputType, createIterableType(iteratedType), errorNode); + } + return iteratedType; } return allowStringInput - ? getIteratedTypeOfPseudoIterableOrElementTypeOfArrayOrString(inputType, errorNode) - : getIteratedTypeOfPseudoIterableOrElementTypeOfArray(inputType, errorNode); + ? getIteratedTypeOfPseudoIterableOrElementTypeOfArrayOrString(inputType, errorNode, checkAssignability) + : getIteratedTypeOfPseudoIterableOrElementTypeOfArray(inputType, errorNode, checkAssignability); } /** @@ -16821,12 +16890,15 @@ 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): Type { + function getIteratedTypeOfPseudoIterableOrElementTypeOfArrayOrString(arrayOrStringType: Type, errorNode: Node, checkAssignability: boolean): Type { Debug.assert(languageVersion < ScriptTarget.ES2015); - const elementType = getIteratedTypeOfIterable(arrayOrStringType, /*errorNode*/ undefined); - if (elementType) { - return elementType; + const iteratedType = getIteratedTypeOfIterable(arrayOrStringType, /*errorNode*/ undefined); + if (iteratedType) { + if (checkAssignability && errorNode) { + checkTypeAssignableTo(arrayOrStringType, createIterableType(iteratedType), errorNode); + } + return iteratedType; } // After we remove all types that are StringLike, we will know if there was a string constituent @@ -16863,8 +16935,8 @@ 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 - : Diagnostics.Type_0_is_not_an_array_type_or_a_string_type; + ? 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; error(errorNode, diagnostic, typeToString(arrayType)); } } @@ -16884,18 +16956,21 @@ namespace ts { return arrayElementType; } - function getIteratedTypeOfPseudoIterableOrElementTypeOfArray(inputType: Type, errorNode: Node): Type { + function getIteratedTypeOfPseudoIterableOrElementTypeOfArray(inputType: Type, errorNode: Node, checkAssignability: boolean): Type { Debug.assert(languageVersion < ScriptTarget.ES2015); - const elementType = getIteratedTypeOfIterable(inputType, /*errorNode*/ undefined); - if (elementType) { - return elementType; + const iteratedType = getIteratedTypeOfIterable(inputType, /*errorNode*/ undefined); + if (iteratedType) { + if (checkAssignability && errorNode) { + checkTypeAssignableTo(inputType, createIterableType(iteratedType), errorNode); + } + return iteratedType; } if (isArrayLikeType(inputType)) { return getIndexTypeOfType(inputType, IndexKind.Number); } if (errorNode) { - error(errorNode, Diagnostics.Type_0_is_not_an_array_type, typeToString(inputType)); + error(errorNode, Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_an_iterator_method_that_returns_an_iterator, typeToString(inputType)); } return undefined; } @@ -17281,6 +17356,10 @@ namespace ts { const baseTypeNode = getClassExtendsHeritageClauseElement(node); if (baseTypeNode) { + if (languageVersion < ScriptTarget.ES2015) { + checkEmitHelpers(node, EmitHelper.Extends); + } + const baseTypes = getBaseTypes(type); if (baseTypes.length && produceDiagnostics) { const baseType = baseTypes[0]; @@ -19714,8 +19793,6 @@ namespace ts { // Initialize global symbol table let augmentations: LiteralExpression[][]; - let requestedExternalEmitHelpers: NodeFlags = 0; - let firstFileRequestingExternalHelpers: SourceFile; for (const file of host.getSourceFiles()) { if (!isExternalOrCommonJsModule(file)) { mergeSymbolTable(globals, file.locals); @@ -19735,15 +19812,6 @@ namespace ts { } } } - if ((compilerOptions.isolatedModules || isExternalModule(file)) && !file.isDeclarationFile) { - const fileRequestedExternalEmitHelpers = file.flags & NodeFlags.EmitHelperFlags; - if (fileRequestedExternalEmitHelpers) { - requestedExternalEmitHelpers |= fileRequestedExternalEmitHelpers; - if (firstFileRequestingExternalHelpers === undefined) { - firstFileRequestingExternalHelpers = file; - } - } - } } if (augmentations) { @@ -19808,53 +19876,55 @@ namespace ts { const symbol = getGlobalSymbol("ReadonlyArray", SymbolFlags.Type, /*diagnostic*/ undefined); globalReadonlyArrayType = symbol && getTypeOfGlobalSymbol(symbol, /*arity*/ 1); anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; + } - // If we have specified that we are importing helpers, we should report global - // errors if we cannot resolve the helpers external module, or if it does not have - // the necessary helpers exported. - if (compilerOptions.importHelpers && firstFileRequestingExternalHelpers) { - // Find the first reference to the helpers module. - const helpersModule = resolveExternalModule( - firstFileRequestingExternalHelpers, - externalHelpersModuleNameText, - Diagnostics.Cannot_find_module_0, - /*errorNode*/ undefined); - - // If we found the module, report errors if it does not have the necessary exports. - if (helpersModule) { - const exports = helpersModule.exports; - if (requestedExternalEmitHelpers & NodeFlags.HasClassExtends && languageVersion < ScriptTarget.ES2015) { - verifyHelperSymbol(exports, "__extends", SymbolFlags.Value); - } - if (requestedExternalEmitHelpers & NodeFlags.HasJsxSpreadAttributes && compilerOptions.jsx !== JsxEmit.Preserve) { - verifyHelperSymbol(exports, "__assign", SymbolFlags.Value); - } - if (requestedExternalEmitHelpers & NodeFlags.HasDecorators) { - verifyHelperSymbol(exports, "__decorate", SymbolFlags.Value); - if (compilerOptions.emitDecoratorMetadata) { - verifyHelperSymbol(exports, "__metadata", SymbolFlags.Value); - } - } - if (requestedExternalEmitHelpers & NodeFlags.HasParamDecorators) { - verifyHelperSymbol(exports, "__param", SymbolFlags.Value); - } - if (requestedExternalEmitHelpers & NodeFlags.HasAsyncFunctions) { - verifyHelperSymbol(exports, "__awaiter", SymbolFlags.Value); - if (languageVersion < ScriptTarget.ES2015) { - verifyHelperSymbol(exports, "__generator", SymbolFlags.Value); + function checkEmitHelpers(node: Node, helpers: EmitHelper) { + if ((requestedExternalHelpers & helpers) !== helpers && compilerOptions.importHelpers) { + const sourceFile = getSourceFileOfNode(node); + if (isEffectiveExternalModule(sourceFile, compilerOptions)) { + const helpersModule = resolveHelpersModule(sourceFile); + if (helpersModule !== unknownSymbol) { + const uncheckedHelpers = helpers & ~requestedExternalHelpers; + for (let helper = EmitHelper.FirstEmitHelper; helper <= EmitHelper.LastEmitHelper; helper <<= 1) { + if (uncheckedHelpers & helper) { + const name = getHelperName(helper); + const symbol = getSymbol(helpersModule.exports, escapeIdentifier(name), SymbolFlags.Value); + if (!symbol) { + diagnostics.add(createFileDiagnostic(sourceFile, 0, 0, Diagnostics.Module_0_has_no_exported_member_1, externalHelpersModuleNameText, name)); + } + } } } + requestedExternalHelpers |= helpers; } } } - function verifyHelperSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags) { - const symbol = getSymbol(symbols, escapeIdentifier(name), meaning); - if (!symbol) { - error(/*location*/ undefined, Diagnostics.Module_0_has_no_exported_member_1, externalHelpersModuleNameText, name); + function getHelperName(helper: EmitHelper) { + switch (helper) { + case EmitHelper.Extends: return "__extends"; + case EmitHelper.Assign: return "__assign"; + case EmitHelper.Decorate: return "__decorate"; + case EmitHelper.Metadata: return "__metadata"; + case EmitHelper.Param: return "__param"; + case EmitHelper.Awaiter: return "__awaiter"; + case EmitHelper.Generator: return "__generator"; + case EmitHelper.Values: return "__values"; + case EmitHelper.Step: return "__step"; + case EmitHelper.Close: return "__close"; + case EmitHelper.Read: return "__read"; + case EmitHelper.Spread: return "__spread"; } } + function resolveHelpersModule(node: SourceFile) { + if (!externalHelpersModule) { + externalHelpersModule = resolveExternalModule(node, externalHelpersModuleNameText, Diagnostics.Cannot_find_module_0, node) || unknownSymbol; + } + + return externalHelpersModule; + } + function createInstantiatedPromiseLikeType(): ObjectType { const promiseLikeType = getGlobalPromiseLikeType(); if (promiseLikeType !== emptyGenericType) { diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 50399fd5c38..fd5be3d5449 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -417,6 +417,8 @@ namespace ts { "webworker": "lib.webworker.d.ts", "scripthost": "lib.scripthost.d.ts", // ES2015 Or ESNext By-feature options + "iterator": "lib.iterator.d.ts", + "pseudoiterable": "lib.pseudoiterable.d.ts", "es2015.core": "lib.es2015.core.d.ts", "es2015.collection": "lib.es2015.collection.d.ts", "es2015.generator": "lib.es2015.generator.d.ts", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9a353e6fb36..920da07a0ce 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1451,7 +1451,7 @@ "category": "Error", "code": 2460 }, - "Type '{0}' is not an array type.": { + "Type '{0}' is not an array type or does not have an '__iterator__()' method that returns an iterator.": { "category": "Error", "code": 2461 }, @@ -1575,7 +1575,7 @@ "category": "Error", "code": 2494 }, - "Type '{0}' is not an array type or a string type.": { + "Type '{0}' is not an array type or a string type or does not have an '__iterator__()' method that returns an iterator.": { "category": "Error", "code": 2495 }, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 020e60989a2..4008239543f 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1749,7 +1749,7 @@ namespace ts { text: ` var __close = (this && this.__close) || function (r) { var m = !(r && r.done) && r.iterator["return"]; - if (m) m.call(r.iterator); + if (m) return m.call(r.iterator); };` }; @@ -1768,20 +1768,17 @@ namespace ts { scoped: false, text: ` var __read = (this && this.__read) || function (o, n) { - var m = o.__iterator__; - if (!m) return o; - var r = { iterator: m.call(o) }, ar = [], e; - try { while ((n === void 0 || n-- > 0) && __step(r)) ar.push(r.result.value); } + if (!(m = o.__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 }; } - finally { try { __close(r); } finally { if (e) throw e.error; } } + finally { try { if (m = !(r && r.done) && i["return"]) m.call(i); } finally { if (e) throw e.error; } } return ar; };` }; export function createReadHelper(context: TransformationContext, iteratorRecord: Expression, count: number | undefined, location?: TextRange) { - context.requestEmitHelper(stepHelper); context.requestEmitHelper(readHelper); - context.requestEmitHelper(closeHelper); return createCall( getHelperName("__read"), /*typeArguments*/ undefined, @@ -1815,10 +1812,6 @@ namespace ts { // Utilities - export function toFunctionBody(node: ConciseBody) { - return isBlock(node) ? node : createBlock([createReturn(node, /*location*/ node)], /*location*/ node); - } - export interface CallBinding { target: LeftHandSideExpression; thisArg: Expression; @@ -1858,6 +1851,10 @@ namespace ts { thisArg = createThis(); target = languageVersion < ScriptTarget.ES2015 ? createIdentifier("_super", /*location*/ callee) : callee; } + else if (getEmitFlags(callee) & EmitFlags.HelperName) { + thisArg = createVoidZero(); + target = parenthesizeForAccess(callee); + } else { switch (callee.kind) { case SyntaxKind.PropertyAccessExpression: { @@ -2164,8 +2161,6 @@ namespace ts { return qualifiedName; } - // Utilities - export function convertToFunctionBody(node: ConciseBody) { return isBlock(node) ? node : createBlock([createReturn(node, /*location*/ node)], /*location*/ node); } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index ba3f97f0d4d..8eb123bf56b 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -247,16 +247,30 @@ namespace ts { if (isEffectiveBindingPattern(bindingTarget)) { const elements = getElementsOfEffectiveBindingPattern(bindingTarget); const numElements = elements.length; - if (isEffectiveObjectBindingPattern(bindingTarget)) { - if (numElements !== 1) { - // For anything other than a single-element destructuring we need to generate a temporary - // to ensure value is evaluated exactly once. Additionally, if we have zero elements - // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, - // so in that case, we'll intentionally create that temporary. - const reuseIdentifierExpressions = !isDeclarationBindingElement(bindingElement) || numElements !== 0; - boundValue = ensureIdentifier(boundValue, reuseIdentifierExpressions, emitTempVariableAssignment, location); - } + if (isEffectiveArrayBindingPattern(bindingTarget) && !isArrayLiteralExpression(boundValue)) { + // Read the elements of the iterable into an array + boundValue = emitTempVariableAssignment( + createReadHelper( + context, + boundValue, + isEffectiveBindingElementWithRest(elements[numElements - 1]) + ? undefined + : numElements, + location + ), + location + ); + } + else if (numElements !== 1) { + // For anything other than a single-element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. Additionally, if we have zero elements + // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, + // so in that case, we'll intentionally create that temporary. + const reuseIdentifierExpressions = !isDeclarationBindingElement(bindingElement) || numElements !== 0; + boundValue = ensureIdentifier(boundValue, reuseIdentifierExpressions, emitTempVariableAssignment, location); + } + if (isEffectiveObjectBindingPattern(bindingTarget)) { for (const element of elements) { // Rewrite element to a declaration with an initializer that fetches property flattenEffectiveBindingElement( @@ -275,21 +289,6 @@ namespace ts { } } else { - if (!isArrayLiteralExpression(boundValue)) { - // Read the elements of the iterable into an array - boundValue = emitTempVariableAssignment( - createReadHelper( - context, - boundValue, - isEffectiveBindingElementWithRest(elements[numElements - 1]) - ? undefined - : numElements, - location - ), - location - ); - } - for (let i = 0; i < numElements; i++) { const element = elements[i]; if (isOmittedExpression(element)) { diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index b958bb4a520..a988f06691c 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -2079,7 +2079,8 @@ namespace ts { // evaluated on every iteration. const assignment = createAssignment(node.initializer, boundValue); if (isDestructuringAssignment(assignment)) { - statements.push(visitNode(createStatement(assignment), visitor, isStatement)); + aggregateTransformFlags(assignment); + statements.push(createStatement(visitBinaryExpression(assignment, /*needsDestructuringValue*/ false))); } else { assignment.end = node.initializer.end; diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 5c87377c642..df750bb41e7 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -969,24 +969,29 @@ namespace ts { // ar = _a.concat([%sent%, 2]); const numInitialElements = countInitialNodesWithoutYield(elements); - const temp = declareLocal(); - let hasAssignedTemp = false; + + let temp: Identifier; if (numInitialElements > 0) { + temp = declareLocal(); emitAssignment(temp, createArrayLiteral( visitNodes(elements, visitor, isExpression, 0, numInitialElements) ) ); - hasAssignedTemp = true; } const expressions = reduceLeft(elements, reduceElement, [], numInitialElements); - return hasAssignedTemp + return temp ? createArrayConcat(temp, [createArrayLiteral(expressions)]) : createArrayLiteral(expressions); function reduceElement(expressions: Expression[], element: Expression) { if (containsYield(element) && expressions.length > 0) { + const hasAssignedTemp = temp !== undefined; + if (!temp) { + temp = declareLocal(); + } + emitAssignment( temp, hasAssignedTemp @@ -996,7 +1001,6 @@ namespace ts { ) : createArrayLiteral(expressions) ); - hasAssignedTemp = true; expressions = []; } @@ -1930,7 +1934,7 @@ namespace ts { function cacheExpression(node: Expression): Identifier { let temp: Identifier; - if (isGeneratedIdentifier(node)) { + if (isGeneratedIdentifier(node) || getEmitFlags(node) & EmitFlags.HelperName) { return node; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 407e900e46b..75bd642f2b9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3582,6 +3582,10 @@ 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 diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index de339e2bf2c..cfad25b53ec 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -1,24 +1,13 @@ /// interface SymbolConstructor { - /** - * A method that returns the default iterator for an object. Called by the semantics of the + /** + * A method that returns the default iterator for an object. Called by the semantics of the * for-of statement. */ readonly iterator: symbol; } -interface IteratorResult { - done: boolean; - value: T; -} - -interface Iterator { - next(value?: any): IteratorResult; - return?(value?: any): IteratorResult; - throw?(e?: any): IteratorResult; -} - interface Iterable { [Symbol.iterator](): Iterator; } @@ -31,17 +20,17 @@ interface Array { /** Iterator */ [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, T]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -55,7 +44,7 @@ interface ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): Array; - + /** * Creates an array from an iterable object. * @param iterable An iterable object to convert to an array. @@ -67,17 +56,17 @@ interface ReadonlyArray { /** Iterator */ [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, T]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -126,15 +115,15 @@ interface Promise { } interface PromiseConstructor { /** - * Creates a Promise that is resolved with an array of results when all of the provided Promises + * Creates a Promise that is resolved with an array of results when all of the provided Promises * resolve, or rejected when any Promise is rejected. * @param values An array of Promises. * @returns A new Promise. */ all(values: Iterable>): Promise; - + /** - * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved * or rejected. * @param values An array of Promises. * @returns A new Promise. @@ -152,20 +141,20 @@ interface String { } /** - * A typed array of 8-bit integer values. The contents are initialized to 0. If the requested + * A typed array of 8-bit integer values. The contents are initialized to 0. If the requested * number of bytes could not be allocated an exception is raised. */ interface Int8Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -184,20 +173,20 @@ interface Int8ArrayConstructor { } /** - * A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the + * A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the * requested number of bytes could not be allocated an exception is raised. */ interface Uint8Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -216,22 +205,22 @@ interface Uint8ArrayConstructor { } /** - * A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0. + * A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0. * If the requested number of bytes could not be allocated an exception is raised. */ interface Uint8ClampedArray { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -251,22 +240,22 @@ interface Uint8ClampedArrayConstructor { } /** - * A typed array of 16-bit signed integer values. The contents are initialized to 0. If the + * A typed array of 16-bit signed integer values. The contents are initialized to 0. If the * requested number of bytes could not be allocated an exception is raised. */ interface Int16Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -285,20 +274,20 @@ interface Int16ArrayConstructor { } /** - * A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the + * A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the * requested number of bytes could not be allocated an exception is raised. */ interface Uint16Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -317,20 +306,20 @@ interface Uint16ArrayConstructor { } /** - * A typed array of 32-bit signed integer values. The contents are initialized to 0. If the + * A typed array of 32-bit signed integer values. The contents are initialized to 0. If the * requested number of bytes could not be allocated an exception is raised. */ interface Int32Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -349,20 +338,20 @@ interface Int32ArrayConstructor { } /** - * A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the + * A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the * requested number of bytes could not be allocated an exception is raised. */ interface Uint32Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -386,15 +375,15 @@ interface Uint32ArrayConstructor { */ interface Float32Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; @@ -413,20 +402,20 @@ interface Float32ArrayConstructor { } /** - * A typed array of 64-bit float values. The contents are initialized to 0. If the requested + * A typed array of 64-bit float values. The contents are initialized to 0. If the requested * number of bytes could not be allocated an exception is raised. */ interface Float64Array { [Symbol.iterator](): IterableIterator; - /** + /** * Returns an array of key, value pairs for every entry in the array */ entries(): IterableIterator<[number, number]>; - /** + /** * Returns an list of keys in the array */ keys(): IterableIterator; - /** + /** * Returns an list of values in the array */ values(): IterableIterator; diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index cbb92157671..b024f62cda1 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -1338,11 +1338,6 @@ interface PromiseLike { onrejected: (reason: any) => TResult2 | PromiseLike): PromiseLike; } -interface ArrayLike { - readonly length: number; - readonly [n: number]: T; -} - interface IteratorResult { done: boolean; value: T; @@ -1362,6 +1357,11 @@ interface PseudoIterableIterator extends Iterator { __iterator__(): PseudoIterableIterator; } +interface ArrayLike { + readonly length: number; + readonly [n: number]: T; +} + /** * Represents a raw buffer of binary data, which is used to store data for the * different typed arrays. ArrayBuffers cannot be read from or written to directly,