FIR CFG: correct target and label for rethrow in try expression
^KT-45385 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
4f20d2dccf
commit
55561fad37
+35
-7
@@ -858,7 +858,7 @@ class ControlFlowGraphBuilder {
|
|||||||
val finallyEnterNode = finallyEnterNodes.topOrNull()
|
val finallyEnterNode = finallyEnterNodes.topOrNull()
|
||||||
// NB: Check the level to avoid adding an edge to the finally block at an upper level.
|
// NB: Check the level to avoid adding an edge to the finally block at an upper level.
|
||||||
if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) {
|
if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) {
|
||||||
// TODO: in case of return/throw in try main block, we need a unique label.
|
// TODO: in case of return/continue/break in try main block, we need a unique label.
|
||||||
addEdge(node, finallyEnterNode)
|
addEdge(node, finallyEnterNode)
|
||||||
} else {
|
} else {
|
||||||
addEdge(node, tryExitNodes.top())
|
addEdge(node, tryExitNodes.top())
|
||||||
@@ -891,7 +891,7 @@ class ControlFlowGraphBuilder {
|
|||||||
val finallyEnterNode = finallyEnterNodes.topOrNull()
|
val finallyEnterNode = finallyEnterNodes.topOrNull()
|
||||||
// NB: Check the level to avoid adding an edge to the finally block at an upper level.
|
// NB: Check the level to avoid adding an edge to the finally block at an upper level.
|
||||||
if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) {
|
if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) {
|
||||||
// TODO: in case of return/rethrow in catch clause, we need a unique label.
|
// TODO: in case of return/continue/break in catch clause, we need a unique label.
|
||||||
addEdge(it, finallyEnterNode, propagateDeadness = false)
|
addEdge(it, finallyEnterNode, propagateDeadness = false)
|
||||||
} else {
|
} else {
|
||||||
addEdge(it, tryExitNodes.top(), propagateDeadness = false)
|
addEdge(it, tryExitNodes.top(), propagateDeadness = false)
|
||||||
@@ -913,7 +913,9 @@ class ControlFlowGraphBuilder {
|
|||||||
addEdge(it, tryExitNode)
|
addEdge(it, 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(), label = UncaughtExceptionPath)
|
addEdge(it, exitTargetsForTry.top(), label = UncaughtExceptionPath)
|
||||||
// TODO: differentiate flows that return/(re)throw in try main block or catch clauses.
|
// TODO: differentiate flows that return/(re)throw in try main block and/or catch clauses
|
||||||
|
// To do so, we need mappings from such distinct label to original exit target (fun exit or loop)
|
||||||
|
// Also, CFG should support multiple edges towards the same destination node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1248,10 +1250,36 @@ class ControlFlowGraphBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addNodeThatReturnsNothing(node: CFGNode<*>, preferredKind: EdgeKind = EdgeKind.Forward) {
|
private fun addNodeThatReturnsNothing(node: CFGNode<*>, preferredKind: EdgeKind = EdgeKind.Forward) {
|
||||||
val exitNode: CFGNode<*> = exitTargetsForTry.top()
|
// If an expression, which returns Nothing, ...(1)
|
||||||
// If an expression, which returns Nothing, isn't inside a try/catch/finally, that is an uncaught exception path.
|
val targetNode = when {
|
||||||
val label = if (tryExitNodes.isEmpty) UncaughtExceptionPath else NormalPath
|
tryExitNodes.isEmpty -> {
|
||||||
addNodeWithJump(node, exitNode, preferredKind, label = label)
|
// (1)... isn't inside a try expression, that is an uncaught exception path.
|
||||||
|
exitTargetsForTry.top()
|
||||||
|
}
|
||||||
|
// (1)... inside a try expression...(2)
|
||||||
|
finallyEnterNodes.topOrNull()?.level == levelCounter -> {
|
||||||
|
// (2)... with finally
|
||||||
|
// Either in try-main or catch. Route to `finally`
|
||||||
|
finallyEnterNodes.top()
|
||||||
|
}
|
||||||
|
// (2)... without finally or within finally ...(3)
|
||||||
|
tryExitNodes.top().fir.finallyBlock == null -> {
|
||||||
|
// (3)... without finally ...(4)
|
||||||
|
// Either in try-main or catch.
|
||||||
|
if (tryExitNodes.size == tryMainExitNodes.size) {
|
||||||
|
// (4)... in catch, i.e., re-throw.
|
||||||
|
exitTargetsForTry.top()
|
||||||
|
} else {
|
||||||
|
// (4)... in try-main. We already have:
|
||||||
|
// edges from try-main enter node to each catch clause enter node and
|
||||||
|
// edges from catch clause enter node to exit target (w/ UncaughtExceptionPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// (3)... within finally.
|
||||||
|
else -> exitTargetsForTry.top()
|
||||||
|
}
|
||||||
|
addNodeWithJump(node, targetNode, preferredKind, label = UncaughtExceptionPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addNodeWithJump(
|
private fun addNodeWithJump(
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_FIR_DIAGNOSTICS
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
class A(val s: String)
|
class A(val s: String)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
fun foo(): Int = 42
|
fun foo(): Int = 42
|
||||||
|
|
||||||
object ThrowInTryWithCatch {
|
object ThrowInTryWithCatch {
|
||||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>private val p: String<!>
|
private val p: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
@@ -40,7 +40,7 @@ object ThrowInFinally {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object RethrowInCatch {
|
object RethrowInCatch {
|
||||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>private val p: String<!>
|
private val p: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
@@ -67,7 +67,7 @@ object RethrowInCatchWithFinally {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object InnerTryWithCatch {
|
object InnerTryWithCatch {
|
||||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>private val p: String<!>
|
private val p: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
@@ -117,7 +117,7 @@ object InnerTryWithCatchAndFinally {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object InnerCatch {
|
object InnerCatch {
|
||||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>private val p: String<!>
|
private val p: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
@@ -152,7 +152,7 @@ object InnerCatchWithFinally {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object InnerCatchOuterRethrow {
|
object InnerCatchOuterRethrow {
|
||||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>private val p: String<!>
|
private val p: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user