diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 9a4b567cb80..22dee43b686 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -2629,7 +2629,7 @@ namespace ts { * Flush the final label of the generator function body. */ function flushFinalLabel(operationIndex: number): void { - if (!lastOperationWasCompletion) { + if (isFinalLabelReachable(operationIndex)) { tryEnterLabel(operationIndex); withBlockStack = undefined; writeReturn(/*expression*/ undefined, /*operationLocation*/ undefined); @@ -2642,6 +2642,34 @@ namespace ts { updateLabelExpressions(); } + /** + * Tests whether the final label of the generator function body + * is reachable by user code. + */ + function isFinalLabelReachable(operationIndex: number) { + // if the last operation was *not* a completion (return/throw) then + // the final label is reachable. + if (!lastOperationWasCompletion) { + return true; + } + + // if there are no labels defined or referenced, then the final label is + // not reachable. + if (!labelOffsets || !labelExpressions) { + return false; + } + + // if the label for this offset is referenced, then the final label + // is reachable. + for (let label = 0; label < labelOffsets.length; label++) { + if (labelOffsets[label] === operationIndex && labelExpressions[label]) { + return true; + } + } + + return false; + } + /** * Appends a case clause for the last label and sets the new label. * diff --git a/tests/baselines/reference/generatorTransformFinalLabel.js b/tests/baselines/reference/generatorTransformFinalLabel.js new file mode 100644 index 00000000000..32272ae0748 --- /dev/null +++ b/tests/baselines/reference/generatorTransformFinalLabel.js @@ -0,0 +1,28 @@ +//// [generatorTransformFinalLabel.ts] +async function test(skip: boolean) { + if (!skip) { + await 1 + } + else { + throw Error('test') + } +} + +//// [generatorTransformFinalLabel.js] +function test(skip) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!!skip) + return [3 /*break*/, 2]; + return [4 /*yield*/, 1]; + case 1: + _a.sent(); + return [3 /*break*/, 3]; + case 2: throw Error('test'); + case 3: return [2 /*return*/]; + } + }); + }); +} diff --git a/tests/baselines/reference/generatorTransformFinalLabel.symbols b/tests/baselines/reference/generatorTransformFinalLabel.symbols new file mode 100644 index 00000000000..8f6fd791476 --- /dev/null +++ b/tests/baselines/reference/generatorTransformFinalLabel.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/generatorTransformFinalLabel.ts === +async function test(skip: boolean) { +>test : Symbol(test, Decl(generatorTransformFinalLabel.ts, 0, 0)) +>skip : Symbol(skip, Decl(generatorTransformFinalLabel.ts, 0, 20)) + + if (!skip) { +>skip : Symbol(skip, Decl(generatorTransformFinalLabel.ts, 0, 20)) + + await 1 + } + else { + throw Error('test') +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } +} diff --git a/tests/baselines/reference/generatorTransformFinalLabel.types b/tests/baselines/reference/generatorTransformFinalLabel.types new file mode 100644 index 00000000000..988428ad1d1 --- /dev/null +++ b/tests/baselines/reference/generatorTransformFinalLabel.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/generatorTransformFinalLabel.ts === +async function test(skip: boolean) { +>test : (skip: boolean) => Promise +>skip : boolean + + if (!skip) { +>!skip : boolean +>skip : boolean + + await 1 +>await 1 : 1 +>1 : 1 + } + else { + throw Error('test') +>Error('test') : Error +>Error : ErrorConstructor +>'test' : "test" + } +} diff --git a/tests/cases/compiler/generatorTransformFinalLabel.ts b/tests/cases/compiler/generatorTransformFinalLabel.ts new file mode 100644 index 00000000000..2dab26b1f08 --- /dev/null +++ b/tests/cases/compiler/generatorTransformFinalLabel.ts @@ -0,0 +1,11 @@ +// @target: es5 +// @lib: es5,es6 +// @noEmitHelpers: true +async function test(skip: boolean) { + if (!skip) { + await 1 + } + else { + throw Error('test') + } +} \ No newline at end of file