Merge pull request #10883 from Microsoft/fix10876

Fix missing final label
This commit is contained in:
Ron Buckton 2016-09-13 10:10:57 -07:00 committed by GitHub
commit 7e33955fe7
5 changed files with 103 additions and 1 deletions

View File

@ -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.
*

View File

@ -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*/];
}
});
});
}

View File

@ -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, --, --))
}
}

View File

@ -0,0 +1,20 @@
=== tests/cases/compiler/generatorTransformFinalLabel.ts ===
async function test(skip: boolean) {
>test : (skip: boolean) => Promise<void>
>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"
}
}

View File

@ -0,0 +1,11 @@
// @target: es5
// @lib: es5,es6
// @noEmitHelpers: true
async function test(skip: boolean) {
if (!skip) {
await 1
}
else {
throw Error('test')
}
}