diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index d151b828065..2689e1fddf1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -637,7 +637,9 @@ abstract class FirDataFlowAnalyzer( fun enterTryExpression(tryExpression: FirTryExpression) { val (tryExpressionEnterNode, tryMainBlockEnterNode) = graphBuilder.enterTryExpression(tryExpression) tryExpressionEnterNode.mergeIncomingFlow() - tryMainBlockEnterNode.mergeIncomingFlow() + // NB: fork to isolate effects inside the try main block + // Otherwise, changes in the try main block could affect the try expression enter node as well as its previous nodes. + tryMainBlockEnterNode.mergeIncomingFlow(shouldForkFlow = true) } fun exitTryMainBlock(tryExpression: FirTryExpression) { @@ -645,7 +647,9 @@ abstract class FirDataFlowAnalyzer( } fun enterCatchClause(catch: FirCatch) { - graphBuilder.enterCatchClause(catch).mergeIncomingFlow(updateReceivers = true) + // NB: fork to isolate effects inside the catch clause + // Otherwise, changes in the catch clause could affect the previous node: try main block. + graphBuilder.enterCatchClause(catch).mergeIncomingFlow(updateReceivers = true, shouldForkFlow = true) } fun exitCatchClause(catch: FirCatch) { @@ -653,19 +657,20 @@ abstract class FirDataFlowAnalyzer( } fun enterFinallyBlock() { - // TODO - graphBuilder.enterFinallyBlock().mergeIncomingFlow() + // NB: fork to isolate effects inside the finally block + // Otherwise, changes in the finally block could affect the previous nodes: try main block and catch clauses. + graphBuilder.enterFinallyBlock().mergeIncomingFlow(shouldForkFlow = true) } fun exitFinallyBlock(tryExpression: FirTryExpression) { - // TODO graphBuilder.exitFinallyBlock(tryExpression).mergeIncomingFlow() } fun exitTryExpression(callCompleted: Boolean) { - // TODO val (tryExpressionExitNode, unionNode) = graphBuilder.exitTryExpression(callCompleted) - tryExpressionExitNode.mergeIncomingFlow() + // NB: fork to prevent effects after the try expression from being flown into the try expression + // Otherwise, changes in any following nodes could affect the previous nodes, including try main block and finally block if any. + tryExpressionExitNode.mergeIncomingFlow(shouldForkFlow = true) unionNode?.let { unionFlowFromArguments(it) } } diff --git a/compiler/testData/codegen/box/regressions/kt18779.kt b/compiler/testData/codegen/box/regressions/kt18779.kt index d72aec3b877..986fc495998 100644 --- a/compiler/testData/codegen/box/regressions/kt18779.kt +++ b/compiler/testData/codegen/box/regressions/kt18779.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR - sealed class Result { class Failure(val exception: Exception) : Result() class Success(val message: String) : Result() diff --git a/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/TryFinally.fir.kt b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/TryFinally.fir.kt index 7bf4b2deb91..91107e9017d 100644 --- a/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/TryFinally.fir.kt +++ b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/TryFinally.fir.kt @@ -14,7 +14,7 @@ fun tryCatchFinally(x: Int?) { } catch (e: Exception) { x!! } finally { - checkSubtype(x) + checkSubtype(x) x!! } checkSubtype(x) diff --git a/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithCatch.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithCatch.fir.kt index 76c04d0251a..225108b566a 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithCatch.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithCatch.fir.kt @@ -2,11 +2,11 @@ fun castInTry(s: Any) { try { s as String // Potential cast exception } catch (e: Exception) { - s.length // shouldn't be resolved + s.length // shouldn't be resolved } finally { - s.length // shouldn't be resolved + s.length // shouldn't be resolved } - s.length // shouldn't be resolved + s.length // shouldn't be resolved } fun castInTryAndCatch(s: Any) { @@ -15,9 +15,9 @@ fun castInTryAndCatch(s: Any) { } catch (e: Exception) { s as String // Potential cast exception } finally { - s.length // shouldn't be resolved + s.length // shouldn't be resolved } - s.length // should be smartcast + s.length // should be smartcast } fun castAtAll(s: Any) { diff --git a/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithoutCatch.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithoutCatch.fir.kt index 44c1618c7ac..01937ff9cb1 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithoutCatch.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/castchecks/castInTryWithoutCatch.fir.kt @@ -2,9 +2,9 @@ fun castInTry(s: Any) { try { s as String // Potential cast exception } finally { - s.length // Shouldn't be resolved + s.length // Shouldn't be resolved } - s.length // Shouldn't be resolved + s.length // Shouldn't be resolved } fun castInTryAndFinally(s: Any) { diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.fir.kt index 4163683d0d1..0735df90d8d 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.fir.kt @@ -37,7 +37,7 @@ fun test3() { catch (e: B) { return } - a.hashCode() // a is nullable here + a.hashCode() // a is nullable here } fun test4() { var a: Int? = null diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/setNotNullInTry.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/setNotNullInTry.fir.kt index e380e336ffe..b80a9706116 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/setNotNullInTry.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/setNotNullInTry.fir.kt @@ -10,5 +10,5 @@ fun foo() { } catch (ex: Exception) {} bar(s) if (s != null) { } - s.hashCode() + s.hashCode() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/catchExceptionSpilling.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/catchExceptionSpilling.fir.kt index 950164c591d..f922b23dfb2 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/catchExceptionSpilling.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/catchExceptionSpilling.fir.kt @@ -17,5 +17,5 @@ fun testWithCatch(x: Any?) { x.length } catch (e: java.lang.IllegalArgumentException) { } - x.length + x.length } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt index 1253490875b..219ab26035a 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt @@ -45,7 +45,7 @@ fun testTryCatch(x: Any?) { } catch (e: kotlin.IllegalArgumentException) { } - x.length + x.length } fun testUncertainFlow(x: Any?) {