FIR CFA: add control flow between default parameter values

function enter -> default 1 -> default 2 -> rest of function
                   \----------^ \----------^

This probably has no effect (in non-stupid code, at least), but it makes
graph construction more architecturally correct (now value parameters'
subgraphs get attached to a node).
This commit is contained in:
pyos
2022-12-09 13:48:15 +01:00
committed by Dmitriy Novozhilov
parent 74758278d7
commit 5d4fb3ead8
9 changed files with 656 additions and 599 deletions
@@ -252,12 +252,15 @@ abstract class FirDataFlowAnalyzer(
// ----------------------------------- Value parameters (and it's defaults) -----------------------------------
fun enterValueParameter(valueParameter: FirValueParameter) {
graphBuilder.enterValueParameter(valueParameter)?.mergeIncomingFlow()
val (outerNode, innerNode) = graphBuilder.enterValueParameter(valueParameter) ?: return
outerNode.mergeIncomingFlow()
innerNode.mergeIncomingFlow()
}
fun exitValueParameter(valueParameter: FirValueParameter): ControlFlowGraph? {
val (node, graph) = graphBuilder.exitValueParameter(valueParameter) ?: return null
node.mergeIncomingFlow()
val (innerNode, outerNode, graph) = graphBuilder.exitValueParameter(valueParameter) ?: return null
innerNode.mergeIncomingFlow()
outerNode.mergeIncomingFlow()
return graph
}
@@ -542,29 +542,35 @@ class ControlFlowGraphBuilder {
// ----------------------------------- Value parameters (and it's defaults) -----------------------------------
fun enterValueParameter(valueParameter: FirValueParameter): EnterDefaultArgumentsNode? {
fun enterValueParameter(valueParameter: FirValueParameter): Pair<EnterValueParameterNode, EnterDefaultArgumentsNode>? {
if (valueParameter.defaultValue == null) return null
val outerEnterNode = createEnterValueParameterNode(valueParameter)
val graph = ControlFlowGraph(valueParameter, "default value of ${valueParameter.name}", ControlFlowGraph.Kind.DefaultArgument)
currentGraph.addSubGraph(graph)
pushGraph(graph, Mode.Body)
createExitDefaultArgumentsNode(valueParameter).also {
exitTargetsForTry.push(it)
}
return createEnterDefaultArgumentsNode(valueParameter).also {
addEdge(lastNode, it)
lastNodes.push(it)
}
val innerExitNode = createExitDefaultArgumentsNode(valueParameter)
val innerEnterNode = createEnterDefaultArgumentsNode(valueParameter)
addNewSimpleNode(outerEnterNode)
addEdge(outerEnterNode, innerEnterNode)
lastNodes.push(innerEnterNode)
exitTargetsForTry.push(innerExitNode)
return outerEnterNode to innerEnterNode
}
fun exitValueParameter(valueParameter: FirValueParameter): Pair<ExitDefaultArgumentsNode, ControlFlowGraph>? {
fun exitValueParameter(valueParameter: FirValueParameter): Triple<ExitDefaultArgumentsNode, ExitValueParameterNode, ControlFlowGraph>? {
if (valueParameter.defaultValue == null) return null
val exitNode = exitTargetsForTry.pop() as ExitDefaultArgumentsNode
popAndAddEdge(exitNode)
val graph = popGraph()
require(exitNode == graph.exitNode)
return exitNode to graph
val outerEnterNode = lastNode as EnterValueParameterNode
val outerExitNode = createExitValueParameterNode(valueParameter)
addNewSimpleNode(outerExitNode)
addEdge(exitNode, outerExitNode, propagateDeadness = false)
outerEnterNode.addSubGraph(graph)
currentGraph.addSubGraph(graph)
return Triple(exitNode, outerExitNode, graph)
}
// ----------------------------------- Block -----------------------------------
@@ -256,12 +256,18 @@ fun ControlFlowGraphBuilder.createClassExitNode(fir: FirClass): ClassExitNode =
fun ControlFlowGraphBuilder.createLocalClassExitNode(fir: FirRegularClass): LocalClassExitNode =
LocalClassExitNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createEnterValueParameterNode(fir: FirValueParameter): EnterValueParameterNode =
EnterValueParameterNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createEnterDefaultArgumentsNode(fir: FirValueParameter): EnterDefaultArgumentsNode =
EnterDefaultArgumentsNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createExitDefaultArgumentsNode(fir: FirValueParameter): ExitDefaultArgumentsNode =
ExitDefaultArgumentsNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createExitValueParameterNode(fir: FirValueParameter): ExitValueParameterNode =
ExitValueParameterNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createComparisonExpressionNode(fir: FirComparisonExpression): ComparisonExpressionNode =
ComparisonExpressionNode(currentGraph, fir, levelCounter, createId())