record temp variable introduced in spread calls

This commit is contained in:
Vladimir Matveev
2016-04-07 15:29:44 -07:00
parent ff0b349782
commit 586404ba09
7 changed files with 117 additions and 99 deletions

View File

@@ -149,10 +149,13 @@ namespace ts {
return node;
}
export function createTempVariable(location?: TextRange): Identifier {
export function createTempVariable(recordTempVariable: (node: Identifier) => void, location?: TextRange): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
name.autoGenerateKind = GeneratedIdentifierKind.Auto;
getNodeId(name);
if (recordTempVariable) {
recordTempVariable(name);
}
return name;
}
@@ -1123,7 +1126,19 @@ namespace ts {
thisArg: Expression;
}
export function createCallBinding(expression: Expression, languageVersion?: ScriptTarget): CallBinding {
function shouldBeCapturedInTempVariable(node: Expression): boolean {
switch (skipParentheses(node).kind) {
case SyntaxKind.Identifier:
case SyntaxKind.ThisKeyword:
case SyntaxKind.NumericLiteral:
case SyntaxKind.StringLiteral:
return false;
default:
return true;
}
}
export function createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget): CallBinding {
const callee = skipOuterExpressions(expression, OuterExpressionKinds.All);
let thisArg: Expression;
let target: LeftHandSideExpression;
@@ -1138,32 +1153,44 @@ namespace ts {
else {
switch (callee.kind) {
case SyntaxKind.PropertyAccessExpression: {
// for `a.b()` target is `(_a = a).b` and thisArg is `_a`
thisArg = createTempVariable();
target = createPropertyAccess(
createAssignment(
thisArg,
(<PropertyAccessExpression>callee).expression,
/*location*/ (<PropertyAccessExpression>callee).expression
),
(<PropertyAccessExpression>callee).name,
if (shouldBeCapturedInTempVariable((<PropertyAccessExpression>callee).expression)) {
// for `a.b()` target is `(_a = a).b` and thisArg is `_a`
thisArg = createTempVariable(recordTempVariable);
target = createPropertyAccess(
createAssignment(
thisArg,
(<PropertyAccessExpression>callee).expression,
/*location*/(<PropertyAccessExpression>callee).expression
),
(<PropertyAccessExpression>callee).name,
/*location*/ callee
);
);
}
else {
thisArg = (<PropertyAccessExpression>callee).expression;
target = <PropertyAccessExpression>callee;
}
break;
}
case SyntaxKind.ElementAccessExpression: {
// for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a`
thisArg = createTempVariable();
target = createElementAccess(
createAssignment(
thisArg,
(<ElementAccessExpression>callee).expression,
/*location*/ (<ElementAccessExpression>callee).expression
),
(<ElementAccessExpression>callee).argumentExpression,
if (shouldBeCapturedInTempVariable((<ElementAccessExpression>callee).expression)) {
// for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a`
thisArg = createTempVariable(recordTempVariable);
target = createElementAccess(
createAssignment(
thisArg,
(<ElementAccessExpression>callee).expression,
/*location*/(<ElementAccessExpression>callee).expression
),
(<ElementAccessExpression>callee).argumentExpression,
/*location*/ callee
);
);
}
else {
thisArg = (<ElementAccessExpression>callee).expression;
target = <ElementAccessExpression>callee;
}
break;
}

View File

@@ -66,8 +66,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
recordTempVariable(name);
const name = createTempVariable(recordTempVariable);
emitAssignment(name, value, location);
return name;
}
@@ -102,7 +101,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
const name = createTempVariable(/*recordTempVariable*/ undefined);
emitAssignment(name, value, location);
return name;
}
@@ -142,7 +141,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
const name = createTempVariable(/*recordTempVariable*/ undefined);
emitAssignment(name, value, location, /*original*/ undefined);
return name;
}
@@ -177,8 +176,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
recordTempVariable(name);
const name = createTempVariable(recordTempVariable);
emitPendingAssignment(name, value, location, /*original*/ undefined);
return name;
}

View File

@@ -1561,7 +1561,7 @@ namespace ts {
const counter = createLoopVariable();
const rhsReference = expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>expression).text)
: createTempVariable();
: createTempVariable(/*recordTempVariable*/ undefined);
// Initialize LHS
// var v = _a[_i];
@@ -1596,7 +1596,7 @@ namespace ts {
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
firstDeclaration ? firstDeclaration.name : createTempVariable(),
firstDeclaration ? firstDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
createElementAccess(rhsReference, counter)
)
]),
@@ -1686,8 +1686,7 @@ namespace ts {
// For computed properties, we need to create a unique handle to the object
// literal so we can modify it without risking internal assignments tainting the object.
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
// Write out the first non-computed properties, then emit the rest through indexing on the temp variable.
const expressions: Expression[] = [];
@@ -2232,7 +2231,7 @@ namespace ts {
// We are here either because SuperKeyword was used somewhere in the expression, or
// because we contain a SpreadElementExpression.
const { target, thisArg } = createCallBinding(node.expression);
const { target, thisArg } = createCallBinding(node.expression, hoistVariableDeclaration);
if (node.transformFlags & TransformFlags.ContainsSpreadElementExpression) {
// [source]
// f(...a, b)
@@ -2289,7 +2288,7 @@ namespace ts {
// [output]
// new ((_a = C).bind.apply(_a, [void 0].concat(a)))()
const { target, thisArg } = createCallBinding(createPropertyAccess(node.expression, "bind"));
const { target, thisArg } = createCallBinding(createPropertyAccess(node.expression, "bind"), hoistVariableDeclaration);
return createNew(
createFunctionApply(
visitNode(target, visitor, isExpression),
@@ -2380,8 +2379,7 @@ namespace ts {
const tag = visitNode(node.tag, visitor, isExpression);
// Allocate storage for the template site object
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
// Build up the template arguments and the raw and cooked strings for the template.
const templateArguments: Expression[] = [temp];

View File

@@ -44,11 +44,9 @@ namespace ts {
let value: Expression;
if (isElementAccessExpression(left)) {
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
const expressionTemp = createTempVariable();
hoistVariableDeclaration(expressionTemp);
const expressionTemp = createTempVariable(hoistVariableDeclaration);
const argumentExpressionTemp = createTempVariable();
hoistVariableDeclaration(argumentExpressionTemp);
const argumentExpressionTemp = createTempVariable(hoistVariableDeclaration);
target = createElementAccess(
createAssignment(expressionTemp, left.expression, /*location*/ left.expression),
@@ -64,8 +62,7 @@ namespace ts {
}
else if (isPropertyAccessExpression(left)) {
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
const expressionTemp = createTempVariable();
hoistVariableDeclaration(expressionTemp);
const expressionTemp = createTempVariable(hoistVariableDeclaration);
target = createPropertyAccess(
createAssignment(expressionTemp, left.expression, /*location*/ left.expression),

View File

@@ -674,8 +674,7 @@ namespace ts {
if (staticProperties.length > 0) {
const expressions: Expression[] = [];
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
// To preserve the behavior of the old emitter, we explicitly indent
// the body of a class with static initializers.
@@ -1614,8 +1613,7 @@ namespace ts {
switch (resolver.getTypeReferenceSerializationKind(typeName)) {
case TypeReferenceSerializationKind.Unknown:
const serialized = serializeEntityNameAsExpression(typeName, /*useFallback*/ true);
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
return createLogicalOr(
createLogicalAnd(
createStrictEquality(
@@ -1701,8 +1699,7 @@ namespace ts {
left = serializeEntityNameAsExpression(node.left, useFallback);
}
else if (useFallback) {
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
left = createLogicalAnd(
createAssignment(
temp,