[FIR] Pass flow to local functions
This commit is contained in:
+7
-1
@@ -64,7 +64,13 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC
|
|||||||
// ----------------------------------- Named function -----------------------------------
|
// ----------------------------------- Named function -----------------------------------
|
||||||
|
|
||||||
fun enterFunction(function: FirFunction<*>) {
|
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? {
|
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.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
|
|
||||||
class ControlFlowGraph(val name: String) {
|
class ControlFlowGraph(val name: String, val kind: Kind) {
|
||||||
val nodes = mutableListOf<CFGNode<*>>()
|
val nodes = mutableListOf<CFGNode<*>>()
|
||||||
lateinit var enterNode: CFGNode<*>
|
lateinit var enterNode: CFGNode<*>
|
||||||
lateinit var exitNode: CFGNode<*>
|
lateinit var exitNode: CFGNode<*>
|
||||||
|
|
||||||
|
enum class Kind {
|
||||||
|
Function, ClassInitializer, PropertyInitializer, TopLevel
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level: Int) {
|
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
|
import org.jetbrains.kotlin.fir.types.isNothing
|
||||||
|
|
||||||
class ControlFlowGraphBuilder {
|
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()
|
val graph: ControlFlowGraph get() = graphs.top()
|
||||||
|
|
||||||
private val lexicalScopes: Stack<Stack<CFGNode<*>>> = stackOf(stackOf())
|
private val lexicalScopes: Stack<Stack<CFGNode<*>>> = stackOf(stackOf())
|
||||||
@@ -50,7 +50,11 @@ class ControlFlowGraphBuilder {
|
|||||||
|
|
||||||
// ----------------------------------- Named function -----------------------------------
|
// ----------------------------------- 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) {
|
val name = when (function) {
|
||||||
is FirNamedFunction -> function.name.asString()
|
is FirNamedFunction -> function.name.asString()
|
||||||
is FirAbstractPropertyAccessor -> if (function.isGetter) "<getter>" else "<setter>"
|
is FirAbstractPropertyAccessor -> if (function.isGetter) "<getter>" else "<setter>"
|
||||||
@@ -60,9 +64,17 @@ class ControlFlowGraphBuilder {
|
|||||||
}
|
}
|
||||||
val invocationKind = function.invocationKind
|
val invocationKind = function.invocationKind
|
||||||
val isInplace = invocationKind.isInplace()
|
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 {
|
val enterNode = createFunctionEnterNode(function, isInplace).also {
|
||||||
if (isInplace) {
|
if (isInplace) {
|
||||||
addNewSimpleNode(it)
|
addNewSimpleNode(it)
|
||||||
@@ -88,7 +100,7 @@ class ControlFlowGraphBuilder {
|
|||||||
exitNodes.push(exitNode)
|
exitNodes.push(exitNode)
|
||||||
}
|
}
|
||||||
levelCounter++
|
levelCounter++
|
||||||
return enterNode
|
return enterNode to previousNode
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitFunction(function: FirFunction<*>): Pair<FunctionExitNode, ControlFlowGraph?> {
|
fun exitFunction(function: FirFunction<*>): Pair<FunctionExitNode, ControlFlowGraph?> {
|
||||||
@@ -127,7 +139,7 @@ class ControlFlowGraphBuilder {
|
|||||||
// ----------------------------------- Property -----------------------------------
|
// ----------------------------------- Property -----------------------------------
|
||||||
|
|
||||||
fun enterProperty(property: FirProperty): PropertyInitializerEnterNode {
|
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 enterNode = createPropertyInitializerEnterNode(property)
|
||||||
val exitNode = createPropertyInitializerExitNode(property)
|
val exitNode = createPropertyInitializerExitNode(property)
|
||||||
topLevelVariableInitializerExitNodes.push(exitNode)
|
topLevelVariableInitializerExitNodes.push(exitNode)
|
||||||
@@ -522,7 +534,7 @@ class ControlFlowGraphBuilder {
|
|||||||
// ----------------------------------- Block -----------------------------------
|
// ----------------------------------- Block -----------------------------------
|
||||||
|
|
||||||
fun enterInitBlock(initBlock: FirAnonymousInitializer): InitBlockEnterNode {
|
fun enterInitBlock(initBlock: FirAnonymousInitializer): InitBlockEnterNode {
|
||||||
graphs.push(ControlFlowGraph("init block"))
|
graphs.push(ControlFlowGraph("init block", ControlFlowGraph.Kind.ClassInitializer))
|
||||||
val enterNode = createInitBlockEnterNode(initBlock).also {
|
val enterNode = createInitBlockEnterNode(initBlock).also {
|
||||||
lexicalScopes.push(stackOf(it))
|
lexicalScopes.push(stackOf(it))
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -112,7 +112,7 @@ digraph lambdas_kt {
|
|||||||
color=blue
|
color=blue
|
||||||
33 [label="Enter block"];
|
33 [label="Enter block"];
|
||||||
34 [label="Access variable R|<local>/x|"];
|
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"];
|
36 [label="Exit block"];
|
||||||
}
|
}
|
||||||
37 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
37 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||||
@@ -156,7 +156,7 @@ digraph lambdas_kt {
|
|||||||
subgraph cluster_19 {
|
subgraph cluster_19 {
|
||||||
color=blue
|
color=blue
|
||||||
52 [label="Enter block"];
|
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"];
|
54 [label="Exit block"];
|
||||||
}
|
}
|
||||||
55 [label="Exit when branch result"];
|
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| {
|
public final fun test_2(x: R|kotlin/Any?|): R|kotlin/Unit| {
|
||||||
when () {
|
when () {
|
||||||
(R|<local>/x| is R|kotlin/Int|) -> {
|
(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]> {
|
lval lambda: R|kotlin/Function0<kotlin/Int>| = fun <anonymous>(): R|kotlin/Int| {
|
||||||
R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()
|
R|<local>/x|.R|kotlin/Int.inc|()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user