[FIR] Fix break/continue in try-finally in loop, ^KT-51759

This commit is contained in:
Ivan Kochurkin
2022-03-31 13:49:40 +03:00
committed by teamcity
parent e9b9322672
commit c7122c1492
9 changed files with 65 additions and 8 deletions
@@ -5434,6 +5434,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinally.kt");
}
@Test
@TestMetadata("breakContinueInTryFinallyInLoop.kt")
public void testBreakContinueInTryFinallyInLoop() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinallyInLoop.kt");
}
@Test
@TestMetadata("breakInsideLocal.kt")
public void testBreakInsideLocal() throws Exception {
@@ -5434,6 +5434,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinally.kt");
}
@Test
@TestMetadata("breakContinueInTryFinallyInLoop.kt")
public void testBreakContinueInTryFinallyInLoop() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinallyInLoop.kt");
}
@Test
@TestMetadata("breakInsideLocal.kt")
public void testBreakInsideLocal() throws Exception {
@@ -5434,6 +5434,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinally.kt");
}
@Test
@TestMetadata("breakContinueInTryFinallyInLoop.kt")
public void testBreakContinueInTryFinallyInLoop() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinallyInLoop.kt");
}
@Test
@TestMetadata("breakInsideLocal.kt")
public void testBreakInsideLocal() throws Exception {
@@ -16,9 +16,6 @@ abstract class PathAwareControlFlowInfo<P : PathAwareControlFlowInfo<P, S>, S :
internal val infoAtNormalPath: S
get() = map.getValue(NormalPath)
private val hasNormalPath: Boolean
get() = map.containsKey(NormalPath)
fun applyLabel(node: CFGNode<*>, label: EdgeLabel): P {
if (label.isNormal) {
// Special case: when we exit the try expression, null label means a normal path.
@@ -26,7 +23,8 @@ abstract class PathAwareControlFlowInfo<P : PathAwareControlFlowInfo<P, S>, S :
// One day, if we allow multiple edges between nodes with different labels, e.g., labeling all paths in try/catch/finally,
// instead of this kind of special handling, proxy enter/exit nodes per label are preferred.
if (node is TryExpressionExitNode) {
return if (hasNormalPath) {
val infoAtNormalPath = map[NormalPath]
return if (infoAtNormalPath != null) {
constructor(persistentMapOf(NormalPath to infoAtNormalPath))
} else {
/* This means no info for normal path. */
@@ -640,10 +640,10 @@ class ControlFlowGraphBuilder {
else -> throw IllegalArgumentException("Unknown jump type: ${jump.render()}")
}
val labelForFinallyBLock = if (jump is FirReturnExpression) {
ReturnPath(jump.target.labeledElement.symbol)
} else {
NormalPath
val labelForFinallyBLock = when (jump) {
is FirReturnExpression -> ReturnPath(jump.target.labeledElement.symbol)
is FirLoopJump -> LoopPath(jump)
else -> NormalPath
}
addNodeWithJump(
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.fir.resolve.dfa.cfg
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.expressions.FirBreakExpression
import org.jetbrains.kotlin.fir.expressions.FirLoopJump
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
class ControlFlowGraph(val declaration: FirDeclaration?, val name: String, val kind: Kind) {
@@ -144,6 +146,11 @@ object LoopBackPath : EdgeLabel(label = null) {
object UncaughtExceptionPath : EdgeLabel(label = "onUncaughtException")
class LoopPath(
firLoopJump: FirLoopJump
) : EdgeLabel("\"" + (if (firLoopJump is FirBreakExpression) "break" else "continue") +
(firLoopJump.target.labeledElement.label?.let { "@${it.name}" } ?: "") + "\"")
// TODO: Label `return`ing edge with this.
class ReturnPath(
returnTargetSymbol: FirFunctionSymbol<*>
@@ -0,0 +1,24 @@
// FIR_IDENTICAL
// ISSUE: KT-51759
fun testBreak(b: Boolean, s: String?) {
while (b) {
val x: String?
try {
x = s ?: break
} finally {
}
x!!.length
}
}
fun testContinue(b: Boolean, s: String?) {
while (b) {
val x: String?
try {
x = s ?: continue
} finally {
}
x!!.length
}
}
@@ -0,0 +1,4 @@
package
public fun testBreak(/*0*/ b: kotlin.Boolean, /*1*/ s: kotlin.String?): kotlin.Unit
public fun testContinue(/*0*/ b: kotlin.Boolean, /*1*/ s: kotlin.String?): kotlin.Unit
@@ -5440,6 +5440,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinally.kt");
}
@Test
@TestMetadata("breakContinueInTryFinallyInLoop.kt")
public void testBreakContinueInTryFinallyInLoop() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakContinueInTryFinallyInLoop.kt");
}
@Test
@TestMetadata("breakInsideLocal.kt")
public void testBreakInsideLocal() throws Exception {