diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt index 1d763c56039..d17ad4cfacf 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt @@ -333,6 +333,9 @@ internal class FirLocalVariableAssignmentAnalyzer { override fun visitLoop(loop: FirLoop, data: MiniCfgData) { val entry = data.flow val assignedInside = visitElementWithLexicalScope(loop, data) + // Now that the inner variables have been discarded, the rest can be propagated to prevent smartcasts + // in declarations that came before this loop. + entry.recordAssignments(assignedInside) // All forks in the loop should have the same set of variables assigned later, equal to the set // at the start of the loop. data.flow.recordAssignments(assignedInside) diff --git a/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.fir.kt index 21dc9e562d4..c1d2ce2459e 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.fir.kt @@ -468,7 +468,7 @@ fun test48() { var x: Any = materialize() runWithoutContract { while (x is String) { - x.length + x.length x = 10 } } @@ -536,7 +536,7 @@ fun test55() { runWithoutContract { for (i in 1..3) { require(x is String) - x.length + x.length x = 10 } } @@ -619,4 +619,37 @@ fun test63() { x?.length ?: -1 x = null } -} \ No newline at end of file +} + +fun test64() { + var x: Any = materialize() + require(x is String) + runWithoutContract { + x.length + } + for (i in 1..3) { + x = 10 + } +} + +fun test65() { + var x: Any = materialize() + require(x is String) + atLeastOnce { + x.length + } + for (i in 1..3) { + x = 10 + } +} + +fun test66() { + var x: Any = materialize() + require(x is String) + exactlyOnce { + x.length + } + for (i in 1..3) { + x = 10 + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.kt b/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.kt index 7a0c77f74a0..06381824edb 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/lambdasWithContracts/lambdaWithCallInPlace.kt @@ -620,3 +620,36 @@ fun test63() { x = null } } + +fun test64() { + var x: Any = materialize() + require(x is String) + runWithoutContract { + x.length + } + for (i in 1..3) { + x = 10 + } +} + +fun test65() { + var x: Any = materialize() + require(x is String) + atLeastOnce { + x.length + } + for (i in 1..3) { + x = 10 + } +} + +fun test66() { + var x: Any = materialize() + require(x is String) + exactlyOnce { + x.length + } + for (i in 1..3) { + x = 10 + } +}