Fix not emitted statement in then clauses producing syntactically invalid output (#32010)

* Fix not emitted statement in then clauses producing syntactically invalid output

* Refactor to common code, apply to all embedded statements
This commit is contained in:
Wesley Wigham
2019-07-01 13:39:18 -07:00
committed by GitHub
parent 11a62cb0ab
commit 3765651d82
9 changed files with 189 additions and 18 deletions

View File

@@ -1544,8 +1544,8 @@ namespace ts {
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement) {
const node = <IfStatement>createSynthesizedNode(SyntaxKind.IfStatement);
node.expression = expression;
node.thenStatement = thenStatement;
node.elseStatement = elseStatement;
node.thenStatement = asEmbeddedStatement(thenStatement);
node.elseStatement = asEmbeddedStatement(elseStatement);
return node;
}
@@ -1559,7 +1559,7 @@ namespace ts {
export function createDo(statement: Statement, expression: Expression) {
const node = <DoStatement>createSynthesizedNode(SyntaxKind.DoStatement);
node.statement = statement;
node.statement = asEmbeddedStatement(statement);
node.expression = expression;
return node;
}
@@ -1574,7 +1574,7 @@ namespace ts {
export function createWhile(expression: Expression, statement: Statement) {
const node = <WhileStatement>createSynthesizedNode(SyntaxKind.WhileStatement);
node.expression = expression;
node.statement = statement;
node.statement = asEmbeddedStatement(statement);
return node;
}
@@ -1590,7 +1590,7 @@ namespace ts {
node.initializer = initializer;
node.condition = condition;
node.incrementor = incrementor;
node.statement = statement;
node.statement = asEmbeddedStatement(statement);
return node;
}
@@ -1607,7 +1607,7 @@ namespace ts {
const node = <ForInStatement>createSynthesizedNode(SyntaxKind.ForInStatement);
node.initializer = initializer;
node.expression = expression;
node.statement = statement;
node.statement = asEmbeddedStatement(statement);
return node;
}
@@ -1624,7 +1624,7 @@ namespace ts {
node.awaitModifier = awaitModifier;
node.initializer = initializer;
node.expression = expression;
node.statement = statement;
node.statement = asEmbeddedStatement(statement);
return node;
}
@@ -1676,7 +1676,7 @@ namespace ts {
export function createWith(expression: Expression, statement: Statement) {
const node = <WithStatement>createSynthesizedNode(SyntaxKind.WithStatement);
node.expression = expression;
node.statement = statement;
node.statement = asEmbeddedStatement(statement);
return node;
}
@@ -1704,7 +1704,7 @@ namespace ts {
export function createLabel(label: string | Identifier, statement: Statement) {
const node = <LabeledStatement>createSynthesizedNode(SyntaxKind.LabeledStatement);
node.label = asName(label);
node.statement = statement;
node.statement = asEmbeddedStatement(statement);
return node;
}
@@ -3080,6 +3080,12 @@ namespace ts {
return typeof value === "number" ? createToken(value) : value;
}
function asEmbeddedStatement<T extends Node>(statement: T): T | EmptyStatement;
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined;
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined {
return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement;
}
/**
* Clears any EmitNode entries from parse-tree nodes.
* @param sourceFile A source file.

View File

@@ -9,5 +9,8 @@ else
//// [constEnum4.js]
if (1)
;
else if (2)
;
else
;

View File

@@ -0,0 +1,47 @@
//// [elidedEmbeddedStatementsReplacedWithSemicolon.ts]
if (1)
const enum A {}
else
const enum B {}
do
const enum C {}
while (0);
while (0)
const enum D {}
for (;0;)
const enum E {}
for (let _ in [])
const enum F {}
for (let _ of [])
const enum G {}
// @ts-ignore suppress `with` statement error
with (window)
const enum H {}
//// [elidedEmbeddedStatementsReplacedWithSemicolon.js]
if (1)
;
else
;
do
;
while (0);
while (0)
;
for (; 0;)
;
for (var _ in [])
;
for (var _i = 0, _a = []; _i < _a.length; _i++) {
var _ = _a[_i];
;
}
// @ts-ignore suppress `with` statement error
with (window)
;

View File

@@ -0,0 +1,40 @@
=== tests/cases/compiler/elidedEmbeddedStatementsReplacedWithSemicolon.ts ===
if (1)
const enum A {}
>A : Symbol(A, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 0, 6))
else
const enum B {}
>B : Symbol(B, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 2, 4))
do
const enum C {}
>C : Symbol(C, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 5, 2))
while (0);
while (0)
const enum D {}
>D : Symbol(D, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 9, 9))
for (;0;)
const enum E {}
>E : Symbol(E, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 12, 9))
for (let _ in [])
>_ : Symbol(_, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 15, 8))
const enum F {}
>F : Symbol(F, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 15, 17))
for (let _ of [])
>_ : Symbol(_, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 18, 8))
const enum G {}
>G : Symbol(G, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 18, 17))
// @ts-ignore suppress `with` statement error
with (window)
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
const enum H {}

View File

@@ -0,0 +1,51 @@
=== tests/cases/compiler/elidedEmbeddedStatementsReplacedWithSemicolon.ts ===
if (1)
>1 : 1
const enum A {}
>A : A
else
const enum B {}
>B : B
do
const enum C {}
>C : C
while (0);
>0 : 0
while (0)
>0 : 0
const enum D {}
>D : D
for (;0;)
>0 : 0
const enum E {}
>E : E
for (let _ in [])
>_ : string
>[] : undefined[]
const enum F {}
>F : F
for (let _ of [])
>_ : any
>[] : undefined[]
const enum G {}
>G : G
// @ts-ignore suppress `with` statement error
with (window)
>window : Window
const enum H {}
>H : error

View File

@@ -64,7 +64,7 @@ label: {
(function (E) {
})(E || (E = {}));
}
label:
label: ;
label: {
var C = /** @class */ (function () {
function C() {
@@ -75,6 +75,6 @@ label: {
label: var a = 1;
label: var b = 1;
label: var c = 1;
label:
label:
label: ;
label: ;
label:

View File

@@ -33,12 +33,12 @@ label: {
(function (E) {
})(E || (E = {}));
}
label:
label: ;
label: class C {
}
label: var a = 1;
label: let b = 1;
label: const c = 1;
label:
label:
label: ;
label: ;
label:

View File

@@ -35,12 +35,12 @@ label: {
(function (E) {
})(E || (E = {}));
}
label:
label: ;
label: class C {
}
label: var a = 1;
label: let b = 1;
label: const c = 1;
label:
label:
label: ;
label: ;
label:

View File

@@ -0,0 +1,24 @@
if (1)
const enum A {}
else
const enum B {}
do
const enum C {}
while (0);
while (0)
const enum D {}
for (;0;)
const enum E {}
for (let _ in [])
const enum F {}
for (let _ of [])
const enum G {}
// @ts-ignore suppress `with` statement error
with (window)
const enum H {}