From 0bd6ea764e78280e18d4eab3080146b837ac12a6 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 21 Dec 2023 13:14:28 +0200 Subject: [PATCH] [FIR] Consider only normal execution path during contracts verification There might be several pathes out from the function from CFG point of view: - normal execution path - exceptional execution path For verification of callsInPlace contract it's needed to check only the normal path ^KT-63414 Fixed --- .../fromSource/good/callsInPlace/tryFinally.kt | 6 +++--- .../fir/analysis/cfa/FirCallsEffectAnalyzer.kt | 12 +++--------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/tryFinally.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/tryFinally.kt index 3a4eabdaf43..5f9d37dafee 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/tryFinally.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/contracts/fromSource/good/callsInPlace/tryFinally.kt @@ -13,7 +13,7 @@ inline fun test_1(f: () -> Unit) { @OptIn(ExperimentalContracts::class) inline fun test_2(f: () -> Int): Int { - contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) } // should be ok + contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) } // should be ok try { return f() } finally { @@ -54,7 +54,7 @@ inline fun test_5(f: () -> Unit) { @OptIn(ExperimentalContracts::class) inline fun test_6(f: () -> Int): Int { - contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) } // should be ok + contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) } // should be ok try { return f() } catch (_: Exception) { @@ -78,7 +78,7 @@ inline fun test_7(f: () -> Unit) { @OptIn(ExperimentalContracts::class) inline fun test_8(f: () -> Int): Int { - contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) } // should be error + contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) } // should be error try { return f() } catch (_: Exception) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt index f67b0da8291..8879700d7db 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt @@ -87,12 +87,8 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() { graph.exitNode.previousCfgNodes.forEach { node -> val requiredRange = effectDeclaration.kind val pathAwareInfo = invocationData.getValue(node) - for (info in pathAwareInfo.values) { - if (investigate(info, symbol, requiredRange, function, reporter, context)) { - // To avoid duplicate reports, stop investigating remaining paths once reported. - break - } - } + val info = pathAwareInfo[NormalPath] ?: return@forEach + investigate(info, symbol, requiredRange, function, reporter, context) } } } @@ -104,7 +100,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() { function: FirContractDescriptionOwner, reporter: DiagnosticReporter, context: CheckerContext - ): Boolean { + ) { val foundRange = info[symbol] ?: EventOccurrencesRange.ZERO if (foundRange !in requiredRange) { reporter.reportOn( @@ -115,9 +111,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() { foundRange, context ) - return true } - return false } private class IllegalScopeContext(