FIR CFG: mark variables touched by not-in-place lambdas in all scopes
This commit is contained in:
+6
@@ -30141,6 +30141,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
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
|
||||
@TestMetadata("doWhileWithMiddleBreak.kt")
|
||||
public void testDoWhileWithMiddleBreak() throws Exception {
|
||||
|
||||
+6
@@ -30141,6 +30141,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
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
|
||||
@TestMetadata("doWhileWithMiddleBreak.kt")
|
||||
public void testDoWhileWithMiddleBreak() throws Exception {
|
||||
|
||||
+6
@@ -30141,6 +30141,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
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
|
||||
@TestMetadata("doWhileWithMiddleBreak.kt")
|
||||
public void testDoWhileWithMiddleBreak() throws Exception {
|
||||
|
||||
+6
-4
@@ -112,14 +112,15 @@ internal class FirLocalVariableAssignmentAnalyzer(
|
||||
}
|
||||
|
||||
fun exitLocalFunction(function: FirFunction) {
|
||||
val eventOccurrencesRange: EventOccurrencesRange? = (function as? FirAnonymousFunction)?.invocationKind
|
||||
concurrentlyAssignedLocalVariablesStack.removeLast()
|
||||
when (eventOccurrencesRange) {
|
||||
when ((function as? FirAnonymousFunction)?.invocationKind) {
|
||||
EventOccurrencesRange.UNKNOWN, null ->
|
||||
// The function may be stored and then called later, so any access to the variables it touches
|
||||
// is no longer smartcastable ever.
|
||||
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.
|
||||
}
|
||||
@@ -358,8 +359,9 @@ internal class FirLocalVariableAssignmentAnalyzer(
|
||||
class MiniCfgData(var flow: MiniFlow?) {
|
||||
val variableDeclarations: ArrayDeque<MutableMap<Name, FirProperty>> = ArrayDeque(listOf(mutableMapOf()))
|
||||
val localFunctionToAssignedLocalVariables: MutableMap<FirFunctionSymbol<*>, AssignedLocalVariables> = mutableMapOf()
|
||||
|
||||
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
|
||||
Generated
+6
@@ -30231,6 +30231,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
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
|
||||
@TestMetadata("doWhileWithMiddleBreak.kt")
|
||||
public void testDoWhileWithMiddleBreak() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user