From fc93e8f6f4affbde41f6e152b9d2bdd3e92b634d Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 28 Oct 2016 14:17:01 -0700 Subject: [PATCH] update CFG to properly handle do statements --- src/compiler/binder.ts | 16 ++++++--- .../reference/doWhileUnreachableCode.js | 26 ++++++++++++++ .../reference/doWhileUnreachableCode.symbols | 22 ++++++++++++ .../reference/doWhileUnreachableCode.types | 34 +++++++++++++++++++ .../cases/compiler/doWhileUnreachableCode.ts | 12 +++++++ 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/doWhileUnreachableCode.js create mode 100644 tests/baselines/reference/doWhileUnreachableCode.symbols create mode 100644 tests/baselines/reference/doWhileUnreachableCode.types create mode 100644 tests/cases/compiler/doWhileUnreachableCode.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9c2c749e112..613a50c6d3d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -892,8 +892,13 @@ namespace ts { function bindDoStatement(node: DoStatement): void { const preDoLabel = createLoopLabel(); - const preConditionLabel = createBranchLabel(); - const postDoLabel = createBranchLabel(); + const enclosingLabeledStatement = node.parent.kind === SyntaxKind.LabeledStatement + ? lastOrUndefined(activeLabels) + : undefined; + // if do statement is wrapped in labeled statement then target labels for break/continue with or without + // label should be the same + const preConditionLabel = enclosingLabeledStatement ? enclosingLabeledStatement.continueTarget : createBranchLabel(); + const postDoLabel = enclosingLabeledStatement ? enclosingLabeledStatement.breakTarget : createBranchLabel(); addAntecedent(preDoLabel, currentFlow); currentFlow = preDoLabel; bindIterativeStatement(node.statement, postDoLabel, preConditionLabel); @@ -1111,8 +1116,11 @@ namespace ts { if (!activeLabel.referenced && !options.allowUnusedLabels) { file.bindDiagnostics.push(createDiagnosticForNode(node.label, Diagnostics.Unused_label)); } - addAntecedent(postStatementLabel, currentFlow); - currentFlow = finishFlowLabel(postStatementLabel); + if (!node.statement || node.statement.kind !== SyntaxKind.DoStatement) { + // do statement sets current flow inside bindDoStatement + addAntecedent(postStatementLabel, currentFlow); + currentFlow = finishFlowLabel(postStatementLabel); + } } function bindDestructuringTargetFlow(node: Expression) { diff --git a/tests/baselines/reference/doWhileUnreachableCode.js b/tests/baselines/reference/doWhileUnreachableCode.js new file mode 100644 index 00000000000..3434a93f52d --- /dev/null +++ b/tests/baselines/reference/doWhileUnreachableCode.js @@ -0,0 +1,26 @@ +//// [doWhileUnreachableCode.ts] +function test() { + let foo = 0; + testLoop: do { + foo++; + continue testLoop; + } while (function() { + var x = 1; + return false; + }()); + + return foo; +} + +//// [doWhileUnreachableCode.js] +function test() { + var foo = 0; + testLoop: do { + foo++; + continue testLoop; + } while (function () { + var x = 1; + return false; + }()); + return foo; +} diff --git a/tests/baselines/reference/doWhileUnreachableCode.symbols b/tests/baselines/reference/doWhileUnreachableCode.symbols new file mode 100644 index 00000000000..571976490c3 --- /dev/null +++ b/tests/baselines/reference/doWhileUnreachableCode.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/doWhileUnreachableCode.ts === +function test() { +>test : Symbol(test, Decl(doWhileUnreachableCode.ts, 0, 0)) + + let foo = 0; +>foo : Symbol(foo, Decl(doWhileUnreachableCode.ts, 1, 7)) + + testLoop: do { + foo++; +>foo : Symbol(foo, Decl(doWhileUnreachableCode.ts, 1, 7)) + + continue testLoop; + } while (function() { + var x = 1; +>x : Symbol(x, Decl(doWhileUnreachableCode.ts, 6, 11)) + + return false; + }()); + + return foo; +>foo : Symbol(foo, Decl(doWhileUnreachableCode.ts, 1, 7)) +} diff --git a/tests/baselines/reference/doWhileUnreachableCode.types b/tests/baselines/reference/doWhileUnreachableCode.types new file mode 100644 index 00000000000..0c176dda799 --- /dev/null +++ b/tests/baselines/reference/doWhileUnreachableCode.types @@ -0,0 +1,34 @@ +=== tests/cases/compiler/doWhileUnreachableCode.ts === +function test() { +>test : () => number + + let foo = 0; +>foo : number +>0 : 0 + + testLoop: do { +>testLoop : any + + foo++; +>foo++ : number +>foo : number + + continue testLoop; +>testLoop : any + + } while (function() { +>function() { var x = 1; return false; }() : boolean +>function() { var x = 1; return false; } : () => boolean + + var x = 1; +>x : number +>1 : 1 + + return false; +>false : false + + }()); + + return foo; +>foo : number +} diff --git a/tests/cases/compiler/doWhileUnreachableCode.ts b/tests/cases/compiler/doWhileUnreachableCode.ts new file mode 100644 index 00000000000..e4b47fc1afb --- /dev/null +++ b/tests/cases/compiler/doWhileUnreachableCode.ts @@ -0,0 +1,12 @@ +function test() { + let foo = 0; + testLoop: do { + foo++; + continue testLoop; + } while (function() { + var x = 1; + return false; + }()); + + return foo; +} \ No newline at end of file