FIR CFG: mark variables touched by not-in-place lambdas in all scopes

This commit is contained in:
pyos
2022-06-13 15:42:20 +02:00
committed by teamcity
parent 63b0708ed5
commit 25f66b4e0e
7 changed files with 58 additions and 4 deletions
@@ -30141,6 +30141,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt"); runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt");
} }
@Test
@TestMetadata("capturedByNested.kt")
public void testCapturedByNested() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByNested.kt");
}
@Test @Test
@TestMetadata("doWhileWithMiddleBreak.kt") @TestMetadata("doWhileWithMiddleBreak.kt")
public void testDoWhileWithMiddleBreak() throws Exception { public void testDoWhileWithMiddleBreak() throws Exception {
@@ -30141,6 +30141,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt"); runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt");
} }
@Test
@TestMetadata("capturedByNested.kt")
public void testCapturedByNested() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByNested.kt");
}
@Test @Test
@TestMetadata("doWhileWithMiddleBreak.kt") @TestMetadata("doWhileWithMiddleBreak.kt")
public void testDoWhileWithMiddleBreak() throws Exception { public void testDoWhileWithMiddleBreak() throws Exception {
@@ -30141,6 +30141,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt"); runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt");
} }
@Test
@TestMetadata("capturedByNested.kt")
public void testCapturedByNested() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByNested.kt");
}
@Test @Test
@TestMetadata("doWhileWithMiddleBreak.kt") @TestMetadata("doWhileWithMiddleBreak.kt")
public void testDoWhileWithMiddleBreak() throws Exception { public void testDoWhileWithMiddleBreak() throws Exception {
@@ -112,14 +112,15 @@ internal class FirLocalVariableAssignmentAnalyzer(
} }
fun exitLocalFunction(function: FirFunction) { fun exitLocalFunction(function: FirFunction) {
val eventOccurrencesRange: EventOccurrencesRange? = (function as? FirAnonymousFunction)?.invocationKind
concurrentlyAssignedLocalVariablesStack.removeLast() concurrentlyAssignedLocalVariablesStack.removeLast()
when (eventOccurrencesRange) { when ((function as? FirAnonymousFunction)?.invocationKind) {
EventOccurrencesRange.UNKNOWN, null -> EventOccurrencesRange.UNKNOWN, null ->
// The function may be stored and then called later, so any access to the variables it touches // The function may be stored and then called later, so any access to the variables it touches
// is no longer smartcastable ever. // is no longer smartcastable ever.
assignedLocalVariablesByFunction[function.symbol]?.insideLocalFunction?.let { assignedLocalVariablesByFunction[function.symbol]?.insideLocalFunction?.let {
concurrentlyAssignedLocalVariablesStack.last() += it for (outerScope in concurrentlyAssignedLocalVariablesStack) {
outerScope += it
}
} }
else -> {} // The function is only called inline; this is handled by CFG construction by visiting the function body. else -> {} // The function is only called inline; this is handled by CFG construction by visiting the function body.
} }
@@ -358,8 +359,9 @@ internal class FirLocalVariableAssignmentAnalyzer(
class MiniCfgData(var flow: MiniFlow?) { class MiniCfgData(var flow: MiniFlow?) {
val variableDeclarations: ArrayDeque<MutableMap<Name, FirProperty>> = ArrayDeque(listOf(mutableMapOf())) val variableDeclarations: ArrayDeque<MutableMap<Name, FirProperty>> = ArrayDeque(listOf(mutableMapOf()))
val localFunctionToAssignedLocalVariables: MutableMap<FirFunctionSymbol<*>, AssignedLocalVariables> = mutableMapOf() val localFunctionToAssignedLocalVariables: MutableMap<FirFunctionSymbol<*>, AssignedLocalVariables> = mutableMapOf()
fun resolveLocalVariable(name: Name): FirProperty? { fun resolveLocalVariable(name: Name): FirProperty? {
return variableDeclarations.asReversed().firstNotNullOfOrNull { it[name] } return variableDeclarations.lastOrNull { name in it }?.getValue(name)
} }
} }
} }
@@ -0,0 +1,22 @@
// FIR_IDENTICAL
import kotlin.contracts.*
@Suppress("OPT_IN_USAGE_ERROR", "OPT_IN_USAGE_FUTURE_ERROR")
fun exactlyOnce(f: () -> Unit) {
contract {
callsInPlace(f, InvocationKind.EXACTLY_ONCE)
}
f()
}
fun test() {
var s: String? = ""
if (s != null) {
val block: () -> Unit
exactlyOnce {
block = { s = null }
}
block()
<!SMARTCAST_IMPOSSIBLE!>s<!>.length
}
}
@@ -0,0 +1,6 @@
package
@kotlin.Suppress(names = {"OPT_IN_USAGE_ERROR", "OPT_IN_USAGE_FUTURE_ERROR"}) public fun exactlyOnce(/*0*/ f: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(f, EXACTLY_ONCE)
public fun test(): kotlin.Unit
@@ -30231,6 +30231,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt"); runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByMultipleLambdas.kt");
} }
@Test
@TestMetadata("capturedByNested.kt")
public void testCapturedByNested() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/capturedByNested.kt");
}
@Test @Test
@TestMetadata("doWhileWithMiddleBreak.kt") @TestMetadata("doWhileWithMiddleBreak.kt")
public void testDoWhileWithMiddleBreak() throws Exception { public void testDoWhileWithMiddleBreak() throws Exception {