From e1f05667381bf651e44091325424d816f97a43bb Mon Sep 17 00:00:00 2001 From: pyos Date: Sat, 19 Nov 2022 13:38:50 +0100 Subject: [PATCH] FIR CFG: refactor handling of boolean operators a bit To reduce the number of functions in FirDataFlowAnalyzer. --- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 40 ++----- .../dfa/cfg/ControlFlowGraphBuilder.kt | 105 ++++++------------ .../FirExpressionsResolveTransformer.kt | 22 ++-- 3 files changed, 52 insertions(+), 115 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index e3e47842077..15bf5fbd9bd 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -1038,46 +1038,22 @@ abstract class FirDataFlowAnalyzer( // ----------------------------------- Boolean operators ----------------------------------- - fun enterBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression) { - graphBuilder.enterBinaryAnd(binaryLogicExpression).mergeIncomingFlow() + fun enterBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression) { + graphBuilder.enterBinaryLogicExpression(binaryLogicExpression).mergeIncomingFlow() } - fun exitLeftBinaryAndArgument(binaryLogicExpression: FirBinaryLogicExpression) { - val (leftExitNode, rightEnterNode) = graphBuilder.exitLeftBinaryAndArgument(binaryLogicExpression) - exitLeftArgumentOfBinaryBooleanOperator(leftExitNode, rightEnterNode, isAnd = true) - } - - fun exitBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression) { - val node = graphBuilder.exitBinaryAnd(binaryLogicExpression) - exitBinaryBooleanOperator(binaryLogicExpression, node, isAnd = true) - } - - fun enterBinaryOr(binaryLogicExpression: FirBinaryLogicExpression) { - graphBuilder.enterBinaryOr(binaryLogicExpression).mergeIncomingFlow() - } - - fun exitLeftBinaryOrArgument(binaryLogicExpression: FirBinaryLogicExpression) { - val (leftExitNode, rightEnterNode) = graphBuilder.exitLeftBinaryOrArgument(binaryLogicExpression) - exitLeftArgumentOfBinaryBooleanOperator(leftExitNode, rightEnterNode, isAnd = false) - } - - fun exitBinaryOr(binaryLogicExpression: FirBinaryLogicExpression) { - val node = graphBuilder.exitBinaryOr(binaryLogicExpression) - exitBinaryBooleanOperator(binaryLogicExpression, node, isAnd = false) - } - - private fun exitLeftArgumentOfBinaryBooleanOperator(leftExitNode: CFGNode<*>, rightEnterNode: CFGNode<*>, isAnd: Boolean) { + fun exitLeftBinaryLogicExpressionArgument(binaryLogicExpression: FirBinaryLogicExpression) { + val (leftExitNode, rightEnterNode) = graphBuilder.exitLeftBinaryLogicExpressionArgument(binaryLogicExpression) val leftExitFlow = leftExitNode.mergeIncomingFlow() val rightEnterFlow = rightEnterNode.mergeIncomingFlow() val leftOperandVariable = variableStorage.get(leftExitFlow, leftExitNode.firstPreviousNode.fir) ?: return + val isAnd = binaryLogicExpression.kind == LogicOperationKind.AND rightEnterFlow.commitOperationStatement(leftOperandVariable eq isAnd) } - private fun exitBinaryBooleanOperator( - binaryLogicExpression: FirBinaryLogicExpression, - node: AbstractBinaryExitNode<*>, - isAnd: Boolean - ) { + fun exitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression) { + val node = graphBuilder.exitBinaryLogicExpression() + val isAnd = binaryLogicExpression.kind == LogicOperationKind.AND val flowFromLeft = node.leftOperandNode.flow val flowFromRight = node.rightOperandNode.flow val flow = node.mergeIncomingFlow() 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 7fb8657e07a..65ce231728f 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 @@ -93,8 +93,7 @@ class ControlFlowGraphBuilder { private val whenExitNodes: NodeStorage = NodeStorage() private val whenBranchIndices: Stack> = stackOf() - private val binaryAndExitNodes: Stack = stackOf() - private val binaryOrExitNodes: Stack = stackOf() + private val binaryLogicExpressionExitNodes: Stack> = stackOf() private val tryExitNodes: NodeStorage = NodeStorage() private val tryMainExitNodes: NodeStorage = NodeStorage() @@ -778,7 +777,7 @@ class ControlFlowGraphBuilder { levelCounter-- val conditionExitNode = createLoopConditionExitNode(loop.condition) addNewSimpleNode(conditionExitNode) - val conditionConstBooleanValue = conditionExitNode.booleanConstValue + val conditionConstBooleanValue = loop.condition.booleanConstValue addEdge(conditionExitNode, loopExitNodes.top(), propagateDeadness = false, isDead = conditionConstBooleanValue == true) val loopBlockEnterNode = createLoopBlockEnterNode(loop) addNewSimpleNode(loopBlockEnterNode, conditionConstBooleanValue == false) @@ -829,7 +828,7 @@ class ControlFlowGraphBuilder { loopConditionEnterNodes.pop() levelCounter-- val conditionExitNode = createLoopConditionExitNode(loop.condition) - val conditionBooleanValue = conditionExitNode.booleanConstValue + val conditionBooleanValue = loop.condition.booleanConstValue popAndAddEdge(conditionExitNode) val blockEnterNode = lastNodes.pop() require(blockEnterNode is LoopBlockEnterNode) @@ -844,79 +843,49 @@ class ControlFlowGraphBuilder { // ----------------------------------- Boolean operators ----------------------------------- - fun enterBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression): BinaryAndEnterNode { - assert(binaryLogicExpression.kind == LogicOperationKind.AND) - binaryAndExitNodes.push(createBinaryAndExitNode(binaryLogicExpression)) - return createBinaryAndEnterNode(binaryLogicExpression).also { addNewSimpleNode(it) }.also { levelCounter++ } + fun enterBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression): CFGNode { + val (enterNode, exitNode) = when (binaryLogicExpression.kind) { + LogicOperationKind.AND -> createBinaryAndEnterNode(binaryLogicExpression) to createBinaryAndExitNode(binaryLogicExpression) + LogicOperationKind.OR -> createBinaryOrEnterNode(binaryLogicExpression) to createBinaryOrExitNode(binaryLogicExpression) + } + addNewSimpleNode(enterNode) + binaryLogicExpressionExitNodes.push(exitNode) + levelCounter++ + return enterNode } - fun exitLeftBinaryAndArgument(binaryLogicExpression: FirBinaryLogicExpression): Pair { - assert(binaryLogicExpression.kind == LogicOperationKind.AND) + fun exitLeftBinaryLogicExpressionArgument( + binaryLogicExpression: FirBinaryLogicExpression + ): Pair, CFGNode> { + levelCounter-- + val leftBooleanConstValue = binaryLogicExpression.leftOperand.booleanConstValue + val (leftExitNode, rightEnterNode) = when (binaryLogicExpression.kind) { + LogicOperationKind.AND -> + createBinaryAndExitLeftOperandNode(binaryLogicExpression) to createBinaryAndEnterRightOperandNode(binaryLogicExpression) + LogicOperationKind.OR -> + createBinaryOrExitLeftOperandNode(binaryLogicExpression) to createBinaryOrEnterRightOperandNode(binaryLogicExpression) + } + val isAnd = binaryLogicExpression.kind == LogicOperationKind.AND val lastNode = lastNodes.pop() - val leftBooleanConstValue = lastNode.booleanConstValue - - val leftExitNode = createBinaryAndExitLeftOperandNode(binaryLogicExpression).also { - addEdge(lastNode, it) - addEdge(it, binaryAndExitNodes.top(), propagateDeadness = false, isDead = leftBooleanConstValue == true) - } - - val rightEnterNode = createBinaryAndEnterRightOperandNode(binaryLogicExpression).also { - addEdge(leftExitNode, it, isDead = leftBooleanConstValue == false) - lastNodes.push(it) - } + addEdge(lastNode, leftExitNode) + addEdge(leftExitNode, binaryLogicExpressionExitNodes.top(), propagateDeadness = false, isDead = leftBooleanConstValue == isAnd) + addEdge(leftExitNode, rightEnterNode, isDead = leftBooleanConstValue == !isAnd) + lastNodes.push(rightEnterNode) + levelCounter++ return leftExitNode to rightEnterNode } - fun exitBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression): BinaryAndExitNode { + fun exitBinaryLogicExpression(): AbstractBinaryExitNode { levelCounter-- - assert(binaryLogicExpression.kind == LogicOperationKind.AND) - return binaryAndExitNodes.pop().also { - val rightNode = lastNodes.pop() - addEdge(rightNode, it, propagateDeadness = false, isDead = it.leftOperandNode.booleanConstValue == false) - it.updateDeadStatus() - lastNodes.push(it) - } + val exitNode = binaryLogicExpressionExitNodes.pop() + val rightNode = lastNodes.pop() + addEdge(rightNode, exitNode, propagateDeadness = false) + exitNode.updateDeadStatus() + lastNodes.push(exitNode) + return exitNode } - fun enterBinaryOr(binaryLogicExpression: FirBinaryLogicExpression): BinaryOrEnterNode { - assert(binaryLogicExpression.kind == LogicOperationKind.OR) - binaryOrExitNodes.push(createBinaryOrExitNode(binaryLogicExpression)) - return createBinaryOrEnterNode(binaryLogicExpression).also { - addNewSimpleNode(it) - }.also { levelCounter++ } - } - - fun exitLeftBinaryOrArgument(binaryLogicExpression: FirBinaryLogicExpression): Pair { - levelCounter-- - assert(binaryLogicExpression.kind == LogicOperationKind.OR) - val previousNode = lastNodes.pop() - val leftBooleanValue = previousNode.booleanConstValue - - val leftExitNode = createBinaryOrExitLeftOperandNode(binaryLogicExpression).also { - addEdge(previousNode, it) - addEdge(it, binaryOrExitNodes.top(), propagateDeadness = false, isDead = leftBooleanValue == false) - } - - val rightExitNode = createBinaryOrEnterRightOperandNode(binaryLogicExpression).also { - addEdge(leftExitNode, it, propagateDeadness = true, isDead = leftBooleanValue == true) - lastNodes.push(it) - levelCounter++ - } - return leftExitNode to rightExitNode - } - - fun exitBinaryOr(binaryLogicExpression: FirBinaryLogicExpression): BinaryOrExitNode { - assert(binaryLogicExpression.kind == LogicOperationKind.OR) - levelCounter-- - return binaryOrExitNodes.pop().also { - val rightNode = lastNodes.pop() - addEdge(rightNode, it, propagateDeadness = false) - it.updateDeadStatus() - lastNodes.push(it) - } - } - - private val CFGNode<*>.booleanConstValue: Boolean? get() = (fir as? FirConstExpression<*>)?.value as? Boolean? + private val FirExpression.booleanConstValue: Boolean? get() = (this as? FirConstExpression<*>)?.value as? Boolean? // ----------------------------------- Try-catch-finally ----------------------------------- diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 2c47eb74774..c6dd0fc9677 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -825,21 +825,13 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT data: ResolutionMode, ): FirStatement = whileAnalysing(binaryLogicExpression) { val booleanType = binaryLogicExpression.typeRef.resolvedTypeFromPrototype(builtinTypes.booleanType.type) - return when (binaryLogicExpression.kind) { - LogicOperationKind.AND -> - binaryLogicExpression.also(dataFlowAnalyzer::enterBinaryAnd) - .transformLeftOperand(this, ResolutionMode.WithExpectedType(booleanType)) - .also(dataFlowAnalyzer::exitLeftBinaryAndArgument) - .transformRightOperand(this, ResolutionMode.WithExpectedType(booleanType)).also(dataFlowAnalyzer::exitBinaryAnd) - - LogicOperationKind.OR -> - binaryLogicExpression.also(dataFlowAnalyzer::enterBinaryOr) - .transformLeftOperand(this, ResolutionMode.WithExpectedType(booleanType)) - .also(dataFlowAnalyzer::exitLeftBinaryOrArgument) - .transformRightOperand(this, ResolutionMode.WithExpectedType(booleanType)).also(dataFlowAnalyzer::exitBinaryOr) - }.transformOtherChildren(transformer, ResolutionMode.WithExpectedType(booleanType)).also { - it.resultType = booleanType - } + return binaryLogicExpression.also(dataFlowAnalyzer::enterBinaryLogicExpression) + .transformLeftOperand(this, ResolutionMode.WithExpectedType(booleanType)) + .also(dataFlowAnalyzer::exitLeftBinaryLogicExpressionArgument) + .transformRightOperand(this, ResolutionMode.WithExpectedType(booleanType)) + .also(dataFlowAnalyzer::exitBinaryLogicExpression) + .transformOtherChildren(transformer, ResolutionMode.WithExpectedType(booleanType)) + .also { it.resultType = booleanType } } override fun transformVariableAssignment(