Skip to content

Commit 7e33955

Browse files
authored
Merge pull request #10883 from Microsoft/fix10876
Fix missing final label
2 parents 95210ac + 899ce32 commit 7e33955

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

src/compiler/transformers/generators.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2629,7 +2629,7 @@ namespace ts {
26292629
* Flush the final label of the generator function body.
26302630
*/
26312631
function flushFinalLabel(operationIndex: number): void {
2632-
if (!lastOperationWasCompletion) {
2632+
if (isFinalLabelReachable(operationIndex)) {
26332633
tryEnterLabel(operationIndex);
26342634
withBlockStack = undefined;
26352635
writeReturn(/*expression*/ undefined, /*operationLocation*/ undefined);
@@ -2642,6 +2642,34 @@ namespace ts {
26422642
updateLabelExpressions();
26432643
}
26442644

2645+
/**
2646+
* Tests whether the final label of the generator function body
2647+
* is reachable by user code.
2648+
*/
2649+
function isFinalLabelReachable(operationIndex: number) {
2650+
// if the last operation was *not* a completion (return/throw) then
2651+
// the final label is reachable.
2652+
if (!lastOperationWasCompletion) {
2653+
return true;
2654+
}
2655+
2656+
// if there are no labels defined or referenced, then the final label is
2657+
// not reachable.
2658+
if (!labelOffsets || !labelExpressions) {
2659+
return false;
2660+
}
2661+
2662+
// if the label for this offset is referenced, then the final label
2663+
// is reachable.
2664+
for (let label = 0; label < labelOffsets.length; label++) {
2665+
if (labelOffsets[label] === operationIndex && labelExpressions[label]) {
2666+
return true;
2667+
}
2668+
}
2669+
2670+
return false;
2671+
}
2672+
26452673
/**
26462674
* Appends a case clause for the last label and sets the new label.
26472675
*
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [generatorTransformFinalLabel.ts]
2+
async function test(skip: boolean) {
3+
if (!skip) {
4+
await 1
5+
}
6+
else {
7+
throw Error('test')
8+
}
9+
}
10+
11+
//// [generatorTransformFinalLabel.js]
12+
function test(skip) {
13+
return __awaiter(this, void 0, void 0, function () {
14+
return __generator(this, function (_a) {
15+
switch (_a.label) {
16+
case 0:
17+
if (!!skip)
18+
return [3 /*break*/, 2];
19+
return [4 /*yield*/, 1];
20+
case 1:
21+
_a.sent();
22+
return [3 /*break*/, 3];
23+
case 2: throw Error('test');
24+
case 3: return [2 /*return*/];
25+
}
26+
});
27+
});
28+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/generatorTransformFinalLabel.ts ===
2+
async function test(skip: boolean) {
3+
>test : Symbol(test, Decl(generatorTransformFinalLabel.ts, 0, 0))
4+
>skip : Symbol(skip, Decl(generatorTransformFinalLabel.ts, 0, 20))
5+
6+
if (!skip) {
7+
>skip : Symbol(skip, Decl(generatorTransformFinalLabel.ts, 0, 20))
8+
9+
await 1
10+
}
11+
else {
12+
throw Error('test')
13+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
14+
}
15+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/compiler/generatorTransformFinalLabel.ts ===
2+
async function test(skip: boolean) {
3+
>test : (skip: boolean) => Promise<void>
4+
>skip : boolean
5+
6+
if (!skip) {
7+
>!skip : boolean
8+
>skip : boolean
9+
10+
await 1
11+
>await 1 : 1
12+
>1 : 1
13+
}
14+
else {
15+
throw Error('test')
16+
>Error('test') : Error
17+
>Error : ErrorConstructor
18+
>'test' : "test"
19+
}
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// @target: es5
2+
// @lib: es5,es6
3+
// @noEmitHelpers: true
4+
async function test(skip: boolean) {
5+
if (!skip) {
6+
await 1
7+
}
8+
else {
9+
throw Error('test')
10+
}
11+
}

0 commit comments

Comments
 (0)