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");
|
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 {
|
||||||
|
|||||||
+6
@@ -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 {
|
||||||
|
|||||||
+6
@@ -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 {
|
||||||
|
|||||||
+6
-4
@@ -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
|
||||||
Generated
+6
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user