createBinary: parenthesize ArrowFunction in RHS

Fixes: #25964
This commit is contained in:
Klaus Meinhardt
2018-07-30 19:22:30 +02:00
parent 0923771606
commit 4dabd650ed
2 changed files with 35 additions and 2 deletions

View File

@@ -4024,6 +4024,11 @@ namespace ts {
const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator);
const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator);
const emittedOperand = skipPartiallyEmittedExpressions(operand);
if (!isLeftSideOfBinary && operand.kind === SyntaxKind.ArrowFunction && binaryOperatorPrecedence > 4) {
// We need to parenthesize arrow functions on the right side to avoid it being
// parsed as parenthesized expression: `a && (() => {})`
return true;
}
const operandPrecedence = getExpressionPrecedence(emittedOperand);
switch (compareValues(operandPrecedence, binaryOperatorPrecedence)) {
case Comparison.LessThan:

View File

@@ -1,5 +1,8 @@
namespace ts {
describe("FactoryAPI", () => {
function assertSyntaxKind(node: Node, expected: SyntaxKind) {
assert.strictEqual(node.kind, expected, `Actual: ${Debug.showSyntaxKind(node)} Expected: ${(ts as any).SyntaxKind[expected]}`);
}
describe("createExportAssignment", () => {
it("parenthesizes default export if necessary", () => {
function checkExpression(expression: Expression) {
@@ -9,7 +12,7 @@ namespace ts {
/*isExportEquals*/ false,
expression,
);
assert.strictEqual(node.expression.kind, SyntaxKind.ParenthesizedExpression);
assertSyntaxKind(node.expression, SyntaxKind.ParenthesizedExpression);
}
const clazz = createClassExpression(/*modifiers*/ undefined, "C", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [
@@ -39,7 +42,7 @@ namespace ts {
/*equalsGreaterThanToken*/ undefined,
body,
);
assert.strictEqual(node.body.kind, SyntaxKind.ParenthesizedExpression);
assertSyntaxKind(node.body, SyntaxKind.ParenthesizedExpression);
}
checkBody(createObjectLiteral());
@@ -50,5 +53,30 @@ namespace ts {
checkBody(createBinary(createLiteral("a"), SyntaxKind.CommaToken, createLiteral("b")));
});
});
describe("createBinaryExpression", () => {
it("parenthesizes arrow function in RHS if necessary", () => {
const lhs = createIdentifier("foo");
const rhs = createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
[],
/*type*/ undefined,
/*equalsGreaterThanToken*/ undefined,
createBlock([]),
);
function checkRhs(operator: BinaryOperator, expectParens: boolean) {
const node = createBinary(lhs, operator, rhs);
assertSyntaxKind(node.right, expectParens ? SyntaxKind.ParenthesizedExpression : SyntaxKind.ArrowFunction);
}
checkRhs(SyntaxKind.CommaToken, /*expectParens*/ false);
checkRhs(SyntaxKind.EqualsToken, /*expectParens*/ false);
checkRhs(SyntaxKind.PlusEqualsToken, /*expectParens*/ false);
checkRhs(SyntaxKind.BarBarToken, /*expectParens*/ true);
checkRhs(SyntaxKind.AmpersandAmpersandToken, /*expectParens*/ true);
checkRhs(SyntaxKind.EqualsEqualsToken, /*expectParens*/ true);
});
});
});
}