Skip to content

Commit 3765651

Browse files
authored
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
1 parent 11a62cb commit 3765651

9 files changed

+189
-18
lines changed

src/compiler/factory.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,8 +1544,8 @@ namespace ts {
15441544
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement) {
15451545
const node = <IfStatement>createSynthesizedNode(SyntaxKind.IfStatement);
15461546
node.expression = expression;
1547-
node.thenStatement = thenStatement;
1548-
node.elseStatement = elseStatement;
1547+
node.thenStatement = asEmbeddedStatement(thenStatement);
1548+
node.elseStatement = asEmbeddedStatement(elseStatement);
15491549
return node;
15501550
}
15511551

@@ -1559,7 +1559,7 @@ namespace ts {
15591559

15601560
export function createDo(statement: Statement, expression: Expression) {
15611561
const node = <DoStatement>createSynthesizedNode(SyntaxKind.DoStatement);
1562-
node.statement = statement;
1562+
node.statement = asEmbeddedStatement(statement);
15631563
node.expression = expression;
15641564
return node;
15651565
}
@@ -1574,7 +1574,7 @@ namespace ts {
15741574
export function createWhile(expression: Expression, statement: Statement) {
15751575
const node = <WhileStatement>createSynthesizedNode(SyntaxKind.WhileStatement);
15761576
node.expression = expression;
1577-
node.statement = statement;
1577+
node.statement = asEmbeddedStatement(statement);
15781578
return node;
15791579
}
15801580

@@ -1590,7 +1590,7 @@ namespace ts {
15901590
node.initializer = initializer;
15911591
node.condition = condition;
15921592
node.incrementor = incrementor;
1593-
node.statement = statement;
1593+
node.statement = asEmbeddedStatement(statement);
15941594
return node;
15951595
}
15961596

@@ -1607,7 +1607,7 @@ namespace ts {
16071607
const node = <ForInStatement>createSynthesizedNode(SyntaxKind.ForInStatement);
16081608
node.initializer = initializer;
16091609
node.expression = expression;
1610-
node.statement = statement;
1610+
node.statement = asEmbeddedStatement(statement);
16111611
return node;
16121612
}
16131613

@@ -1624,7 +1624,7 @@ namespace ts {
16241624
node.awaitModifier = awaitModifier;
16251625
node.initializer = initializer;
16261626
node.expression = expression;
1627-
node.statement = statement;
1627+
node.statement = asEmbeddedStatement(statement);
16281628
return node;
16291629
}
16301630

@@ -1676,7 +1676,7 @@ namespace ts {
16761676
export function createWith(expression: Expression, statement: Statement) {
16771677
const node = <WithStatement>createSynthesizedNode(SyntaxKind.WithStatement);
16781678
node.expression = expression;
1679-
node.statement = statement;
1679+
node.statement = asEmbeddedStatement(statement);
16801680
return node;
16811681
}
16821682

@@ -1704,7 +1704,7 @@ namespace ts {
17041704
export function createLabel(label: string | Identifier, statement: Statement) {
17051705
const node = <LabeledStatement>createSynthesizedNode(SyntaxKind.LabeledStatement);
17061706
node.label = asName(label);
1707-
node.statement = statement;
1707+
node.statement = asEmbeddedStatement(statement);
17081708
return node;
17091709
}
17101710

@@ -3080,6 +3080,12 @@ namespace ts {
30803080
return typeof value === "number" ? createToken(value) : value;
30813081
}
30823082

3083+
function asEmbeddedStatement<T extends Node>(statement: T): T | EmptyStatement;
3084+
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined;
3085+
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined {
3086+
return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement;
3087+
}
3088+
30833089
/**
30843090
* Clears any EmitNode entries from parse-tree nodes.
30853091
* @param sourceFile A source file.

tests/baselines/reference/constEnum4.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ else
99

1010
//// [constEnum4.js]
1111
if (1)
12+
;
1213
else if (2)
14+
;
1315
else
16+
;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//// [elidedEmbeddedStatementsReplacedWithSemicolon.ts]
2+
if (1)
3+
const enum A {}
4+
else
5+
const enum B {}
6+
7+
do
8+
const enum C {}
9+
while (0);
10+
11+
while (0)
12+
const enum D {}
13+
14+
for (;0;)
15+
const enum E {}
16+
17+
for (let _ in [])
18+
const enum F {}
19+
20+
for (let _ of [])
21+
const enum G {}
22+
23+
// @ts-ignore suppress `with` statement error
24+
with (window)
25+
const enum H {}
26+
27+
//// [elidedEmbeddedStatementsReplacedWithSemicolon.js]
28+
if (1)
29+
;
30+
else
31+
;
32+
do
33+
;
34+
while (0);
35+
while (0)
36+
;
37+
for (; 0;)
38+
;
39+
for (var _ in [])
40+
;
41+
for (var _i = 0, _a = []; _i < _a.length; _i++) {
42+
var _ = _a[_i];
43+
;
44+
}
45+
// @ts-ignore suppress `with` statement error
46+
with (window)
47+
;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
=== tests/cases/compiler/elidedEmbeddedStatementsReplacedWithSemicolon.ts ===
2+
if (1)
3+
const enum A {}
4+
>A : Symbol(A, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 0, 6))
5+
6+
else
7+
const enum B {}
8+
>B : Symbol(B, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 2, 4))
9+
10+
do
11+
const enum C {}
12+
>C : Symbol(C, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 5, 2))
13+
14+
while (0);
15+
16+
while (0)
17+
const enum D {}
18+
>D : Symbol(D, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 9, 9))
19+
20+
for (;0;)
21+
const enum E {}
22+
>E : Symbol(E, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 12, 9))
23+
24+
for (let _ in [])
25+
>_ : Symbol(_, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 15, 8))
26+
27+
const enum F {}
28+
>F : Symbol(F, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 15, 17))
29+
30+
for (let _ of [])
31+
>_ : Symbol(_, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 18, 8))
32+
33+
const enum G {}
34+
>G : Symbol(G, Decl(elidedEmbeddedStatementsReplacedWithSemicolon.ts, 18, 17))
35+
36+
// @ts-ignore suppress `with` statement error
37+
with (window)
38+
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
39+
40+
const enum H {}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
=== tests/cases/compiler/elidedEmbeddedStatementsReplacedWithSemicolon.ts ===
2+
if (1)
3+
>1 : 1
4+
5+
const enum A {}
6+
>A : A
7+
8+
else
9+
const enum B {}
10+
>B : B
11+
12+
do
13+
const enum C {}
14+
>C : C
15+
16+
while (0);
17+
>0 : 0
18+
19+
while (0)
20+
>0 : 0
21+
22+
const enum D {}
23+
>D : D
24+
25+
for (;0;)
26+
>0 : 0
27+
28+
const enum E {}
29+
>E : E
30+
31+
for (let _ in [])
32+
>_ : string
33+
>[] : undefined[]
34+
35+
const enum F {}
36+
>F : F
37+
38+
for (let _ of [])
39+
>_ : any
40+
>[] : undefined[]
41+
42+
const enum G {}
43+
>G : G
44+
45+
// @ts-ignore suppress `with` statement error
46+
with (window)
47+
>window : Window
48+
49+
const enum H {}
50+
>H : error
51+

tests/baselines/reference/labeledStatementWithLabel.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ label: {
6464
(function (E) {
6565
})(E || (E = {}));
6666
}
67-
label:
67+
label: ;
6868
label: {
6969
var C = /** @class */ (function () {
7070
function C() {
@@ -75,6 +75,6 @@ label: {
7575
label: var a = 1;
7676
label: var b = 1;
7777
label: var c = 1;
78-
label:
79-
label:
78+
label: ;
79+
label: ;
8080
label:

tests/baselines/reference/labeledStatementWithLabel_es2015.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ label: {
3333
(function (E) {
3434
})(E || (E = {}));
3535
}
36-
label:
36+
label: ;
3737
label: class C {
3838
}
3939
label: var a = 1;
4040
label: let b = 1;
4141
label: const c = 1;
42-
label:
43-
label:
42+
label: ;
43+
label: ;
4444
label:

tests/baselines/reference/labeledStatementWithLabel_strict.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ label: {
3535
(function (E) {
3636
})(E || (E = {}));
3737
}
38-
label:
38+
label: ;
3939
label: class C {
4040
}
4141
label: var a = 1;
4242
label: let b = 1;
4343
label: const c = 1;
44-
label:
45-
label:
44+
label: ;
45+
label: ;
4646
label:
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
if (1)
2+
const enum A {}
3+
else
4+
const enum B {}
5+
6+
do
7+
const enum C {}
8+
while (0);
9+
10+
while (0)
11+
const enum D {}
12+
13+
for (;0;)
14+
const enum E {}
15+
16+
for (let _ in [])
17+
const enum F {}
18+
19+
for (let _ of [])
20+
const enum G {}
21+
22+
// @ts-ignore suppress `with` statement error
23+
with (window)
24+
const enum H {}

0 commit comments

Comments
 (0)