From 0a194f91a0a44c79bd5eb152825865940ccf407f Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Tue, 4 Apr 2017 11:15:03 -0700 Subject: [PATCH] Emit parenthesis around propert/element access expression of casted object literal expression --- src/compiler/transformers/ts.ts | 13 +++++++--- ...ssionOfCastedObjectLiteralExpressionES5.js | 7 ++++++ ...OfCastedObjectLiteralExpressionES5.symbols | 10 ++++++++ ...onOfCastedObjectLiteralExpressionES5.types | 25 +++++++++++++++++++ ...ssionOfCastedObjectLiteralExpressionES6.js | 7 ++++++ ...OfCastedObjectLiteralExpressionES6.symbols | 10 ++++++++ ...onOfCastedObjectLiteralExpressionES6.types | 25 +++++++++++++++++++ ...ssionOfCastedObjectLiteralExpressionES5.ts | 4 +++ ...ssionOfCastedObjectLiteralExpressionES6.ts | 4 +++ 9 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.js create mode 100644 tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.symbols create mode 100644 tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.types create mode 100644 tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.js create mode 100644 tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.symbols create mode 100644 tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.types create mode 100644 tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts create mode 100644 tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6dc643b9543..50503e308d5 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2324,14 +2324,19 @@ namespace ts { // code if the casted expression has a lower precedence than the rest of the // expression. // + // To preserve comments, we return a "PartiallyEmittedExpression" here which will + // preserve the position information of the original expression. + const partialExpression = createPartiallyEmittedExpression(expression, node); + // Due to the auto-parenthesization rules used by the visitor and factory functions // we can safely elide the parentheses here, as a new synthetic // ParenthesizedExpression will be inserted if we remove parentheses too // aggressively. - // - // To preserve comments, we return a "PartiallyEmittedExpression" here which will - // preserve the position information of the original expression. - return createPartiallyEmittedExpression(expression, node); + // However, auto-parenthesization will not preserve parenthesis for the following case: ({ "1": "one", "2": "two" } as { [key: string]: string })[x]. + // so we have to manually preserve it here. + const shouldPreserveParen = (isPropertyAccessExpression(node.parent) || isElementAccessExpression(node.parent)) && + isObjectLiteralExpression((expression as PartiallyEmittedExpression).expression); + return shouldPreserveParen ? createParen(partialExpression) : partialExpression; } return visitEachChild(node, visitor, context); diff --git a/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.js b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.js new file mode 100644 index 00000000000..1b07e3304d0 --- /dev/null +++ b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.js @@ -0,0 +1,7 @@ +//// [emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts] +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; + +//// [emitAccessExpressionOfCastedObjectLiteralExpressionES5.js] +(function (x) { return ({ "1": "one", "2": "two" })[x]; }); +(function (x) { return ({ "1": "one", "2": "two" }).x; }); diff --git a/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.symbols b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.symbols new file mode 100644 index 00000000000..a106295ce09 --- /dev/null +++ b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.symbols @@ -0,0 +1,10 @@ +=== tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts === +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts, 0, 1)) +>key : Symbol(key, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts, 0, 41)) +>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts, 0, 1)) + +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; +>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts, 1, 1)) +>key : Symbol(key, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts, 1, 41)) + diff --git a/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.types b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.types new file mode 100644 index 00000000000..82308ecfff9 --- /dev/null +++ b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES5.types @@ -0,0 +1,25 @@ +=== tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts === +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +>(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x] : (x: any) => string +>x : any +>({ "1": "one", "2": "two" } as { [key: string]: string })[x] : string +>({ "1": "one", "2": "two" } as { [key: string]: string }) : { [key: string]: string; } +>{ "1": "one", "2": "two" } as { [key: string]: string } : { [key: string]: string; } +>{ "1": "one", "2": "two" } : { "1": string; "2": string; } +>"one" : "one" +>"two" : "two" +>key : string +>x : any + +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; +>(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x : (x: any) => string +>x : any +>({ "1": "one", "2": "two" } as { [key: string]: string }).x : string +>({ "1": "one", "2": "two" } as { [key: string]: string }) : { [key: string]: string; } +>{ "1": "one", "2": "two" } as { [key: string]: string } : { [key: string]: string; } +>{ "1": "one", "2": "two" } : { "1": string; "2": string; } +>"one" : "one" +>"two" : "two" +>key : string +>x : string + diff --git a/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.js b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.js new file mode 100644 index 00000000000..7df1d4b8cf7 --- /dev/null +++ b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.js @@ -0,0 +1,7 @@ +//// [emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts] +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; + +//// [emitAccessExpressionOfCastedObjectLiteralExpressionES6.js] +(x) => ({ "1": "one", "2": "two" })[x]; +(x) => ({ "1": "one", "2": "two" }).x; diff --git a/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.symbols b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.symbols new file mode 100644 index 00000000000..0de1e97117c --- /dev/null +++ b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.symbols @@ -0,0 +1,10 @@ +=== tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts === +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts, 0, 1)) +>key : Symbol(key, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts, 0, 41)) +>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts, 0, 1)) + +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; +>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts, 1, 1)) +>key : Symbol(key, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts, 1, 41)) + diff --git a/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.types b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.types new file mode 100644 index 00000000000..a669c6427cb --- /dev/null +++ b/tests/baselines/reference/emitAccessExpressionOfCastedObjectLiteralExpressionES6.types @@ -0,0 +1,25 @@ +=== tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts === +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +>(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x] : (x: any) => string +>x : any +>({ "1": "one", "2": "two" } as { [key: string]: string })[x] : string +>({ "1": "one", "2": "two" } as { [key: string]: string }) : { [key: string]: string; } +>{ "1": "one", "2": "two" } as { [key: string]: string } : { [key: string]: string; } +>{ "1": "one", "2": "two" } : { "1": string; "2": string; } +>"one" : "one" +>"two" : "two" +>key : string +>x : any + +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; +>(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x : (x: any) => string +>x : any +>({ "1": "one", "2": "two" } as { [key: string]: string }).x : string +>({ "1": "one", "2": "two" } as { [key: string]: string }) : { [key: string]: string; } +>{ "1": "one", "2": "two" } as { [key: string]: string } : { [key: string]: string; } +>{ "1": "one", "2": "two" } : { "1": string; "2": string; } +>"one" : "one" +>"two" : "two" +>key : string +>x : string + diff --git a/tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts b/tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts new file mode 100644 index 00000000000..31c7face08d --- /dev/null +++ b/tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES5.ts @@ -0,0 +1,4 @@ +// @target: es5 + +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; \ No newline at end of file diff --git a/tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts b/tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts new file mode 100644 index 00000000000..ae3fe8a3f01 --- /dev/null +++ b/tests/cases/compiler/emitAccessExpressionOfCastedObjectLiteralExpressionES6.ts @@ -0,0 +1,4 @@ +// @target: es6 + +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string })[x]; +(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x; \ No newline at end of file