[FIR] Fix building CFG and resolving when expression without branches
This commit is contained in:
+13
-8
@@ -353,15 +353,20 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
||||
fun exitWhenExpression(whenExpression: FirWhenExpression) {
|
||||
val (whenExitNode, syntheticElseNode) = graphBuilder.exitWhenExpression(whenExpression)
|
||||
if (syntheticElseNode != null) {
|
||||
val previousConditionExitNode = syntheticElseNode.previousNodes.single() as WhenBranchConditionExitNode
|
||||
syntheticElseNode.mergeIncomingFlow()
|
||||
syntheticElseNode.flow = logicSystem.approveFactsInsideFlow(
|
||||
variablesForWhenConditions.remove(previousConditionExitNode)!!,
|
||||
EqFalse,
|
||||
syntheticElseNode.flow,
|
||||
shouldForkFlow = true,
|
||||
shouldRemoveSynthetics = true
|
||||
)
|
||||
val previousConditionExitNode = syntheticElseNode.previousNodes.single() as? WhenBranchConditionExitNode
|
||||
// previous node for syntheticElseNode can be not WhenBranchConditionExitNode in case of `when` without any branches
|
||||
// in that case there will be when enter or subject access node
|
||||
if (previousConditionExitNode != null) {
|
||||
syntheticElseNode.flow = logicSystem.approveFactsInsideFlow(
|
||||
variablesForWhenConditions.remove(previousConditionExitNode)!!,
|
||||
EqFalse,
|
||||
syntheticElseNode.flow,
|
||||
shouldForkFlow = true,
|
||||
shouldRemoveSynthetics = true
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
val previousFlows = whenExitNode.alivePreviousNodes.map { it.flow }
|
||||
val flow = logicSystem.joinFlow(previousFlows)
|
||||
|
||||
-1
@@ -225,7 +225,6 @@ class ControlFlowGraphBuilder {
|
||||
// exit from last condition node still on stack
|
||||
// we should remove it
|
||||
val lastWhenConditionExit = lastNodes.pop()
|
||||
assert(lastWhenConditionExit is WhenBranchConditionExitNode)
|
||||
val syntheticElseBranchNode = if (!whenExpression.isExhaustive) {
|
||||
createWhenSyntheticElseBranchNode(whenExpression).apply {
|
||||
addEdge(lastWhenConditionExit, this)
|
||||
|
||||
+16
-11
@@ -532,20 +532,25 @@ open class FirBodyResolveTransformer(
|
||||
}
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var whenExpression = whenExpression.transformSubject(this, noExpectedType)
|
||||
if (whenExpression.isOneBranch()) {
|
||||
whenExpression = whenExpression.transformBranches(this, noExpectedType)
|
||||
whenExpression.resultType = whenExpression.branches.first().result.resultType
|
||||
} else {
|
||||
whenExpression = whenExpression.transformBranches(this, null)
|
||||
|
||||
whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression) ?: run {
|
||||
dataFlowAnalyzer.exitWhenExpression(whenExpression)
|
||||
whenExpression.resultType = FirErrorTypeRefImpl(null, "")
|
||||
return@with whenExpression.compose()
|
||||
when {
|
||||
whenExpression.branches.isEmpty() -> {}
|
||||
whenExpression.isOneBranch() -> {
|
||||
whenExpression = whenExpression.transformBranches(this, noExpectedType)
|
||||
whenExpression.resultType = whenExpression.branches.first().result.resultType
|
||||
}
|
||||
else -> {
|
||||
whenExpression = whenExpression.transformBranches(this, null)
|
||||
|
||||
val expectedTypeRef = data as FirTypeRef?
|
||||
whenExpression = callCompleter.completeCall(whenExpression, expectedTypeRef)
|
||||
whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression) ?: run {
|
||||
dataFlowAnalyzer.exitWhenExpression(whenExpression)
|
||||
whenExpression.resultType = FirErrorTypeRefImpl(null, "")
|
||||
return@with whenExpression.compose()
|
||||
}
|
||||
|
||||
val expectedTypeRef = data as FirTypeRef?
|
||||
whenExpression = callCompleter.completeCall(whenExpression, expectedTypeRef)
|
||||
}
|
||||
}
|
||||
whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null)
|
||||
dataFlowAnalyzer.exitWhenExpression(whenExpression)
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
digraph emptyWhen_kt {
|
||||
graph [splines=ortho nodesep=3]
|
||||
node [shape=box penwidth=2]
|
||||
edge [penwidth=2]
|
||||
|
||||
subgraph cluster_0 {
|
||||
color=red
|
||||
0 [label="Enter function test_1" style="filled" fillcolor=red];
|
||||
subgraph cluster_1 {
|
||||
color=blue
|
||||
1 [label="Enter block"];
|
||||
subgraph cluster_2 {
|
||||
color=blue
|
||||
2 [label="Enter when"];
|
||||
3 [label="Synthetic else branch"];
|
||||
4 [label="Exit when"];
|
||||
}
|
||||
5 [label="Exit block"];
|
||||
}
|
||||
6 [label="Exit function test_1" style="filled" fillcolor=red];
|
||||
}
|
||||
|
||||
0 -> {1};
|
||||
1 -> {2};
|
||||
2 -> {3};
|
||||
3 -> {4};
|
||||
4 -> {5};
|
||||
5 -> {6};
|
||||
|
||||
subgraph cluster_3 {
|
||||
color=red
|
||||
7 [label="Enter function test_2" style="filled" fillcolor=red];
|
||||
subgraph cluster_4 {
|
||||
color=blue
|
||||
8 [label="Enter block"];
|
||||
subgraph cluster_5 {
|
||||
color=blue
|
||||
9 [label="Enter when"];
|
||||
10 [label="Access variable R|<local>/x|"];
|
||||
11 [label="Synthetic else branch"];
|
||||
12 [label="Exit when"];
|
||||
}
|
||||
13 [label="Exit block"];
|
||||
}
|
||||
14 [label="Exit function test_2" style="filled" fillcolor=red];
|
||||
}
|
||||
|
||||
7 -> {8};
|
||||
8 -> {9};
|
||||
9 -> {10};
|
||||
10 -> {11};
|
||||
11 -> {12};
|
||||
12 -> {13};
|
||||
13 -> {14};
|
||||
|
||||
subgraph cluster_6 {
|
||||
color=red
|
||||
15 [label="Enter function test_3" style="filled" fillcolor=red];
|
||||
subgraph cluster_7 {
|
||||
color=blue
|
||||
16 [label="Enter block"];
|
||||
subgraph cluster_8 {
|
||||
color=blue
|
||||
17 [label="Enter when"];
|
||||
18 [label="Access variable R|<local>/x|"];
|
||||
19 [label="Variable declaration: lval y: R|kotlin/Int|"];
|
||||
20 [label="Synthetic else branch"];
|
||||
21 [label="Exit when"];
|
||||
}
|
||||
22 [label="Exit block"];
|
||||
}
|
||||
23 [label="Exit function test_3" style="filled" fillcolor=red];
|
||||
}
|
||||
|
||||
15 -> {16};
|
||||
16 -> {17};
|
||||
17 -> {18};
|
||||
18 -> {19};
|
||||
19 -> {20};
|
||||
20 -> {21};
|
||||
21 -> {22};
|
||||
22 -> {23};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fun test_1() {
|
||||
when {}
|
||||
}
|
||||
|
||||
fun test_2(x: Int) {
|
||||
when (x) {}
|
||||
}
|
||||
|
||||
fun test_3(x: Int) {
|
||||
when (val y = x) {}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
FILE: emptyWhen.kt
|
||||
public final fun test_1(): R|kotlin/Unit| {
|
||||
when () {
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_2(x: R|kotlin/Int|): R|kotlin/Unit| {
|
||||
when (R|<local>/x|) {
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_3(x: R|kotlin/Int|): R|kotlin/Unit| {
|
||||
when (lval y: R|kotlin/Int| = R|<local>/x|) {
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -46,6 +46,11 @@ public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest {
|
||||
runTest("compiler/fir/resolve/testData/resolve/cfg/complex.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("emptyWhen.kt")
|
||||
public void testEmptyWhen() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/cfg/emptyWhen.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("initBlock.kt")
|
||||
public void testInitBlock() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/cfg/initBlock.kt");
|
||||
|
||||
Reference in New Issue
Block a user