Skip to content

Commit aaf14f4

Browse files
authored
Merge pull request microsoft#26065 from ajafff/createbinary-arrow-parens
createBinary: parenthesize ArrowFunction in RHS
2 parents a21ac11 + 4dabd65 commit aaf14f4

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

src/compiler/factory.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4024,6 +4024,11 @@ namespace ts {
40244024
const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator);
40254025
const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator);
40264026
const emittedOperand = skipPartiallyEmittedExpressions(operand);
4027+
if (!isLeftSideOfBinary && operand.kind === SyntaxKind.ArrowFunction && binaryOperatorPrecedence > 4) {
4028+
// We need to parenthesize arrow functions on the right side to avoid it being
4029+
// parsed as parenthesized expression: `a && (() => {})`
4030+
return true;
4031+
}
40274032
const operandPrecedence = getExpressionPrecedence(emittedOperand);
40284033
switch (compareValues(operandPrecedence, binaryOperatorPrecedence)) {
40294034
case Comparison.LessThan:

src/testRunner/unittests/factory.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
namespace ts {
22
describe("FactoryAPI", () => {
3+
function assertSyntaxKind(node: Node, expected: SyntaxKind) {
4+
assert.strictEqual(node.kind, expected, `Actual: ${Debug.showSyntaxKind(node)} Expected: ${(ts as any).SyntaxKind[expected]}`);
5+
}
36
describe("createExportAssignment", () => {
47
it("parenthesizes default export if necessary", () => {
58
function checkExpression(expression: Expression) {
@@ -9,7 +12,7 @@ namespace ts {
912
/*isExportEquals*/ false,
1013
expression,
1114
);
12-
assert.strictEqual(node.expression.kind, SyntaxKind.ParenthesizedExpression);
15+
assertSyntaxKind(node.expression, SyntaxKind.ParenthesizedExpression);
1316
}
1417

1518
const clazz = createClassExpression(/*modifiers*/ undefined, "C", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [
@@ -39,7 +42,7 @@ namespace ts {
3942
/*equalsGreaterThanToken*/ undefined,
4043
body,
4144
);
42-
assert.strictEqual(node.body.kind, SyntaxKind.ParenthesizedExpression);
45+
assertSyntaxKind(node.body, SyntaxKind.ParenthesizedExpression);
4346
}
4447

4548
checkBody(createObjectLiteral());
@@ -50,5 +53,30 @@ namespace ts {
5053
checkBody(createBinary(createLiteral("a"), SyntaxKind.CommaToken, createLiteral("b")));
5154
});
5255
});
56+
57+
describe("createBinaryExpression", () => {
58+
it("parenthesizes arrow function in RHS if necessary", () => {
59+
const lhs = createIdentifier("foo");
60+
const rhs = createArrowFunction(
61+
/*modifiers*/ undefined,
62+
/*typeParameters*/ undefined,
63+
[],
64+
/*type*/ undefined,
65+
/*equalsGreaterThanToken*/ undefined,
66+
createBlock([]),
67+
);
68+
function checkRhs(operator: BinaryOperator, expectParens: boolean) {
69+
const node = createBinary(lhs, operator, rhs);
70+
assertSyntaxKind(node.right, expectParens ? SyntaxKind.ParenthesizedExpression : SyntaxKind.ArrowFunction);
71+
}
72+
73+
checkRhs(SyntaxKind.CommaToken, /*expectParens*/ false);
74+
checkRhs(SyntaxKind.EqualsToken, /*expectParens*/ false);
75+
checkRhs(SyntaxKind.PlusEqualsToken, /*expectParens*/ false);
76+
checkRhs(SyntaxKind.BarBarToken, /*expectParens*/ true);
77+
checkRhs(SyntaxKind.AmpersandAmpersandToken, /*expectParens*/ true);
78+
checkRhs(SyntaxKind.EqualsEqualsToken, /*expectParens*/ true);
79+
});
80+
});
5381
});
5482
}

0 commit comments

Comments
 (0)