From 79037c6b897db3934b41155be75c91afe6289f68 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 27 Sep 2019 15:43:24 -0700 Subject: [PATCH 1/3] Add a test --- .../reference/comma-sef-operand.errors.txt | 9 +++++++++ .../baselines/reference/comma-sef-operand.js | 7 +++++++ .../reference/comma-sef-operand.symbols | 14 +++++++++++++ .../reference/comma-sef-operand.types | 20 +++++++++++++++++++ tests/cases/compiler/comma-sef-operand.ts | 2 ++ 5 files changed, 52 insertions(+) create mode 100644 tests/baselines/reference/comma-sef-operand.errors.txt create mode 100644 tests/baselines/reference/comma-sef-operand.js create mode 100644 tests/baselines/reference/comma-sef-operand.symbols create mode 100644 tests/baselines/reference/comma-sef-operand.types create mode 100644 tests/cases/compiler/comma-sef-operand.ts diff --git a/tests/baselines/reference/comma-sef-operand.errors.txt b/tests/baselines/reference/comma-sef-operand.errors.txt new file mode 100644 index 0000000000000..703094dd49d9a --- /dev/null +++ b/tests/baselines/reference/comma-sef-operand.errors.txt @@ -0,0 +1,9 @@ +tests/cases/compiler/comma-sef-operand.ts(2,16): error TS2695: Left side of comma operator is unused and has no side effects. + + +==== tests/cases/compiler/comma-sef-operand.ts (1 errors) ==== + declare const obj: any; + console.log(`${JSON.stringify(obj), undefined, 2}`); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2695: Left side of comma operator is unused and has no side effects. + \ No newline at end of file diff --git a/tests/baselines/reference/comma-sef-operand.js b/tests/baselines/reference/comma-sef-operand.js new file mode 100644 index 0000000000000..69f5b493e5ab6 --- /dev/null +++ b/tests/baselines/reference/comma-sef-operand.js @@ -0,0 +1,7 @@ +//// [comma-sef-operand.ts] +declare const obj: any; +console.log(`${JSON.stringify(obj), undefined, 2}`); + + +//// [comma-sef-operand.js] +console.log("" + (JSON.stringify(obj), undefined, 2)); diff --git a/tests/baselines/reference/comma-sef-operand.symbols b/tests/baselines/reference/comma-sef-operand.symbols new file mode 100644 index 0000000000000..f45163f0aaedf --- /dev/null +++ b/tests/baselines/reference/comma-sef-operand.symbols @@ -0,0 +1,14 @@ +=== tests/cases/compiler/comma-sef-operand.ts === +declare const obj: any; +>obj : Symbol(obj, Decl(comma-sef-operand.ts, 0, 13)) + +console.log(`${JSON.stringify(obj), undefined, 2}`); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>JSON.stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>obj : Symbol(obj, Decl(comma-sef-operand.ts, 0, 13)) +>undefined : Symbol(undefined) + diff --git a/tests/baselines/reference/comma-sef-operand.types b/tests/baselines/reference/comma-sef-operand.types new file mode 100644 index 0000000000000..c59460dad98bf --- /dev/null +++ b/tests/baselines/reference/comma-sef-operand.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/comma-sef-operand.ts === +declare const obj: any; +>obj : any + +console.log(`${JSON.stringify(obj), undefined, 2}`); +>console.log(`${JSON.stringify(obj), undefined, 2}`) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>`${JSON.stringify(obj), undefined, 2}` : string +>JSON.stringify(obj), undefined, 2 : 2 +>JSON.stringify(obj), undefined : undefined +>JSON.stringify(obj) : string +>JSON.stringify : { (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (string | number)[], space?: string | number): string; } +>JSON : JSON +>stringify : { (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (string | number)[], space?: string | number): string; } +>obj : any +>undefined : undefined +>2 : 2 + diff --git a/tests/cases/compiler/comma-sef-operand.ts b/tests/cases/compiler/comma-sef-operand.ts new file mode 100644 index 0000000000000..ce83d2a34f3cb --- /dev/null +++ b/tests/cases/compiler/comma-sef-operand.ts @@ -0,0 +1,2 @@ +declare const obj: any; +console.log(`${JSON.stringify(obj), undefined, 2}`); From 52240ddf106e793d150b12b9aedb6226efcf1c4b Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 27 Sep 2019 15:43:32 -0700 Subject: [PATCH 2/3] Update unrelated files --- .../reference/importExportInternalComments.js | 4 ++-- .../reference/importExportInternalComments.symbols | 2 +- .../reference/importExportInternalComments.types | 11 +++++++---- tests/cases/compiler/importExportInternalComments.ts | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/importExportInternalComments.js b/tests/baselines/reference/importExportInternalComments.js index c48d7a5ecf942..42e19f3838e2f 100644 --- a/tests/baselines/reference/importExportInternalComments.js +++ b/tests/baselines/reference/importExportInternalComments.js @@ -10,7 +10,7 @@ declare module "foo"; /*1*/ import /*2*/ D /*3*/, /*4*/ { /*5*/ A /*6*/, /*7*/ B /*8*/ as /*9*/ C /*10*/ } /*11*/ from /*12*/ "foo"; /*1*/ import /*2*/ * /*3*/ as /*4*/ foo /*5*/ from /*6*/ "foo"; -void D, A, C, foo; // Use the variables to prevent ellision +void D, void A, void C, void foo; // Use the variables to prevent ellision /*1*/ export /*2*/ { /*3*/ A /*4*/, /*5*/ B /*6*/ as /*7*/ C /*8*/ } /*9*/ from /*10*/ "foo"; /*1*/ export /*2*/ * /*3*/ from /*4*/ "foo" @@ -20,6 +20,6 @@ void D, A, C, foo; // Use the variables to prevent ellision //// [index.js] /*1*/ import /*2*/ D /*3*/, /*4*/ { /*5*/ A /*6*/, /*7*/ B /*8*/ as /*9*/ C /*10*/ } /*11*/ from /*12*/ "foo"; /*1*/ import /*2*/ * /*3*/ as /*4*/ foo /*5*/ from /*6*/ "foo"; -void D, A, C, foo; // Use the variables to prevent ellision +void D, void A, void C, void foo; // Use the variables to prevent ellision /*1*/ export /*2*/ { /*3*/ A /*4*/, /*5*/ B /*6*/ as /*7*/ C /*8*/ } /*9*/ from /*10*/ "foo"; /*1*/ export /*2*/ * /*3*/ from /*4*/ "foo"; diff --git a/tests/baselines/reference/importExportInternalComments.symbols b/tests/baselines/reference/importExportInternalComments.symbols index 87eeb2d31e9c9..e80de2c8bfee4 100644 --- a/tests/baselines/reference/importExportInternalComments.symbols +++ b/tests/baselines/reference/importExportInternalComments.symbols @@ -16,7 +16,7 @@ declare module "foo"; /*1*/ import /*2*/ * /*3*/ as /*4*/ foo /*5*/ from /*6*/ "foo"; >foo : Symbol(foo, Decl(index.ts, 1, 12)) -void D, A, C, foo; // Use the variables to prevent ellision +void D, void A, void C, void foo; // Use the variables to prevent ellision >D : Symbol(D, Decl(index.ts, 0, 12)) >A : Symbol(A, Decl(index.ts, 0, 35)) >C : Symbol(C, Decl(index.ts, 0, 50)) diff --git a/tests/baselines/reference/importExportInternalComments.types b/tests/baselines/reference/importExportInternalComments.types index 602a89fe5d0bb..eb25f342723e1 100644 --- a/tests/baselines/reference/importExportInternalComments.types +++ b/tests/baselines/reference/importExportInternalComments.types @@ -16,14 +16,17 @@ declare module "foo"; /*1*/ import /*2*/ * /*3*/ as /*4*/ foo /*5*/ from /*6*/ "foo"; >foo : any -void D, A, C, foo; // Use the variables to prevent ellision ->void D, A, C, foo : any ->void D, A, C : any ->void D, A : any +void D, void A, void C, void foo; // Use the variables to prevent ellision +>void D, void A, void C, void foo : undefined +>void D, void A, void C : undefined +>void D, void A : undefined >void D : undefined >D : any +>void A : undefined >A : any +>void C : undefined >C : any +>void foo : undefined >foo : any /*1*/ export /*2*/ { /*3*/ A /*4*/, /*5*/ B /*6*/ as /*7*/ C /*8*/ } /*9*/ from /*10*/ "foo"; diff --git a/tests/cases/compiler/importExportInternalComments.ts b/tests/cases/compiler/importExportInternalComments.ts index 64119078f3d29..63cf4c0b3cff7 100644 --- a/tests/cases/compiler/importExportInternalComments.ts +++ b/tests/cases/compiler/importExportInternalComments.ts @@ -9,7 +9,7 @@ declare module "foo"; /*1*/ import /*2*/ D /*3*/, /*4*/ { /*5*/ A /*6*/, /*7*/ B /*8*/ as /*9*/ C /*10*/ } /*11*/ from /*12*/ "foo"; /*1*/ import /*2*/ * /*3*/ as /*4*/ foo /*5*/ from /*6*/ "foo"; -void D, A, C, foo; // Use the variables to prevent ellision +void D, void A, void C, void foo; // Use the variables to prevent ellision /*1*/ export /*2*/ { /*3*/ A /*4*/, /*5*/ B /*6*/ as /*7*/ C /*8*/ } /*9*/ from /*10*/ "foo"; /*1*/ export /*2*/ * /*3*/ from /*4*/ "foo" \ No newline at end of file From d851fd2190ac0eaf377f7854cdc9ff2a97eb1d66 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 27 Sep 2019 15:43:50 -0700 Subject: [PATCH 3/3] A comma operator is SEF if *either* of its operands are --- src/compiler/checker.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1aa95546d3d84..267d97cdad9b7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -24378,7 +24378,7 @@ namespace ts { } /** - * This is a *shallow* check: An expression is side-effect-free if the + * This is a *shallow* check: An expression is side-effect-free (SEF) if the * evaluation of the expression *itself* cannot produce side effects. * For example, x++ / 3 is side-effect free because the / operator * does not have side effects. @@ -24419,6 +24419,12 @@ namespace ts { if (isAssignmentOperator((node as BinaryExpression).operatorToken.kind)) { return false; } + if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken) { + // A comma operator is SEF if either operand is SEF, e.g. the template argument in + // `The coordinates are ${x.toString(), y, z}` + // contains an illegally SEF expression at 'y' (the left side of the outer comma whose right operand is 'z') + return isSideEffectFree((node as BinaryExpression).left) || isSideEffectFree((node as BinaryExpression).right); + } return isSideEffectFree((node as BinaryExpression).left) && isSideEffectFree((node as BinaryExpression).right);