Skip to content

Commit

Permalink
Minor cleanup, ensure multiple emit helpers for outfile tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Nov 18, 2020
1 parent 8acb22e commit fd4dbbe
Show file tree
Hide file tree
Showing 15 changed files with 5,890 additions and 3,551 deletions.
16 changes: 4 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 7 additions & 30 deletions src/compiler/factory/emitHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,34 +615,6 @@ namespace ts {
};`
};

/** @deprecated To be removed in TS >= 4.3, as it may be referenced in a tsbuildinfo */
export const spreadHelper: UnscopedEmitHelper = {
name: "typescript:spread",
importName: "__spread",
scoped: false,
dependencies: [readHelper],
text: `
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};`
};

/** @deprecated To be removed in TS >= 4.3, as it may be referenced in a tsbuildinfo */
export const spreadArraysHelper: UnscopedEmitHelper = {
name: "typescript:spreadArrays",
importName: "__spreadArrays",
scoped: false,
text: `
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};`
};

export const spreadArrayHelper: UnscopedEmitHelper = {
name: "typescript:spreadArray",
importName: "__spreadArray",
Expand Down Expand Up @@ -886,8 +858,6 @@ namespace ts {
awaiterHelper,
extendsHelper,
templateObjectHelper,
spreadHelper,
spreadArraysHelper,
spreadArrayHelper,
valuesHelper,
readHelper,
Expand Down Expand Up @@ -918,4 +888,11 @@ namespace ts {
return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
})(name => super[name], (name, value) => super[name] = value);`
};

export function isCallToHelper(firstSegment: Expression, helperName: __String) {
return isCallExpression(firstSegment)
&& isIdentifier(firstSegment.expression)
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
&& firstSegment.expression.escapedText === helperName;
}
}
38 changes: 19 additions & 19 deletions src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3892,6 +3892,8 @@ namespace ts {
*
* @param elements The array of Expression nodes.
* @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array.
* This should be `true` when spreading into an `ArrayLiteral`, and `false` when spreading into an
* argument list.
* @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 {
Expand All @@ -3916,6 +3918,15 @@ namespace ts {
//
// [output]
// __spreadArray(__spreadArray([], a), [b])
//
// NOTE: We use `isPackedArrayLiteral` below rather than just `isArrayLiteral`
// because ES2015 spread will replace _missing_ array elements with `undefined`,
// so we cannot just use an array as is. For example:
//
// `[1, ...[2, , 3]]` becomes `[1, 2, undefined, 3]`
//
// However, for packed array literals (i.e., an array literal with no OmittedExpression
// elements), we can use the array as-is.

// Map spans of spread expressions into their expressions and spans of other
// expressions into an array literal.
Expand All @@ -3926,46 +3937,35 @@ namespace ts {
)
);

const helpers = emitHelpers();
if (segments.length === 1) {
const firstSegment = segments[0];
if (!needsUniqueCopy
|| isPackedArrayLiteral(firstSegment)
// If we don't need a unique copy, then we are spreading into an argument list for
// a CallExpression or NewExpression. When using `--downlevelIteration`, we need
// to coerce this into an array for use with `apply`, so we will use the code path
// that follows instead.
if (!needsUniqueCopy && !compilerOptions.downlevelIteration
|| isPackedArrayLiteral(firstSegment) // see NOTE (above)
|| isCallToHelper(firstSegment, "___spreadArray" as __String)) {
return segments[0];
}
}

const helpers = emitHelpers();
const startsWithSpread = isSpreadElement(elements[0]);
let expression: Expression =
startsWithSpread ? factory.createArrayLiteralExpression() :
segments[0];
for (let i = startsWithSpread ? 0 : 1; i < segments.length; i++) {
expression = helpers.createSpreadArrayHelper(
expression,
compilerOptions.downlevelIteration && !isArrayLiteralExpression(segments[i]) ?
compilerOptions.downlevelIteration && !isPackedArrayLiteral(segments[i]) ? // see NOTE (above)
helpers.createReadHelper(segments[i], /*count*/ undefined) :
segments[i]);
}

return expression;
}

function isPackedElement(node: Expression) {
return !isOmittedExpression(node);
}

function isPackedArrayLiteral(node: Expression) {
return isArrayLiteralExpression(node) && every(node.elements, isPackedElement);
}

function isCallToHelper(firstSegment: Expression, helperName: __String) {
return isCallExpression(firstSegment)
&& isIdentifier(firstSegment.expression)
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
&& firstSegment.expression.escapedText === helperName;
}

function partitionSpread(node: Expression) {
return isSpreadElement(node)
? visitSpanOfSpreads
Expand Down
11 changes: 11 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6991,4 +6991,15 @@ namespace ts {
return bindParentToChildIgnoringJSDoc(child, parent) || bindJSDoc(child);
}
}

function isPackedElement(node: Expression) {
return !isOmittedExpression(node);
}

/**
* Determines whether the provided node is an ArrayLiteralExpression that contains no missing elements.
*/
export function isPackedArrayLiteral(node: Expression) {
return isArrayLiteralExpression(node) && every(node.elements, isPackedElement);
}
}
3 changes: 2 additions & 1 deletion src/testRunner/unittests/tsbuild/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,8 @@ const { b, ...rest } = { a: 10, b: 30, yy: 30 };
const content = fs.readFileSync(path, "utf8");
fs.writeFileSync(path, `${content}
function ${project}${file}Spread(...b: number[]) { }
${project}${file}Spread(...[10, 20, 30]);`);
const ${project}${file}_ar = [20, 30];
${project}${file}Spread(10, ...${project}${file}_ar);`);

replaceText(fs, `src/${project}/tsconfig.json`, `"strict": false,`, `"strict": false,
"downlevelIteration": true,`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function a11(_a) {
var array = [1, 2, 3];
var array2 = [true, false, "hello"];
a2(__spreadArray([], __read(array)));
a1.apply(void 0, array);
a1.apply(void 0, __spreadArray([], __read(array)));
a9([1, 2, [["string"]], false, true]); // Parameter type is [any, any, [[any]]]
a10([1, 2, [["string"]], false, true]); // Parameter type is any[]
a10([1, 2, 3, false, true]); // Parameter type is any[]
Expand Down
Loading

0 comments on commit fd4dbbe

Please sign in to comment.