[FIR] Pass flow to local functions
This commit is contained in:
+7
-1
@@ -64,7 +64,13 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
||||
// ----------------------------------- Named function -----------------------------------
|
||||
|
||||
fun enterFunction(function: FirFunction<*>) {
|
||||
graphBuilder.enterFunction(function).mergeIncomingFlow()
|
||||
val (functionEnterNode, previousNode) = graphBuilder.enterFunction(function)
|
||||
if (previousNode == null) {
|
||||
functionEnterNode.mergeIncomingFlow()
|
||||
} else {
|
||||
assert(functionEnterNode.previousNodes.isEmpty())
|
||||
functionEnterNode.flow = logicSystem.forkFlow(previousNode.flow)
|
||||
}
|
||||
}
|
||||
|
||||
fun exitFunction(function: FirFunction<*>): ControlFlowGraph? {
|
||||
|
||||
+5
-1
@@ -12,10 +12,14 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
|
||||
class ControlFlowGraph(val name: String) {
|
||||
class ControlFlowGraph(val name: String, val kind: Kind) {
|
||||
val nodes = mutableListOf<CFGNode<*>>()
|
||||
lateinit var enterNode: CFGNode<*>
|
||||
lateinit var exitNode: CFGNode<*>
|
||||
|
||||
enum class Kind {
|
||||
Function, ClassInitializer, PropertyInitializer, TopLevel
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level: Int) {
|
||||
|
||||
+19
-7
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.resultType
|
||||
import org.jetbrains.kotlin.fir.types.isNothing
|
||||
|
||||
class ControlFlowGraphBuilder {
|
||||
private val graphs: Stack<ControlFlowGraph> = stackOf(ControlFlowGraph("<DUMP_GRAPH_FOR_ENUMS>"))
|
||||
private val graphs: Stack<ControlFlowGraph> = stackOf(ControlFlowGraph("<DUMP_GRAPH_FOR_ENUMS>", ControlFlowGraph.Kind.TopLevel))
|
||||
val graph: ControlFlowGraph get() = graphs.top()
|
||||
|
||||
private val lexicalScopes: Stack<Stack<CFGNode<*>>> = stackOf(stackOf())
|
||||
@@ -50,7 +50,11 @@ class ControlFlowGraphBuilder {
|
||||
|
||||
// ----------------------------------- Named function -----------------------------------
|
||||
|
||||
fun enterFunction(function: FirFunction<*>): FunctionEnterNode {
|
||||
/*
|
||||
* Second argument of pair is not null only if function is local and it is a
|
||||
* previous node before function declaration
|
||||
*/
|
||||
fun enterFunction(function: FirFunction<*>): Pair<FunctionEnterNode, CFGNode<*>?> {
|
||||
val name = when (function) {
|
||||
is FirNamedFunction -> function.name.asString()
|
||||
is FirAbstractPropertyAccessor -> if (function.isGetter) "<getter>" else "<setter>"
|
||||
@@ -60,9 +64,17 @@ class ControlFlowGraphBuilder {
|
||||
}
|
||||
val invocationKind = function.invocationKind
|
||||
val isInplace = invocationKind.isInplace()
|
||||
if (!isInplace) {
|
||||
graphs.push(ControlFlowGraph(name))
|
||||
|
||||
val previousNode = if (!isInplace && graphs.topOrNull()?.let { it.kind != ControlFlowGraph.Kind.TopLevel } == true) {
|
||||
lastNodes.top()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
if (!isInplace) {
|
||||
graphs.push(ControlFlowGraph(name, ControlFlowGraph.Kind.Function))
|
||||
}
|
||||
|
||||
val enterNode = createFunctionEnterNode(function, isInplace).also {
|
||||
if (isInplace) {
|
||||
addNewSimpleNode(it)
|
||||
@@ -88,7 +100,7 @@ class ControlFlowGraphBuilder {
|
||||
exitNodes.push(exitNode)
|
||||
}
|
||||
levelCounter++
|
||||
return enterNode
|
||||
return enterNode to previousNode
|
||||
}
|
||||
|
||||
fun exitFunction(function: FirFunction<*>): Pair<FunctionExitNode, ControlFlowGraph?> {
|
||||
@@ -127,7 +139,7 @@ class ControlFlowGraphBuilder {
|
||||
// ----------------------------------- Property -----------------------------------
|
||||
|
||||
fun enterProperty(property: FirProperty): PropertyInitializerEnterNode {
|
||||
graphs.push(ControlFlowGraph("val ${property.name}"))
|
||||
graphs.push(ControlFlowGraph("val ${property.name}", ControlFlowGraph.Kind.PropertyInitializer))
|
||||
val enterNode = createPropertyInitializerEnterNode(property)
|
||||
val exitNode = createPropertyInitializerExitNode(property)
|
||||
topLevelVariableInitializerExitNodes.push(exitNode)
|
||||
@@ -522,7 +534,7 @@ class ControlFlowGraphBuilder {
|
||||
// ----------------------------------- Block -----------------------------------
|
||||
|
||||
fun enterInitBlock(initBlock: FirAnonymousInitializer): InitBlockEnterNode {
|
||||
graphs.push(ControlFlowGraph("init block"))
|
||||
graphs.push(ControlFlowGraph("init block", ControlFlowGraph.Kind.ClassInitializer))
|
||||
val enterNode = createInitBlockEnterNode(initBlock).also {
|
||||
lexicalScopes.push(stackOf(it))
|
||||
}
|
||||
|
||||
+2
-2
@@ -112,7 +112,7 @@ digraph lambdas_kt {
|
||||
color=blue
|
||||
33 [label="Enter block"];
|
||||
34 [label="Access variable R|<local>/x|"];
|
||||
35 [label="Function call: R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()"];
|
||||
35 [label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
|
||||
36 [label="Exit block"];
|
||||
}
|
||||
37 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||
@@ -156,7 +156,7 @@ digraph lambdas_kt {
|
||||
subgraph cluster_19 {
|
||||
color=blue
|
||||
52 [label="Enter block"];
|
||||
53 [label="Variable declaration: lval lambda: R|kotlin/Function0<class error: Ambiguity: inc, [kotlin/inc, kotlin/inc]>|"];
|
||||
53 [label="Variable declaration: lval lambda: R|kotlin/Function0<kotlin/Int>|"];
|
||||
54 [label="Exit block"];
|
||||
}
|
||||
55 [label="Exit when branch result"];
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ FILE: lambdas.kt
|
||||
public final fun test_2(x: R|kotlin/Any?|): R|kotlin/Unit| {
|
||||
when () {
|
||||
(R|<local>/x| is R|kotlin/Int|) -> {
|
||||
lval lambda: R|kotlin/Function0<class error: Ambiguity: inc, [kotlin/inc, kotlin/inc]>| = fun <anonymous>(): <ERROR TYPE REF: Ambiguity: inc, [kotlin/inc, kotlin/inc]> {
|
||||
R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()
|
||||
lval lambda: R|kotlin/Function0<kotlin/Int>| = fun <anonymous>(): R|kotlin/Int| {
|
||||
R|<local>/x|.R|kotlin/Int.inc|()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user