Skip to content

Commit 4c6b94f

Browse files
authored
wrap subexpressions of conditional expressions in parens if necessary (#12420)
1 parent 90ee161 commit 4c6b94f

5 files changed

+80
-4
lines changed

src/compiler/factory.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -654,16 +654,16 @@ namespace ts {
654654
if (whenFalse) {
655655
// second overload
656656
node.questionToken = <QuestionToken>questionTokenOrWhenTrue;
657-
node.whenTrue = whenTrueOrWhenFalse;
657+
node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(whenTrueOrWhenFalse);
658658
node.colonToken = <ColonToken>colonTokenOrLocation;
659-
node.whenFalse = whenFalse;
659+
node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenFalse);
660660
}
661661
else {
662662
// first overload
663663
node.questionToken = createToken(SyntaxKind.QuestionToken);
664-
node.whenTrue = <Expression>questionTokenOrWhenTrue;
664+
node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(<Expression>questionTokenOrWhenTrue);
665665
node.colonToken = createToken(SyntaxKind.ColonToken);
666-
node.whenFalse = whenTrueOrWhenFalse;
666+
node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenTrueOrWhenFalse);
667667
}
668668
return node;
669669
}
@@ -2381,6 +2381,15 @@ namespace ts {
23812381
return condition;
23822382
}
23832383

2384+
function parenthesizeSubexpressionOfConditionalExpression(e: Expression): Expression {
2385+
// per ES grammar both 'whenTrue' and 'whenFalse' parts of conditional expression are assignment expressions
2386+
// so in case when comma expression is introduced as a part of previous transformations
2387+
// if should be wrapped in parens since comma operator has the lowest precedence
2388+
return e.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>e).operatorToken.kind === SyntaxKind.CommaToken
2389+
? createParen(e)
2390+
: e;
2391+
}
2392+
23842393
/**
23852394
* Wraps an expression in parentheses if it is needed in order to use the expression
23862395
* as the expression of a NewExpression node.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [commaOperatorInConditionalExpression.ts]
2+
function f (m: string) {
3+
[1, 2, 3].map(i => {
4+
return true? { [m]: i } : { [m]: i + 1 }
5+
})
6+
}
7+
8+
//// [commaOperatorInConditionalExpression.js]
9+
function f(m) {
10+
[1, 2, 3].map(function (i) {
11+
return true ? (_a = {}, _a[m] = i, _a) : (_b = {}, _b[m] = i + 1, _b);
12+
var _a, _b;
13+
});
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/compiler/commaOperatorInConditionalExpression.ts ===
2+
function f (m: string) {
3+
>f : Symbol(f, Decl(commaOperatorInConditionalExpression.ts, 0, 0))
4+
>m : Symbol(m, Decl(commaOperatorInConditionalExpression.ts, 0, 12))
5+
6+
[1, 2, 3].map(i => {
7+
>[1, 2, 3].map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
8+
>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
9+
>i : Symbol(i, Decl(commaOperatorInConditionalExpression.ts, 1, 18))
10+
11+
return true? { [m]: i } : { [m]: i + 1 }
12+
>m : Symbol(m, Decl(commaOperatorInConditionalExpression.ts, 0, 12))
13+
>i : Symbol(i, Decl(commaOperatorInConditionalExpression.ts, 1, 18))
14+
>m : Symbol(m, Decl(commaOperatorInConditionalExpression.ts, 0, 12))
15+
>i : Symbol(i, Decl(commaOperatorInConditionalExpression.ts, 1, 18))
16+
17+
})
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=== tests/cases/compiler/commaOperatorInConditionalExpression.ts ===
2+
function f (m: string) {
3+
>f : (m: string) => void
4+
>m : string
5+
6+
[1, 2, 3].map(i => {
7+
>[1, 2, 3].map(i => { return true? { [m]: i } : { [m]: i + 1 } }) : { [x: string]: number; }[]
8+
>[1, 2, 3].map : { <U>(this: [number, number, number, number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U, U, U, U]; <U>(this: [number, number, number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U, U, U]; <U>(this: [number, number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U, U]; <U>(this: [number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U]; <U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): U[]; }
9+
>[1, 2, 3] : number[]
10+
>1 : 1
11+
>2 : 2
12+
>3 : 3
13+
>map : { <U>(this: [number, number, number, number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U, U, U, U]; <U>(this: [number, number, number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U, U, U]; <U>(this: [number, number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U, U]; <U>(this: [number, number], callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): [U, U]; <U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any): U[]; }
14+
>i => { return true? { [m]: i } : { [m]: i + 1 } } : (i: number) => { [x: string]: number; }
15+
>i : number
16+
17+
return true? { [m]: i } : { [m]: i + 1 }
18+
>true? { [m]: i } : { [m]: i + 1 } : { [x: string]: number; }
19+
>true : true
20+
>{ [m]: i } : { [x: string]: number; }
21+
>m : string
22+
>i : number
23+
>{ [m]: i + 1 } : { [x: string]: number; }
24+
>m : string
25+
>i + 1 : number
26+
>i : number
27+
>1 : 1
28+
29+
})
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function f (m: string) {
2+
[1, 2, 3].map(i => {
3+
return true? { [m]: i } : { [m]: i + 1 }
4+
})
5+
}

0 commit comments

Comments
 (0)