diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 8560e44dcf8..e6ba8b76704 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3179,35 +3179,38 @@ module ts { } function emitParenExpression(node: ParenthesizedExpression) { - if (node.expression.kind === SyntaxKind.TypeAssertionExpression) { - var operand = (node.expression).expression; + if (!node.parent || node.parent.kind !== SyntaxKind.ArrowFunction) { + if (node.expression.kind === SyntaxKind.TypeAssertionExpression) { + var operand = (node.expression).expression; - // Make sure we consider all nested cast expressions, e.g.: - // (-A).x; - while (operand.kind == SyntaxKind.TypeAssertionExpression) { - operand = (operand).expression; - } + // Make sure we consider all nested cast expressions, e.g.: + // (-A).x; + while (operand.kind == SyntaxKind.TypeAssertionExpression) { + operand = (operand).expression; + } - // We have an expression of the form: (SubExpr) - // Emitting this as (SubExpr) is really not desirable. We would like to emit the subexpr as is. - // Omitting the parentheses, however, could cause change in the semantics of the generated - // code if the casted expression has a lower precedence than the rest of the expression, e.g.: - // (new A).foo should be emitted as (new A).foo and not new A.foo - // (typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString() - // new (A()) should be emitted as new (A()) and not new A() - // (function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} () - if (operand.kind !== SyntaxKind.PrefixUnaryExpression && - operand.kind !== SyntaxKind.VoidExpression && - operand.kind !== SyntaxKind.TypeOfExpression && - operand.kind !== SyntaxKind.DeleteExpression && - operand.kind !== SyntaxKind.PostfixUnaryExpression && - operand.kind !== SyntaxKind.NewExpression && - !(operand.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.NewExpression) && - !(operand.kind === SyntaxKind.FunctionExpression && node.parent.kind === SyntaxKind.CallExpression)) { - emit(operand); - return; + // We have an expression of the form: (SubExpr) + // Emitting this as (SubExpr) is really not desirable. We would like to emit the subexpr as is. + // Omitting the parentheses, however, could cause change in the semantics of the generated + // code if the casted expression has a lower precedence than the rest of the expression, e.g.: + // (new A).foo should be emitted as (new A).foo and not new A.foo + // (typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString() + // new (A()) should be emitted as new (A()) and not new A() + // (function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} () + if (operand.kind !== SyntaxKind.PrefixUnaryExpression && + operand.kind !== SyntaxKind.VoidExpression && + operand.kind !== SyntaxKind.TypeOfExpression && + operand.kind !== SyntaxKind.DeleteExpression && + operand.kind !== SyntaxKind.PostfixUnaryExpression && + operand.kind !== SyntaxKind.NewExpression && + !(operand.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.NewExpression) && + !(operand.kind === SyntaxKind.FunctionExpression && node.parent.kind === SyntaxKind.CallExpression)) { + emit(operand); + return; + } } } + write("("); emit(node.expression); write(")"); diff --git a/tests/baselines/reference/arrowFunctionWithObjectLiteralBody5.js b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody5.js new file mode 100644 index 00000000000..77f5c2d4c3d --- /dev/null +++ b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody5.js @@ -0,0 +1,14 @@ +//// [arrowFunctionWithObjectLiteralBody5.ts] +var a = () => { name: "foo", message: "bar" }; + +var b = () => ({ name: "foo", message: "bar" }); + +var c = () => ({ name: "foo", message: "bar" }); + +var d = () => ((({ name: "foo", message: "bar" }))); + +//// [arrowFunctionWithObjectLiteralBody5.js] +var a = function () { return { name: "foo", message: "bar" }; }; +var b = function () { return ({ name: "foo", message: "bar" }); }; +var c = function () { return ({ name: "foo", message: "bar" }); }; +var d = function () { return (({ name: "foo", message: "bar" })); }; diff --git a/tests/baselines/reference/arrowFunctionWithObjectLiteralBody5.types b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody5.types new file mode 100644 index 00000000000..15b3697732a --- /dev/null +++ b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody5.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/arrowFunctionWithObjectLiteralBody5.ts === +var a = () => { name: "foo", message: "bar" }; +>a : () => Error +>() => { name: "foo", message: "bar" } : () => Error +>{ name: "foo", message: "bar" } : Error +>Error : Error +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + +var b = () => ({ name: "foo", message: "bar" }); +>b : () => Error +>() => ({ name: "foo", message: "bar" }) : () => Error +>({ name: "foo", message: "bar" }) : Error +>{ name: "foo", message: "bar" } : Error +>Error : Error +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + +var c = () => ({ name: "foo", message: "bar" }); +>c : () => { name: string; message: string; } +>() => ({ name: "foo", message: "bar" }) : () => { name: string; message: string; } +>({ name: "foo", message: "bar" }) : { name: string; message: string; } +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + +var d = () => ((({ name: "foo", message: "bar" }))); +>d : () => Error +>() => ((({ name: "foo", message: "bar" }))) : () => Error +>((({ name: "foo", message: "bar" }))) : Error +>(({ name: "foo", message: "bar" })) : Error +>({ name: "foo", message: "bar" }) : Error +>Error : Error +>({ name: "foo", message: "bar" }) : { name: string; message: string; } +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + diff --git a/tests/baselines/reference/arrowFunctionWithObjectLiteralBody6.js b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody6.js new file mode 100644 index 00000000000..6128a6bef86 --- /dev/null +++ b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody6.js @@ -0,0 +1,14 @@ +//// [arrowFunctionWithObjectLiteralBody6.ts] +var a = () => { name: "foo", message: "bar" }; + +var b = () => ({ name: "foo", message: "bar" }); + +var c = () => ({ name: "foo", message: "bar" }); + +var d = () => ((({ name: "foo", message: "bar" }))); + +//// [arrowFunctionWithObjectLiteralBody6.js] +var a = () => ({ name: "foo", message: "bar" }); +var b = () => ({ name: "foo", message: "bar" }); +var c = () => ({ name: "foo", message: "bar" }); +var d = () => (({ name: "foo", message: "bar" })); diff --git a/tests/baselines/reference/arrowFunctionWithObjectLiteralBody6.types b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody6.types new file mode 100644 index 00000000000..14a45dca213 --- /dev/null +++ b/tests/baselines/reference/arrowFunctionWithObjectLiteralBody6.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/arrowFunctionWithObjectLiteralBody6.ts === +var a = () => { name: "foo", message: "bar" }; +>a : () => Error +>() => { name: "foo", message: "bar" } : () => Error +>{ name: "foo", message: "bar" } : Error +>Error : Error +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + +var b = () => ({ name: "foo", message: "bar" }); +>b : () => Error +>() => ({ name: "foo", message: "bar" }) : () => Error +>({ name: "foo", message: "bar" }) : Error +>{ name: "foo", message: "bar" } : Error +>Error : Error +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + +var c = () => ({ name: "foo", message: "bar" }); +>c : () => { name: string; message: string; } +>() => ({ name: "foo", message: "bar" }) : () => { name: string; message: string; } +>({ name: "foo", message: "bar" }) : { name: string; message: string; } +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + +var d = () => ((({ name: "foo", message: "bar" }))); +>d : () => Error +>() => ((({ name: "foo", message: "bar" }))) : () => Error +>((({ name: "foo", message: "bar" }))) : Error +>(({ name: "foo", message: "bar" })) : Error +>({ name: "foo", message: "bar" }) : Error +>Error : Error +>({ name: "foo", message: "bar" }) : { name: string; message: string; } +>{ name: "foo", message: "bar" } : { name: string; message: string; } +>name : string +>message : string + diff --git a/tests/cases/compiler/arrowFunctionWithObjectLiteralBody5.ts b/tests/cases/compiler/arrowFunctionWithObjectLiteralBody5.ts new file mode 100644 index 00000000000..1f805786815 --- /dev/null +++ b/tests/cases/compiler/arrowFunctionWithObjectLiteralBody5.ts @@ -0,0 +1,7 @@ +var a = () => { name: "foo", message: "bar" }; + +var b = () => ({ name: "foo", message: "bar" }); + +var c = () => ({ name: "foo", message: "bar" }); + +var d = () => ((({ name: "foo", message: "bar" }))); \ No newline at end of file diff --git a/tests/cases/compiler/arrowFunctionWithObjectLiteralBody6.ts b/tests/cases/compiler/arrowFunctionWithObjectLiteralBody6.ts new file mode 100644 index 00000000000..870717c849a --- /dev/null +++ b/tests/cases/compiler/arrowFunctionWithObjectLiteralBody6.ts @@ -0,0 +1,8 @@ +// @target: es6 +var a = () => { name: "foo", message: "bar" }; + +var b = () => ({ name: "foo", message: "bar" }); + +var c = () => ({ name: "foo", message: "bar" }); + +var d = () => ((({ name: "foo", message: "bar" }))); \ No newline at end of file