Skip to content

Commit

Permalink
Add __spreadArrays helper
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Apr 29, 2019
1 parent 7423c69 commit 528601f
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 20 deletions.
5 changes: 3 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18671,8 +18671,8 @@ namespace ts {
}

function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type {
if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.SpreadIncludes);
if (languageVersion < ScriptTarget.ES2015) {
checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArrays);
}

const arrayOrIterableType = checkExpression(node.expression, checkMode);
Expand Down Expand Up @@ -30611,6 +30611,7 @@ namespace ts {
case ExternalEmitHelpers.Values: return "__values";
case ExternalEmitHelpers.Read: return "__read";
case ExternalEmitHelpers.Spread: return "__spread";
case ExternalEmitHelpers.SpreadArrays: return "__spreadArrays";
case ExternalEmitHelpers.Await: return "__await";
case ExternalEmitHelpers.AsyncGenerator: return "__asyncGenerator";
case ExternalEmitHelpers.AsyncDelegator: return "__asyncDelegator";
Expand Down
24 changes: 24 additions & 0 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3693,6 +3693,30 @@ namespace ts {
);
}

export const spreadArraysHelper: UnscopedEmitHelper = {
name: "typescript:spreadArrays",
scoped: false,
text: `
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var ar = [], i = 0; i < arguments.length; i++)
for (var j = 0; j < arguments[i].length; j++)
ar.push(arguments[i][j]);
return ar;
};`
};

export function createSpreadArraysHelper(context: TransformationContext, argumentList: ReadonlyArray<Expression>, location?: TextRange) {
context.requestEmitHelper(spreadArraysHelper);
return setTextRange(
createCall(
getHelperName("__spreadArrays"),
/*typeArguments*/ undefined,
argumentList
),
location
);
}

// Utilities

export function createForOfBindingStatement(node: ForInitializer, boundValue: Expression): Statement {
Expand Down
28 changes: 16 additions & 12 deletions src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3522,7 +3522,7 @@ namespace ts {
function visitArrayLiteralExpression(node: ArrayLiteralExpression): Expression {
if (some(node.elements, isSpreadElement)) {
// We are here because we contain a SpreadElementExpression.
return transformAndSpreadElements(node.elements, /*needsUniqueCopy*/ true, !!node.multiLine, /*hasTrailingComma*/ !!node.elements.hasTrailingComma);
return transformAndSpreadElements(node.elements, !!node.multiLine, /*hasTrailingComma*/ !!node.elements.hasTrailingComma);
}
return visitEachChild(node, visitor, context);
}
Expand Down Expand Up @@ -3737,7 +3737,7 @@ namespace ts {
resultingCall = createFunctionApply(
visitNode(target, callExpressionVisitor, isExpression),
node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : visitNode(thisArg, visitor, isExpression),
transformAndSpreadElements(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*hasTrailingComma*/ false)
transformAndSpreadElements(node.arguments, /*multiLine*/ false, /*hasTrailingComma*/ false)
);
}
else {
Expand Down Expand Up @@ -3793,7 +3793,7 @@ namespace ts {
createFunctionApply(
visitNode(target, visitor, isExpression),
thisArg,
transformAndSpreadElements(createNodeArray([createVoidZero(), ...node.arguments!]), /*needsUniqueCopy*/ false, /*multiLine*/ false, /*hasTrailingComma*/ false)
transformAndSpreadElements(createNodeArray([createVoidZero(), ...node.arguments!]), /*multiLine*/ false, /*hasTrailingComma*/ false)
),
/*typeArguments*/ undefined,
[]
Expand All @@ -3806,15 +3806,17 @@ namespace ts {
* Transforms an array of Expression nodes that contains a SpreadExpression.
*
* @param elements The array of Expression nodes.
* @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array.
* @param multiLine A value indicating whether the result should be emitted on multiple lines.
*/
function transformAndSpreadElements(elements: NodeArray<Expression>, needsUniqueCopy: boolean, multiLine: boolean, hasTrailingComma: boolean): Expression {
function transformAndSpreadElements(elements: NodeArray<Expression>, multiLine: boolean, hasTrailingComma: boolean): Expression {
// [source]
// [a, ...b, c]
//
// [output (downlevelIteration)]
// __spread([a], b, [c])
//
// [output]
// [a].concat(b, [c])
// __spreadArrays([a], b, [c])

// Map spans of spread expressions into their expressions and spans of other
// expressions into an array literal.
Expand All @@ -3840,14 +3842,16 @@ namespace ts {
}
else {
if (segments.length === 1) {
const firstElement = elements[0];
return needsUniqueCopy && isSpreadElement(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression
? createArraySlice(segments[0])
: segments[0];
const firstSegment = segments[0];
if (isCallExpression(firstSegment)
&& isIdentifier(firstSegment.expression)
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
&& firstSegment.expression.escapedText === "___spreadArrays") {
return segments[0];
}
}

// Rewrite using the pattern <segment0>.concat(<segment1>, <segment2>, ...)
return createArrayConcat(segments.shift()!, segments);
return createSpreadArraysHelper(context, segments);
}
}

Expand Down
13 changes: 7 additions & 6 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5307,12 +5307,13 @@ namespace ts {
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations)
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations)
Await = 1 << 11, // __await (used by ES2017 async generator transformation)
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation)
MakeTemplateObject = 1 << 16, // __makeTemplateObject (used for constructing template string array objects)
SpreadArrays = 1 << 11, // __spreadArrays (used by ES2015 array spread and argument list spread transformations)
Await = 1 << 12, // __await (used by ES2017 async generator transformation)
AsyncGenerator = 1 << 13, // __asyncGenerator (used by ES2017 async generator transformation)
AsyncDelegator = 1 << 14, // __asyncDelegator (used by ES2017 async generator yield* transformation)
AsyncValues = 1 << 15, // __asyncValues (used by ES2017 for..await..of transformation)
ExportStar = 1 << 16, // __exportStar (used by CommonJS/AMD/UMD module transformation)
MakeTemplateObject = 1 << 17, // __makeTemplateObject (used for constructing template string array objects)
FirstEmitHelper = Extends,
LastEmitHelper = MakeTemplateObject,

Expand Down

0 comments on commit 528601f

Please sign in to comment.