Skip to content

Commit c144e5e

Browse files
committed
Merge branch 'master' of https://github.com/Microsoft/TypeScript into bug/36989
2 parents 4605c34 + 56b6d0d commit c144e5e

File tree

64 files changed

+11853
-317
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+11853
-317
lines changed

src/compiler/binder.ts

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,10 @@ namespace ts {
952952
return initFlowNode({ flags: FlowFlags.LoopLabel, antecedents: undefined });
953953
}
954954

955+
function createReduceLabel(target: FlowLabel, antecedents: FlowNode[], antecedent: FlowNode): FlowReduceLabel {
956+
return initFlowNode({ flags: FlowFlags.ReduceLabel, target, antecedents, antecedent });
957+
}
958+
955959
function setFlowNodeReferenced(flow: FlowNode) {
956960
// On first reference we set the Referenced flag, thereafter we set the Shared flag
957961
flow.flags |= flow.flags & FlowFlags.Referenced ? FlowFlags.Shared : FlowFlags.Referenced;
@@ -1209,35 +1213,36 @@ namespace ts {
12091213
}
12101214

12111215
function bindTryStatement(node: TryStatement): void {
1212-
const preFinallyLabel = createBranchLabel();
12131216
// We conservatively assume that *any* code in the try block can cause an exception, but we only need
12141217
// to track code that causes mutations (because only mutations widen the possible control flow type of
1215-
// a variable). The currentExceptionTarget is the target label for control flows that result from
1216-
// exceptions. We add all mutation flow nodes as antecedents of this label such that we can analyze them
1217-
// as possible antecedents of the start of catch or finally blocks. Furthermore, we add the current
1218-
// control flow to represent exceptions that occur before any mutations.
1218+
// a variable). The exceptionLabel is the target label for control flows that result from exceptions.
1219+
// We add all mutation flow nodes as antecedents of this label such that we can analyze them as possible
1220+
// antecedents of the start of catch or finally blocks. Furthermore, we add the current control flow to
1221+
// represent exceptions that occur before any mutations.
12191222
const saveReturnTarget = currentReturnTarget;
12201223
const saveExceptionTarget = currentExceptionTarget;
1221-
currentReturnTarget = createBranchLabel();
1222-
currentExceptionTarget = node.catchClause ? createBranchLabel() : currentReturnTarget;
1223-
addAntecedent(currentExceptionTarget, currentFlow);
1224+
const normalExitLabel = createBranchLabel();
1225+
const returnLabel = createBranchLabel();
1226+
let exceptionLabel = createBranchLabel();
1227+
if (node.finallyBlock) {
1228+
currentReturnTarget = returnLabel;
1229+
}
1230+
addAntecedent(exceptionLabel, currentFlow);
1231+
currentExceptionTarget = exceptionLabel;
12241232
bind(node.tryBlock);
1225-
addAntecedent(preFinallyLabel, currentFlow);
1226-
const flowAfterTry = currentFlow;
1227-
let flowAfterCatch = unreachableFlow;
1233+
addAntecedent(normalExitLabel, currentFlow);
12281234
if (node.catchClause) {
12291235
// Start of catch clause is the target of exceptions from try block.
1230-
currentFlow = finishFlowLabel(currentExceptionTarget);
1236+
currentFlow = finishFlowLabel(exceptionLabel);
12311237
// The currentExceptionTarget now represents control flows from exceptions in the catch clause.
12321238
// Effectively, in a try-catch-finally, if an exception occurs in the try block, the catch block
12331239
// acts like a second try block.
1234-
currentExceptionTarget = currentReturnTarget;
1235-
addAntecedent(currentExceptionTarget, currentFlow);
1240+
exceptionLabel = createBranchLabel();
1241+
addAntecedent(exceptionLabel, currentFlow);
1242+
currentExceptionTarget = exceptionLabel;
12361243
bind(node.catchClause);
1237-
addAntecedent(preFinallyLabel, currentFlow);
1238-
flowAfterCatch = currentFlow;
1244+
addAntecedent(normalExitLabel, currentFlow);
12391245
}
1240-
const exceptionTarget = finishFlowLabel(currentExceptionTarget);
12411246
currentReturnTarget = saveReturnTarget;
12421247
currentExceptionTarget = saveExceptionTarget;
12431248
if (node.finallyBlock) {
@@ -1250,35 +1255,33 @@ namespace ts {
12501255
// When analyzing a control flow graph that starts inside a finally block we want to consider all
12511256
// five possibilities above. However, when analyzing a control flow graph that starts outside (past)
12521257
// the finally block, we only want to consider the first two (if we're past a finally block then it
1253-
// must have completed normally). To make this possible, we inject two extra nodes into the control
1254-
// flow graph: An after-finally with an antecedent of the control flow at the end of the finally
1255-
// block, and a pre-finally with an antecedent that represents all exceptional control flows. The
1256-
// 'lock' property of the pre-finally references the after-finally, and the after-finally has a
1257-
// boolean 'locked' property that we set to true when analyzing a control flow that contained the
1258-
// the after-finally node. When the lock associated with a pre-finally is locked, the antecedent of
1259-
// the pre-finally (i.e. the exceptional control flows) are skipped.
1260-
const preFinallyFlow: PreFinallyFlow = initFlowNode({ flags: FlowFlags.PreFinally, antecedent: exceptionTarget, lock: {} });
1261-
addAntecedent(preFinallyLabel, preFinallyFlow);
1262-
currentFlow = finishFlowLabel(preFinallyLabel);
1258+
// must have completed normally). Likewise, when analyzing a control flow graph from return statements
1259+
// in try or catch blocks in an IIFE, we only want to consider the third. To make this possible, we
1260+
// inject a ReduceLabel node into the control flow graph. This node contains an alternate reduced
1261+
// set of antecedents for the pre-finally label. As control flow analysis passes by a ReduceLabel
1262+
// node, the pre-finally label is temporarily switched to the reduced antecedent set.
1263+
const finallyLabel = createBranchLabel();
1264+
finallyLabel.antecedents = concatenate(concatenate(normalExitLabel.antecedents, exceptionLabel.antecedents), returnLabel.antecedents);
1265+
currentFlow = finallyLabel;
12631266
bind(node.finallyBlock);
1264-
// If the end of the finally block is reachable, but the end of the try and catch blocks are not,
1265-
// convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should
1266-
// result in an unreachable current control flow.
1267-
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
1268-
if ((flowAfterTry.flags & FlowFlags.Unreachable) && (flowAfterCatch.flags & FlowFlags.Unreachable)) {
1269-
currentFlow = flowAfterTry === reportedUnreachableFlow || flowAfterCatch === reportedUnreachableFlow
1270-
? reportedUnreachableFlow
1271-
: unreachableFlow;
1272-
}
1267+
if (currentFlow.flags & FlowFlags.Unreachable) {
1268+
// If the end of the finally block is unreachable, the end of the entire try statement is unreachable.
1269+
currentFlow = unreachableFlow;
12731270
}
1274-
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
1275-
const afterFinallyFlow: AfterFinallyFlow = initFlowNode({ flags: FlowFlags.AfterFinally, antecedent: currentFlow });
1276-
preFinallyFlow.lock = afterFinallyFlow;
1277-
currentFlow = afterFinallyFlow;
1271+
else {
1272+
// If we have an IIFE return target and return statements in the try or catch blocks, add a control
1273+
// flow that goes back through the finally block and back through only the return statements.
1274+
if (currentReturnTarget && returnLabel.antecedents) {
1275+
addAntecedent(currentReturnTarget, createReduceLabel(finallyLabel, returnLabel.antecedents, currentFlow));
1276+
}
1277+
// If the end of the finally block is reachable, but the end of the try and catch blocks are not,
1278+
// convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should
1279+
// result in an unreachable current control flow.
1280+
currentFlow = normalExitLabel.antecedents ? createReduceLabel(finallyLabel, normalExitLabel.antecedents, currentFlow) : unreachableFlow;
12781281
}
12791282
}
12801283
else {
1281-
currentFlow = finishFlowLabel(preFinallyLabel);
1284+
currentFlow = finishFlowLabel(normalExitLabel);
12821285
}
12831286
}
12841287

0 commit comments

Comments
 (0)