[FIR] Basic support for break inside try-finally blocks

Support single try expression only
This commit is contained in:
Andrey Zinovyev
2021-07-12 16:27:09 +03:00
committed by teamcityserver
parent a6984c5198
commit c160511244
2 changed files with 30 additions and 3 deletions
@@ -56,7 +56,6 @@ object FirPropertyAccessorsTypesChecker : FirPropertyChecker() {
reporter.reportOn(getterReturnTypeSource, FirErrors.WRONG_GETTER_RETURN_TYPE, propertyType, getterReturnType, context)
}
}
// FirFunctionReturnChecker.checkHasReturnIfBlock(getter, reporter, context)
}
}
@@ -603,7 +603,7 @@ class ControlFlowGraphBuilder {
is FirBreakExpression -> loopExitNodes[jump.target.labeledElement]
else -> throw IllegalArgumentException("Unknown jump type: ${jump.render()}")
}
addNodeWithJump(node, nextNode, isBack = jump is FirContinueExpression)
addNodeWithJump(node, nextNode, isBack = jump is FirContinueExpression, isBreak = jump is FirBreakExpression)
return node
}
@@ -929,6 +929,10 @@ class ControlFlowGraphBuilder {
val tryExitNode = tryExitNodes.top()
// a flow where either there wasn't any exception or caught if any.
addEdge(it, tryExitNode)
if (tryExitNode.isDead) {
//refresh forward links, which were created before finalizing try expression (eg created by `break`)
propagateDeadnessForward(tryExitNode)
}
// a flow that exits to the exit target while there was an uncaught exception.
addEdge(it, exitTargetsForTry.top(), propagateDeadness = false, label = UncaughtExceptionPath)
// TODO: differentiate flows that return/(re)throw in try main block and/or catch clauses
@@ -1314,6 +1318,7 @@ class ControlFlowGraphBuilder {
preferredKind: EdgeKind = EdgeKind.Forward,
isBack: Boolean = false,
label: EdgeLabel = NormalPath,
isBreak: Boolean = false
) {
popAndAddEdge(node, preferredKind)
if (targetNode != null) {
@@ -1325,7 +1330,16 @@ class ControlFlowGraphBuilder {
addBackEdge(node, targetNode, label = label)
}
} else {
addEdge(node, targetNode, propagateDeadness = false, label = label)
//TODO this supports single try-finally block only
//need to get all try-finally up to target
val finallyNodes = finallyBefore(targetNode)
if (finallyNodes != null && isBreak) {
val (finallyEnter, finallyExit) = finallyNodes
addEdge(node, finallyEnter, propagateDeadness = false, label = label)
addEdge(finallyExit, targetNode, propagateDeadness = false, label = label)
} else {
addEdge(node, targetNode, propagateDeadness = false, label = label)
}
}
}
val stub = createStubNode()
@@ -1333,6 +1347,10 @@ class ControlFlowGraphBuilder {
lastNodes.push(stub)
}
private fun finallyBefore(target: CFGNode<*>): Pair<FinallyBlockEnterNode, TryExpressionExitNode>? {
return finallyEnterNodes.topOrNull()?.takeIf { it.level > target.level }?.let { it to tryExitNodes.top() }
}
private fun popAndAddEdge(to: CFGNode<*>, preferredKind: EdgeKind = EdgeKind.Forward) {
addEdge(lastNodes.pop(), to, preferredKind = preferredKind)
}
@@ -1361,6 +1379,16 @@ class ControlFlowGraphBuilder {
addEdge(from, to, propagateDeadness = false, isDead = isDead, isBack = true, preferredKind = EdgeKind.CfgBackward, label = label)
}
private fun propagateDeadnessForward(node: CFGNode<*>) {
if (!node.isDead) return
node.followingNodes
.filter { node.outgoingEdges.getValue(it).kind == EdgeKind.Forward }
.forEach { target ->
CFGNode.addJustKindEdge(node, target, EdgeKind.DeadForward, false)
target.updateDeadStatus()
}
}
// ----------------------------------- Utils -----------------------------------
private inline fun Collection<FirDeclaration>.forEachMember(block: (FirDeclaration) -> Unit) {