[FIR] Basic support for break inside try-finally blocks
Support single try expression only
This commit is contained in:
committed by
teamcityserver
parent
a6984c5198
commit
c160511244
-1
@@ -56,7 +56,6 @@ object FirPropertyAccessorsTypesChecker : FirPropertyChecker() {
|
|||||||
reporter.reportOn(getterReturnTypeSource, FirErrors.WRONG_GETTER_RETURN_TYPE, propertyType, getterReturnType, context)
|
reporter.reportOn(getterReturnTypeSource, FirErrors.WRONG_GETTER_RETURN_TYPE, propertyType, getterReturnType, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FirFunctionReturnChecker.checkHasReturnIfBlock(getter, reporter, context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-2
@@ -603,7 +603,7 @@ class ControlFlowGraphBuilder {
|
|||||||
is FirBreakExpression -> loopExitNodes[jump.target.labeledElement]
|
is FirBreakExpression -> loopExitNodes[jump.target.labeledElement]
|
||||||
else -> throw IllegalArgumentException("Unknown jump type: ${jump.render()}")
|
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
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,6 +929,10 @@ class ControlFlowGraphBuilder {
|
|||||||
val tryExitNode = tryExitNodes.top()
|
val tryExitNode = tryExitNodes.top()
|
||||||
// a flow where either there wasn't any exception or caught if any.
|
// a flow where either there wasn't any exception or caught if any.
|
||||||
addEdge(it, tryExitNode)
|
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.
|
// a flow that exits to the exit target while there was an uncaught exception.
|
||||||
addEdge(it, exitTargetsForTry.top(), propagateDeadness = false, label = UncaughtExceptionPath)
|
addEdge(it, exitTargetsForTry.top(), propagateDeadness = false, label = UncaughtExceptionPath)
|
||||||
// TODO: differentiate flows that return/(re)throw in try main block and/or catch clauses
|
// 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,
|
preferredKind: EdgeKind = EdgeKind.Forward,
|
||||||
isBack: Boolean = false,
|
isBack: Boolean = false,
|
||||||
label: EdgeLabel = NormalPath,
|
label: EdgeLabel = NormalPath,
|
||||||
|
isBreak: Boolean = false
|
||||||
) {
|
) {
|
||||||
popAndAddEdge(node, preferredKind)
|
popAndAddEdge(node, preferredKind)
|
||||||
if (targetNode != null) {
|
if (targetNode != null) {
|
||||||
@@ -1325,7 +1330,16 @@ class ControlFlowGraphBuilder {
|
|||||||
addBackEdge(node, targetNode, label = label)
|
addBackEdge(node, targetNode, label = label)
|
||||||
}
|
}
|
||||||
} else {
|
} 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()
|
val stub = createStubNode()
|
||||||
@@ -1333,6 +1347,10 @@ class ControlFlowGraphBuilder {
|
|||||||
lastNodes.push(stub)
|
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) {
|
private fun popAndAddEdge(to: CFGNode<*>, preferredKind: EdgeKind = EdgeKind.Forward) {
|
||||||
addEdge(lastNodes.pop(), to, preferredKind = preferredKind)
|
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)
|
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 -----------------------------------
|
// ----------------------------------- Utils -----------------------------------
|
||||||
|
|
||||||
private inline fun Collection<FirDeclaration>.forEachMember(block: (FirDeclaration) -> Unit) {
|
private inline fun Collection<FirDeclaration>.forEachMember(block: (FirDeclaration) -> Unit) {
|
||||||
|
|||||||
Reference in New Issue
Block a user