diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index d54481abce0..dfac1c5ba88 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -30,6 +30,11 @@ class ControlFlowGraphBuilder { val currentGraph: ControlFlowGraph get() = graphs.top() + val levelCounter: Int + // `try` expressions aren't subgraphs, but they increase the level in order to tell which nodes + // are inside the try and which aren't + get() = graphs.size + tryExitNodes.size - 1 /* top-level graph */ + private val lastNodes: Stack> = stackOf() val lastNode: CFGNode<*> get() = lastNodes.top() @@ -37,8 +42,6 @@ class ControlFlowGraphBuilder { val lastNodeOrNull: CFGNode<*>? get() = lastNodes.topOrNull() - var levelCounter: Int = 0 - // ----------------------------------- Node caches ----------------------------------- private val exitTargetsForReturn: SymbolBasedNodeStorage = SymbolBasedNodeStorage() @@ -114,7 +117,6 @@ class ControlFlowGraphBuilder { nodes: (E) -> Pair ): Pair where EnterNode : CFGNode, EnterNode : GraphEnterNodeMarker, ExitNode : CFGNode, ExitNode : GraphExitNodeMarker { graphs.push(ControlFlowGraph(fir as? FirDeclaration, name, kind)) - levelCounter++ return nodes(fir).also { (enterNode, exitNode) -> currentGraph.enterNode = enterNode currentGraph.exitNode = exitNode @@ -123,7 +125,6 @@ class ControlFlowGraphBuilder { } private fun popGraph(): ControlFlowGraph { - levelCounter-- return graphs.pop().also { it.complete() } } @@ -385,7 +386,6 @@ class ControlFlowGraphBuilder { fun enterClass(klass: FirClass, buildGraph: Boolean): Pair?, ClassEnterNode>? { if (!buildGraph || klass !is FirControlFlowGraphOwner) { graphs.push(ControlFlowGraph(null, "", ControlFlowGraph.Kind.ClassInitializer)) - levelCounter++ return null } @@ -432,7 +432,6 @@ class ControlFlowGraphBuilder { fun exitClass(): Pair? { if (currentGraph.declaration == null) { - levelCounter-- graphs.pop().also { assert(it.kind == ControlFlowGraph.Kind.ClassInitializer) } return null } @@ -704,7 +703,6 @@ class ControlFlowGraphBuilder { addNewSimpleNode(node) whenExitNodes.push(createWhenExitNode(whenExpression)) notCompletedFunctionCalls.push(mutableListOf()) - levelCounter++ splitDataFlowForPostponedLambdas() return node } @@ -714,28 +712,20 @@ class ControlFlowGraphBuilder { } fun enterWhenBranchCondition(whenBranch: FirWhenBranch): WhenBranchConditionEnterNode { - return createWhenBranchConditionEnterNode(whenBranch).also { addNewSimpleNode(it) }.also { levelCounter++ } + return createWhenBranchConditionEnterNode(whenBranch).also { addNewSimpleNode(it) } } fun exitWhenBranchCondition(whenBranch: FirWhenBranch): Pair { - levelCounter-- - val conditionExitNode = createWhenBranchConditionExitNode(whenBranch).also { - addNewSimpleNode(it) - }.also { levelCounter++ } - val branchEnterNode = createWhenBranchResultEnterNode(whenBranch).also { - lastNodes.push(it) - addEdge(conditionExitNode, it) - } + val conditionExitNode = createWhenBranchConditionExitNode(whenBranch).also { addNewSimpleNode(it) } + lastNodes.push(conditionExitNode) // keep one for next condition entry + val branchEnterNode = createWhenBranchResultEnterNode(whenBranch).also { addNewSimpleNode(it) } return conditionExitNode to branchEnterNode } fun exitWhenBranchResult(whenBranch: FirWhenBranch): WhenBranchResultExitNode { - levelCounter-- val node = createWhenBranchResultExitNode(whenBranch) popAndAddEdge(node) - val whenExitNode = whenExitNodes.top() - addEdge(node, whenExitNode, propagateDeadness = false) - levelCounter++ + addEdge(node, whenExitNodes.top(), propagateDeadness = false) return node } @@ -743,7 +733,6 @@ class ControlFlowGraphBuilder { whenExpression: FirWhenExpression, callCompleted: Boolean ): Pair { - levelCounter -= whenExpression.branches.size val whenExitNode = whenExitNodes.pop() // exit from last condition node still on stack // we should remove it @@ -758,40 +747,29 @@ class ControlFlowGraphBuilder { mergeDataFlowFromPostponedLambdas(whenExitNode, callCompleted) whenExitNode.updateDeadStatus() lastNodes.push(whenExitNode) - levelCounter-- return whenExitNode to syntheticElseBranchNode } // ----------------------------------- While Loop ----------------------------------- fun enterWhileLoop(loop: FirLoop): Pair { - val loopEnterNode = createLoopEnterNode(loop).also { - addNewSimpleNode(it) - } + val loopEnterNode = createLoopEnterNode(loop).also { addNewSimpleNode(it) } loopExitNodes.push(createLoopExitNode(loop)) - levelCounter++ - val conditionEnterNode = createLoopConditionEnterNode(loop.condition, loop).also { - addNewSimpleNode(it) - loopConditionEnterNodes.push(it) - } - levelCounter++ + val conditionEnterNode = createLoopConditionEnterNode(loop.condition, loop).also { addNewSimpleNode(it) } + loopConditionEnterNodes.push(conditionEnterNode) return loopEnterNode to conditionEnterNode } fun exitWhileLoopCondition(loop: FirLoop): Pair { - levelCounter-- - val conditionExitNode = createLoopConditionExitNode(loop.condition) - addNewSimpleNode(conditionExitNode) + val conditionExitNode = createLoopConditionExitNode(loop.condition).also { addNewSimpleNode(it) } val conditionConstBooleanValue = loop.condition.booleanConstValue addEdge(conditionExitNode, loopExitNodes.top(), propagateDeadness = false, isDead = conditionConstBooleanValue == true) val loopBlockEnterNode = createLoopBlockEnterNode(loop) addNewSimpleNode(loopBlockEnterNode, conditionConstBooleanValue == false) - levelCounter++ return conditionExitNode to loopBlockEnterNode } fun exitWhileLoop(loop: FirLoop): Triple { - levelCounter-- val loopBlockExitNode = createLoopBlockExitNode(loop) popAndAddEdge(loopBlockExitNode) val conditionEnterNode = loopConditionEnterNodes.pop() @@ -799,41 +777,32 @@ class ControlFlowGraphBuilder { val loopExitNode = loopExitNodes.pop() loopExitNode.updateDeadStatus() lastNodes.push(loopExitNode) - levelCounter-- return Triple(conditionEnterNode, loopBlockExitNode, loopExitNode) } // ----------------------------------- Do while Loop ----------------------------------- fun enterDoWhileLoop(loop: FirLoop): Pair { - val loopEnterNode = createLoopEnterNode(loop) - addNewSimpleNode(loopEnterNode) + val loopEnterNode = createLoopEnterNode(loop).also { addNewSimpleNode(it) } loopExitNodes.push(createLoopExitNode(loop)) - levelCounter++ - val blockEnterNode = createLoopBlockEnterNode(loop) - addNewSimpleNode(blockEnterNode) - // put block enter node twice so we can refer it after exit from loop condition - lastNodes.push(blockEnterNode) + val blockEnterNode = createLoopBlockEnterNode(loop).also { addNewSimpleNode(it) } + lastNodes.push(blockEnterNode) // to add back edge at the end loopConditionEnterNodes.push(createLoopConditionEnterNode(loop.condition, loop)) - levelCounter++ return loopEnterNode to blockEnterNode } fun enterDoWhileLoopCondition(loop: FirLoop): Pair { - levelCounter-- val blockExitNode = createLoopBlockExitNode(loop).also { addNewSimpleNode(it) } // This may sound shocking, but `do...while` conditions can `continue` to themselves, // so we can't pop the node off the stack here. val conditionEnterNode = loopConditionEnterNodes.top().also { addNewSimpleNode(it) } // Might have had live `continue`s with an unreachable block exit, so recompute deadness. conditionEnterNode.updateDeadStatus() - levelCounter++ return blockExitNode to conditionEnterNode } fun exitDoWhileLoop(loop: FirLoop): Pair { loopConditionEnterNodes.pop() - levelCounter-- val conditionExitNode = createLoopConditionExitNode(loop.condition) val conditionBooleanValue = loop.condition.booleanConstValue popAndAddEdge(conditionExitNode) @@ -844,7 +813,6 @@ class ControlFlowGraphBuilder { addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true) loopExit.updateDeadStatus() lastNodes.push(loopExit) - levelCounter-- return conditionExitNode to loopExit } @@ -857,14 +825,12 @@ class ControlFlowGraphBuilder { } addNewSimpleNode(enterNode) binaryLogicExpressionExitNodes.push(exitNode) - levelCounter++ return enterNode } fun exitLeftBinaryLogicExpressionArgument( binaryLogicExpression: FirBinaryLogicExpression ): Pair, CFGNode> { - levelCounter-- val leftBooleanConstValue = binaryLogicExpression.leftOperand.booleanConstValue val (leftExitNode, rightEnterNode) = when (binaryLogicExpression.kind) { LogicOperationKind.AND -> @@ -878,12 +844,10 @@ class ControlFlowGraphBuilder { addEdge(leftExitNode, binaryLogicExpressionExitNodes.top(), propagateDeadness = false, isDead = leftBooleanConstValue == isAnd) addEdge(leftExitNode, rightEnterNode, isDead = leftBooleanConstValue == !isAnd) lastNodes.push(rightEnterNode) - levelCounter++ return leftExitNode to rightEnterNode } fun exitBinaryLogicExpression(): AbstractBinaryExitNode { - levelCounter-- val exitNode = binaryLogicExpressionExitNodes.pop() val rightNode = lastNodes.pop() addEdge(rightNode, exitNode, propagateDeadness = false) @@ -897,14 +861,10 @@ class ControlFlowGraphBuilder { // ----------------------------------- Try-catch-finally ----------------------------------- fun enterTryExpression(tryExpression: FirTryExpression): Pair { - val enterTryExpressionNode = createTryExpressionEnterNode(tryExpression) - val exitTryExpressionNode = createTryExpressionExitNode(tryExpression) - addNewSimpleNode(enterTryExpressionNode) - tryExitNodes.push(exitTryExpressionNode) - levelCounter++ + val enterTryExpressionNode = createTryExpressionEnterNode(tryExpression).also { addNewSimpleNode(it) } + tryExitNodes.push(createTryExpressionExitNode(tryExpression)) - val enterTryMainBlockNode = createTryMainBlockEnterNode(tryExpression) - addNewSimpleNode(enterTryMainBlockNode) + val enterTryMainBlockNode = createTryMainBlockEnterNode(tryExpression).also { addNewSimpleNode(it) } catchNodes.push(tryExpression.catches.map { createCatchClauseEnterNode(it) }) if (tryExpression.finallyBlock != null) { @@ -923,12 +883,10 @@ class ControlFlowGraphBuilder { notCompletedFunctionCalls.push(mutableListOf()) splitDataFlowForPostponedLambdas() - levelCounter++ return enterTryExpressionNode to enterTryMainBlockNode } fun exitTryMainBlock(): TryMainBlockExitNode { - levelCounter-- val exitTryExpressionNode = tryExitNodes.top() val node = createTryMainBlockExitNode(exitTryExpressionNode.fir) popAndAddEdge(node) @@ -956,12 +914,10 @@ class ControlFlowGraphBuilder { addEdge(catchEnterNode, finallyEnterNodes.top(), propagateDeadness = false, label = UncaughtExceptionPath) } lastNodes.push(catchEnterNode) - levelCounter++ return catchEnterNode } fun exitCatchClause(catch: FirCatch): CatchClauseExitNode { - levelCounter-- val exitTryExpressionNode = tryExitNodes.top() val catchExitNode = createCatchClauseExitNode(catch) popAndAddEdge(catchExitNode) @@ -1030,7 +986,6 @@ class ControlFlowGraphBuilder { } fun exitTryExpression(callCompleted: Boolean): TryExpressionExitNode { - levelCounter-- notCompletedFunctionCalls.pop().forEach(::completeFunctionCall) val node = tryExitNodes.pop() mergeDataFlowFromPostponedLambdas(node, callCompleted) @@ -1070,7 +1025,7 @@ class ControlFlowGraphBuilder { // it would be much easier if we could build calls after full completion only, at least for Nothing calls private fun completeFunctionCall(node: FunctionCallNode) { if (!node.fir.resultType.isNothing) return - val stub = withLevelOfNode(node) { createStubNode() } + val stub = StubNode(currentGraph, node.level, currentGraph.nodeCount++) val edges = node.followingNodes.map { it to node.edgeTo(it) } CFGNode.removeAllOutgoingEdges(node) CFGNode.addEdge(node, stub, EdgeKind.DeadForward, propagateDeadness = false) @@ -1111,7 +1066,6 @@ class ControlFlowGraphBuilder { } fun enterCall() { - levelCounter++ splitDataFlowForPostponedLambdas() } @@ -1130,7 +1084,6 @@ class ControlFlowGraphBuilder { } fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean): FunctionCallNode { - levelCounter-- val returnsNothing = functionCall.resultType.isNothing val node = createFunctionCallNode(functionCall) unifyDataFlowFromPostponedLambdas(node, callCompleted) @@ -1146,7 +1099,6 @@ class ControlFlowGraphBuilder { } fun exitDelegatedConstructorCall(call: FirDelegatedConstructorCall, callCompleted: Boolean): DelegatedConstructorCallNode { - levelCounter-- val node = createDelegatedConstructorCallNode(call) unifyDataFlowFromPostponedLambdas(node, callCompleted) addNewSimpleNode(node) @@ -1154,7 +1106,6 @@ class ControlFlowGraphBuilder { } fun exitStringConcatenationCall(call: FirStringConcatenationCall): StringConcatenationCallNode { - levelCounter-- val node = createStringConcatenationCallNode(call) unifyDataFlowFromPostponedLambdas(node, callCompleted = true) addNewSimpleNode(node) @@ -1178,7 +1129,6 @@ class ControlFlowGraphBuilder { } fun exitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, callCompleted: Boolean): CheckNotNullCallNode { - levelCounter-- val node = createCheckNotNullCallNode(checkNotNullCall) unifyDataFlowFromPostponedLambdas(node, callCompleted) if (checkNotNullCall.resultType.isNothing) { @@ -1196,7 +1146,6 @@ class ControlFlowGraphBuilder { // and are never evaluated. We'll push all nodes created in the process into a stub graph, then throw it away. // TODO: don't waste time creating the nodes in the first place graphs.push(ControlFlowGraph(null, "", ControlFlowGraph.Kind.FakeCall)) - levelCounter++ return createFakeExpressionEnterNode().also { lastNodes.push(it) exitTargetsForTry.push(it) // technically might create CFG loops, but the graph will never be visited anyway... @@ -1204,7 +1153,6 @@ class ControlFlowGraphBuilder { } fun exitFakeExpression() { - levelCounter-- lastNodes.pop() exitTargetsForTry.pop() graphs.pop().also { assert(it.kind == ControlFlowGraph.Kind.FakeCall) } @@ -1395,19 +1343,6 @@ class ControlFlowGraphBuilder { } } } - - // ----------------------------------- Utils ----------------------------------- - - private fun withLevelOfNode(node: CFGNode<*>, f: () -> R): R { - val last = levelCounter - levelCounter = node.level - try { - return f() - } finally { - levelCounter = last - } - } - } fun FirDeclaration?.isLocalClassOrAnonymousObject() = ((this as? FirRegularClass)?.isLocal == true) || this is FirAnonymousObject diff --git a/compiler/testData/codegen/box/smartCasts/kt44814.dot b/compiler/testData/codegen/box/smartCasts/kt44814.dot index 284ac9754d9..ce25dc1e6d1 100644 --- a/compiler/testData/codegen/box/smartCasts/kt44814.dot +++ b/compiler/testData/codegen/box/smartCasts/kt44814.dot @@ -368,8 +368,8 @@ digraph kt44814_kt { subgraph cluster_41 { color=blue 112 [label="Enter function [3]" style="filled" fillcolor=red]; - 113 [label="Access variable R|/node| [4]"]; - 114 [label="Access variable R|/token| [4]"]; + 113 [label="Access variable R|/node| [3]"]; + 114 [label="Access variable R|/token| [3]"]; 115 [label="Delegated constructor call: super|>(...) [3]" style="filled" fillcolor=yellow]; 116 [label="Exit function [3]" style="filled" fillcolor=red]; } @@ -387,8 +387,8 @@ digraph kt44814_kt { subgraph cluster_44 { color=blue 122 [label="Enter function [3]" style="filled" fillcolor=red]; - 123 [label="Access variable R|/node| [4]"]; - 124 [label="Access variable R|/token| [4]"]; + 123 [label="Access variable R|/node| [3]"]; + 124 [label="Access variable R|/token| [3]"]; 125 [label="Delegated constructor call: super|>(...) [3]" style="filled" fillcolor=yellow]; 126 [label="Exit function [3]" style="filled" fillcolor=red]; } @@ -462,13 +462,13 @@ digraph kt44814_kt { subgraph cluster_51 { color=blue 142 [label="Enter block [3]"]; - 143 [label="Function call: R|/LighterASTNode.LighterASTNode|() [6]" style="filled" fillcolor=yellow]; - 144 [label="Function call: R|kotlin/collections/listOf|(...) [5]" style="filled" fillcolor=yellow]; - 145 [label="Function call: R|/LighterASTNode.LighterASTNode|(...) [4]" style="filled" fillcolor=yellow]; - 146 [label="Function call: R|/FlyweightCapableTreeStructure.FlyweightCapableTreeStructure|() [4]" style="filled" fillcolor=yellow]; + 143 [label="Function call: R|/LighterASTNode.LighterASTNode|() [3]" style="filled" fillcolor=yellow]; + 144 [label="Function call: R|kotlin/collections/listOf|(...) [3]" style="filled" fillcolor=yellow]; + 145 [label="Function call: R|/LighterASTNode.LighterASTNode|(...) [3]" style="filled" fillcolor=yellow]; + 146 [label="Function call: R|/FlyweightCapableTreeStructure.FlyweightCapableTreeStructure|() [3]" style="filled" fillcolor=yellow]; 147 [label="Function call: R|/FirLightSourceElement.FirLightSourceElement|(...) [3]" style="filled" fillcolor=yellow]; 148 [label="Variable declaration: lval sourceElement: R|FirSourceElement?| [3]"]; - 149 [label="Access variable R|/sourceElement| [4]"]; + 149 [label="Access variable R|/sourceElement| [3]"]; 150 [label="Function call: (this@R|/FirModifierList.Companion|, R|/sourceElement|).R|/FirModifierList.Companion.getModifierList|() [3]" style="filled" fillcolor=yellow]; 151 [label="Variable declaration: lval result: R|FirModifierList?| [3]"]; subgraph cluster_52 { @@ -476,32 +476,32 @@ digraph kt44814_kt { 152 [label="Enter when [3]"]; subgraph cluster_53 { color=blue - 153 [label="Enter when branch condition [4]"]; - 154 [label="Access variable R|/result| [5]"]; - 155 [label="Type operator: (R|/result| is R|FirModifierList.FirLightModifierList|) [5]"]; - 156 [label="Exit when branch condition [4]"]; + 153 [label="Enter when branch condition [3]"]; + 154 [label="Access variable R|/result| [3]"]; + 155 [label="Type operator: (R|/result| is R|FirModifierList.FirLightModifierList|) [3]"]; + 156 [label="Exit when branch condition [3]"]; } subgraph cluster_54 { color=blue - 157 [label="Enter when branch condition else [5]"]; - 158 [label="Exit when branch condition [5]"]; + 157 [label="Enter when branch condition else [3]"]; + 158 [label="Exit when branch condition [3]"]; } - 159 [label="Enter when branch result [6]"]; + 159 [label="Enter when branch result [3]"]; subgraph cluster_55 { color=blue - 160 [label="Enter block [6]"]; - 161 [label="Const: String(Fail) [6]"]; - 162 [label="Exit block [6]"]; + 160 [label="Enter block [3]"]; + 161 [label="Const: String(Fail) [3]"]; + 162 [label="Exit block [3]"]; } - 163 [label="Exit when branch result [5]"]; - 164 [label="Enter when branch result [5]"]; + 163 [label="Exit when branch result [3]"]; + 164 [label="Enter when branch result [3]"]; subgraph cluster_56 { color=blue - 165 [label="Enter block [5]"]; - 166 [label="Const: String(OK) [5]"]; - 167 [label="Exit block [5]"]; + 165 [label="Enter block [3]"]; + 166 [label="Const: String(OK) [3]"]; + 167 [label="Exit block [3]"]; } - 168 [label="Exit when branch result [4]"]; + 168 [label="Exit when branch result [3]"]; 169 [label="Exit when [3]"]; } 170 [label="Jump: ^boxImpl when () { @@ -527,108 +527,108 @@ digraph kt44814_kt { subgraph cluster_59 { color=blue 176 [label="Enter when [3]"]; - 177 [label="Access variable this@R|/FirModifierList.Companion.getModifierList| [4]"]; + 177 [label="Access variable this@R|/FirModifierList.Companion.getModifierList| [3]"]; subgraph cluster_60 { color=blue - 178 [label="Enter when branch condition [4]"]; - 179 [label="Exit $subj [5]"]; - 180 [label="Const: Null(null) [5]"]; - 181 [label="Equality operator == [5]"]; - 182 [label="Exit when branch condition [4]"]; + 178 [label="Enter when branch condition [3]"]; + 179 [label="Exit $subj [3]"]; + 180 [label="Const: Null(null) [3]"]; + 181 [label="Equality operator == [3]"]; + 182 [label="Exit when branch condition [3]"]; } subgraph cluster_61 { color=blue - 183 [label="Enter when branch condition [5]"]; - 184 [label="Exit $subj [6]"]; - 185 [label="Type operator: ($subj$ is R|FirPsiSourceElement|) [6]"]; - 186 [label="Exit when branch condition [5]"]; + 183 [label="Enter when branch condition [3]"]; + 184 [label="Exit $subj [3]"]; + 185 [label="Type operator: ($subj$ is R|FirPsiSourceElement|) [3]"]; + 186 [label="Exit when branch condition [3]"]; } subgraph cluster_62 { color=blue - 187 [label="Enter when branch condition [6]"]; - 188 [label="Exit $subj [7]"]; - 189 [label="Type operator: ($subj$ is R|FirLightSourceElement|) [7]"]; - 190 [label="Exit when branch condition [6]"]; + 187 [label="Enter when branch condition [3]"]; + 188 [label="Exit $subj [3]"]; + 189 [label="Type operator: ($subj$ is R|FirLightSourceElement|) [3]"]; + 190 [label="Exit when branch condition [3]"]; } - 191 [label="Enter when branch result [7]"]; + 191 [label="Enter when branch result [3]"]; subgraph cluster_63 { color=blue - 192 [label="Enter block [7]"]; - 193 [label="Access variable R|/FirLightSourceElement.lighterASTNode| [9]"]; - 194 [label="Access variable R|/FirLightSourceElement.treeStructure| [9]"]; - 195 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...) [8]" style="filled" fillcolor=yellow]; - 196 [label="Postponed enter to lambda [8]"]; + 192 [label="Enter block [3]"]; + 193 [label="Access variable R|/FirLightSourceElement.lighterASTNode| [3]"]; + 194 [label="Access variable R|/FirLightSourceElement.treeStructure| [3]"]; + 195 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...) [3]" style="filled" fillcolor=yellow]; + 196 [label="Postponed enter to lambda [3]"]; subgraph cluster_64 { color=blue - 197 [label="Enter function anonymousFunction [9]" style="filled" fillcolor=red]; + 197 [label="Enter function anonymousFunction [4]" style="filled" fillcolor=red]; subgraph cluster_65 { color=blue - 198 [label="Enter block [9]"]; - 199 [label="Access variable R|/it| [9]"]; - 200 [label="Enter safe call [9]"]; - 201 [label="Access variable R|/LighterASTNode.tokenType| [9]"]; - 202 [label="Exit safe call [9]"]; - 203 [label="Access qualifier /TokenType [9]"]; - 204 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [9]"]; - 205 [label="Equality operator == [9]"]; - 206 [label="Exit block [9]"]; + 198 [label="Enter block [4]"]; + 199 [label="Access variable R|/it| [4]"]; + 200 [label="Enter safe call [4]"]; + 201 [label="Access variable R|/LighterASTNode.tokenType| [4]"]; + 202 [label="Exit safe call [4]"]; + 203 [label="Access qualifier /TokenType [4]"]; + 204 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [4]"]; + 205 [label="Equality operator == [4]"]; + 206 [label="Exit block [4]"]; } - 207 [label="Exit function anonymousFunction [9]" style="filled" fillcolor=red]; + 207 [label="Exit function anonymousFunction [4]" style="filled" fillcolor=red]; } - 208 [label="Postponed exit from lambda [8]"]; - 209 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|(...) [7]" style="filled" fillcolor=yellow]; - 210 [label="Exit lhs of ?: [7]"]; - 211 [label="Enter rhs of ?: [7]"]; - 212 [label="Const: Null(null) [7]"]; - 213 [label="Jump: ^getModifierList Null(null) [7]"]; - 214 [label="Stub [7]" style="filled" fillcolor=gray]; - 215 [label="Lhs of ?: is not null [7]"]; - 216 [label="Exit ?: [7]"]; - 217 [label="Variable declaration: lval modifierListNode: R|LighterASTNode| [7]"]; - 218 [label="Access variable R|/modifierListNode| [8]"]; - 219 [label="Access variable R|/FirLightSourceElement.treeStructure| [8]"]; - 220 [label="Function call: R|/FirModifierList.FirLightModifierList.FirLightModifierList|(...) [7]" style="filled" fillcolor=yellow]; - 221 [label="Exit block [7]"]; + 208 [label="Postponed exit from lambda [3]"]; + 209 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|(...) [3]" style="filled" fillcolor=yellow]; + 210 [label="Exit lhs of ?: [3]"]; + 211 [label="Enter rhs of ?: [3]"]; + 212 [label="Const: Null(null) [3]"]; + 213 [label="Jump: ^getModifierList Null(null) [3]"]; + 214 [label="Stub [3]" style="filled" fillcolor=gray]; + 215 [label="Lhs of ?: is not null [3]"]; + 216 [label="Exit ?: [3]"]; + 217 [label="Variable declaration: lval modifierListNode: R|LighterASTNode| [3]"]; + 218 [label="Access variable R|/modifierListNode| [3]"]; + 219 [label="Access variable R|/FirLightSourceElement.treeStructure| [3]"]; + 220 [label="Function call: R|/FirModifierList.FirLightModifierList.FirLightModifierList|(...) [3]" style="filled" fillcolor=yellow]; + 221 [label="Exit block [3]"]; } - 222 [label="Exit when branch result [6]"]; - 223 [label="Enter when branch result [6]"]; + 222 [label="Exit when branch result [3]"]; + 223 [label="Enter when branch result [3]"]; subgraph cluster_66 { color=blue - 224 [label="Enter block [6]"]; - 225 [label="Access variable R|/FirPsiSourceElement.psi| [6]"]; - 226 [label="Type operator: (this@R|/FirModifierList.Companion.getModifierList|.R|/FirPsiSourceElement.psi| as? R|KtModifierListOwner|) [6]"]; - 227 [label="Enter safe call [6]"]; - 228 [label="Access variable R|/KtModifierListOwner.modifierList| [6]"]; - 229 [label="Enter safe call [6]"]; - 230 [label="Postponed enter to lambda [7]"]; + 224 [label="Enter block [3]"]; + 225 [label="Access variable R|/FirPsiSourceElement.psi| [3]"]; + 226 [label="Type operator: (this@R|/FirModifierList.Companion.getModifierList|.R|/FirPsiSourceElement.psi| as? R|KtModifierListOwner|) [3]"]; + 227 [label="Enter safe call [3]"]; + 228 [label="Access variable R|/KtModifierListOwner.modifierList| [3]"]; + 229 [label="Enter safe call [3]"]; + 230 [label="Postponed enter to lambda [3]"]; subgraph cluster_67 { color=blue - 231 [label="Enter function anonymousFunction [8]" style="filled" fillcolor=red]; + 231 [label="Enter function anonymousFunction [4]" style="filled" fillcolor=red]; subgraph cluster_68 { color=blue - 232 [label="Enter block [8]"]; - 233 [label="Access variable R|/it| [9]"]; - 234 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [8]" style="filled" fillcolor=yellow]; - 235 [label="Exit block [8]"]; + 232 [label="Enter block [4]"]; + 233 [label="Access variable R|/it| [4]"]; + 234 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [4]" style="filled" fillcolor=yellow]; + 235 [label="Exit block [4]"]; } - 236 [label="Exit function anonymousFunction [8]" style="filled" fillcolor=red]; + 236 [label="Exit function anonymousFunction [4]" style="filled" fillcolor=red]; } - 237 [label="Postponed exit from lambda [7]"]; - 238 [label="Function call: $subj$.R|kotlin/let|(...) [6]" style="filled" fillcolor=yellow]; - 239 [label="Exit safe call [6]"]; - 240 [label="Exit safe call [6]"]; - 241 [label="Exit block [6]"]; + 237 [label="Postponed exit from lambda [3]"]; + 238 [label="Function call: $subj$.R|kotlin/let|(...) [3]" style="filled" fillcolor=yellow]; + 239 [label="Exit safe call [3]"]; + 240 [label="Exit safe call [3]"]; + 241 [label="Exit block [3]"]; } - 242 [label="Exit when branch result [5]"]; - 243 [label="Merge postponed lambda exits [6]"]; - 244 [label="Enter when branch result [5]"]; + 242 [label="Exit when branch result [3]"]; + 243 [label="Merge postponed lambda exits [3]"]; + 244 [label="Enter when branch result [3]"]; subgraph cluster_69 { color=blue - 245 [label="Enter block [5]"]; - 246 [label="Const: Null(null) [5]"]; - 247 [label="Exit block [5]"]; + 245 [label="Enter block [3]"]; + 246 [label="Const: Null(null) [3]"]; + 247 [label="Exit block [3]"]; } - 248 [label="Exit when branch result [4]"]; + 248 [label="Exit when branch result [3]"]; 249 [label="Exit when [3]"]; } 250 [label="Jump: ^getModifierList when (this@R|/FirModifierList.Companion.getModifierList|) { @@ -861,7 +861,7 @@ digraph kt44814_kt { subgraph cluster_78 { color=blue 274 [label="Enter block [1]"]; - 275 [label="Access qualifier /FirModifierList [2]"]; + 275 [label="Access qualifier /FirModifierList [1]"]; 276 [label="Function call: Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]" style="filled" fillcolor=yellow]; 277 [label="Jump: ^box Q|FirModifierList|.R|/FirModifierList.Companion.boxImpl|() [1]"]; 278 [label="Stub [1]" style="filled" fillcolor=gray];