Skip to content

Commit

Permalink
wrap subexpressions of conditional expressions in parens if necessary (
Browse files Browse the repository at this point in the history
  • Loading branch information
vladima authored Nov 21, 2016
1 parent 90ee161 commit 4c6b94f
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 4 deletions.
17 changes: 13 additions & 4 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -654,16 +654,16 @@ namespace ts {
if (whenFalse) {
// second overload
node.questionToken = <QuestionToken>questionTokenOrWhenTrue;
node.whenTrue = whenTrueOrWhenFalse;
node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(whenTrueOrWhenFalse);
node.colonToken = <ColonToken>colonTokenOrLocation;
node.whenFalse = whenFalse;
node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenFalse);
}
else {
// first overload
node.questionToken = createToken(SyntaxKind.QuestionToken);
node.whenTrue = <Expression>questionTokenOrWhenTrue;
node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(<Expression>questionTokenOrWhenTrue);
node.colonToken = createToken(SyntaxKind.ColonToken);
node.whenFalse = whenTrueOrWhenFalse;
node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenTrueOrWhenFalse);
}
return node;
}
Expand Down Expand Up @@ -2381,6 +2381,15 @@ namespace ts {
return condition;
}

function parenthesizeSubexpressionOfConditionalExpression(e: Expression): Expression {
// per ES grammar both 'whenTrue' and 'whenFalse' parts of conditional expression are assignment expressions
// so in case when comma expression is introduced as a part of previous transformations
// if should be wrapped in parens since comma operator has the lowest precedence
return e.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>e).operatorToken.kind === SyntaxKind.CommaToken
? createParen(e)
: e;
}

/**
* Wraps an expression in parentheses if it is needed in order to use the expression
* as the expression of a NewExpression node.
Expand Down
14 changes: 14 additions & 0 deletions tests/baselines/reference/commaOperatorInConditionalExpression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [commaOperatorInConditionalExpression.ts]
function f (m: string) {
[1, 2, 3].map(i => {
return true? { [m]: i } : { [m]: i + 1 }
})
}

//// [commaOperatorInConditionalExpression.js]
function f(m) {
[1, 2, 3].map(function (i) {
return true ? (_a = {}, _a[m] = i, _a) : (_b = {}, _b[m] = i + 1, _b);
var _a, _b;
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
=== tests/cases/compiler/commaOperatorInConditionalExpression.ts ===
function f (m: string) {
>f : Symbol(f, Decl(commaOperatorInConditionalExpression.ts, 0, 0))
>m : Symbol(m, Decl(commaOperatorInConditionalExpression.ts, 0, 12))

[1, 2, 3].map(i => {
>[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, --, --))
>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>i : Symbol(i, Decl(commaOperatorInConditionalExpression.ts, 1, 18))

return true? { [m]: i } : { [m]: i + 1 }
>m : Symbol(m, Decl(commaOperatorInConditionalExpression.ts, 0, 12))
>i : Symbol(i, Decl(commaOperatorInConditionalExpression.ts, 1, 18))
>m : Symbol(m, Decl(commaOperatorInConditionalExpression.ts, 0, 12))
>i : Symbol(i, Decl(commaOperatorInConditionalExpression.ts, 1, 18))

})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
=== tests/cases/compiler/commaOperatorInConditionalExpression.ts ===
function f (m: string) {
>f : (m: string) => void
>m : string

[1, 2, 3].map(i => {
>[1, 2, 3].map(i => { return true? { [m]: i } : { [m]: i + 1 } }) : { [x: string]: number; }[]
>[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[]; }
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 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[]; }
>i => { return true? { [m]: i } : { [m]: i + 1 } } : (i: number) => { [x: string]: number; }
>i : number

return true? { [m]: i } : { [m]: i + 1 }
>true? { [m]: i } : { [m]: i + 1 } : { [x: string]: number; }
>true : true
>{ [m]: i } : { [x: string]: number; }
>m : string
>i : number
>{ [m]: i + 1 } : { [x: string]: number; }
>m : string
>i + 1 : number
>i : number
>1 : 1

})
}
5 changes: 5 additions & 0 deletions tests/cases/compiler/commaOperatorInConditionalExpression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function f (m: string) {
[1, 2, 3].map(i => {
return true? { [m]: i } : { [m]: i + 1 }
})
}

0 comments on commit 4c6b94f

Please sign in to comment.