diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt index ad112641fa8..c76eabd30ca 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.types.model.TypeSystemCommonSuperTypesContext interface DataFlowInferenceContext : TypeSystemCommonSuperTypesContext, ConeInferenceContext { - fun myCommonSuperType(types: List): ConeKotlinType? { + fun commonSuperTypeOrNull(types: List): ConeKotlinType? { return when (types.size) { 0 -> null 1 -> types.first() @@ -22,7 +22,7 @@ interface DataFlowInferenceContext : TypeSystemCommonSuperTypesContext, ConeInfe } } - fun myIntersectTypes(types: List): ConeKotlinType? { + fun intersectTypesOrNull(types: List): ConeKotlinType? { return when (types.size) { 0 -> null 1 -> types.first() @@ -43,7 +43,7 @@ interface DataFlowInferenceContext : TypeSystemCommonSuperTypesContext, ConeInfe val commonTypes = allTypes.toMutableSet() types.forEach { commonTypes.retainAll(it) } val differentTypes = allTypes - commonTypes - myCommonSuperType(differentTypes.toList())?.let { commonTypes += it } + commonSuperTypeOrNull(differentTypes.toList())?.let { commonTypes += it } return commonTypes } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowVariable.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowVariable.kt index 6df3c2fb139..dca1784170f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowVariable.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowVariable.kt @@ -6,43 +6,32 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirThisReference -import org.jetbrains.kotlin.fir.expressions.impl.FirThisReceiverExpressionImpl import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol /* * isSynthetic = false for variables that represents actual variables in fir * isSynthetic = true for complex expressions (like when expression) */ -sealed class DataFlowVariable(val index: Int, val fir: FirElement) { +sealed class DataFlowVariable(val variableIndexForDebug: Int, val fir: FirElement) { abstract val isSynthetic: Boolean - abstract val real: DataFlowVariable + abstract val aliasedVariable: DataFlowVariable abstract val isThisReference: Boolean - final override fun hashCode(): Int { - return index - } - - final override fun equals(other: Any?): Boolean { - if (other !is DataFlowVariable) return false - return index == other.index - } - final override fun toString(): String { - return "d$index" + return "d$variableIndexForDebug" } } private class RealDataFlowVariable(index: Int, fir: FirElement, override val isThisReference: Boolean) : DataFlowVariable(index, fir) { override val isSynthetic: Boolean get() = false - override val real: DataFlowVariable get() = this + override val aliasedVariable: DataFlowVariable get() = this } private class SyntheticDataFlowVariable(index: Int, fir: FirElement) : DataFlowVariable(index, fir) { override val isSynthetic: Boolean get() = true - override val real: DataFlowVariable get() = this + override val aliasedVariable: DataFlowVariable get() = this override val isThisReference: Boolean get() = false } @@ -50,7 +39,7 @@ private class SyntheticDataFlowVariable(index: Int, fir: FirElement) : DataFlowV private class AliasedDataFlowVariable(index: Int, fir: FirElement, var delegate: DataFlowVariable) : DataFlowVariable(index, fir) { override val isSynthetic: Boolean get() = delegate.isSynthetic - override val real: DataFlowVariable get() = delegate.real + override val aliasedVariable: DataFlowVariable get() = delegate.aliasedVariable override val isThisReference: Boolean get() = false } @@ -58,7 +47,7 @@ private class AliasedDataFlowVariable(index: Int, fir: FirElement, var delegate: class DataFlowVariableStorage { private val fir2DfiMap: MutableMap = mutableMapOf() - private var counter: Int = 1 + private var debugIndexCounter: Int = 1 fun getOrCreateNewRealVariable(symbol: FirBasedSymbol<*>): DataFlowVariable { return getOrCreateNewRealVariableImpl(symbol, false) @@ -71,12 +60,12 @@ class DataFlowVariableStorage { private fun getOrCreateNewRealVariableImpl(symbol: FirBasedSymbol<*>, isThisReference: Boolean): DataFlowVariable { val fir = symbol.fir get(fir)?.let { return it } - return RealDataFlowVariable(counter++, fir, isThisReference).also { storeVariable(it, fir) } + return RealDataFlowVariable(debugIndexCounter++, fir, isThisReference).also { storeVariable(it, fir) } } fun getOrCreateNewSyntheticVariable(fir: FirElement): DataFlowVariable { get(fir)?.let { return it } - return SyntheticDataFlowVariable(counter++, fir).also { storeVariable(it, fir) } + return SyntheticDataFlowVariable(debugIndexCounter++, fir).also { storeVariable(it, fir) } } fun createAliasVariable(symbol: FirBasedSymbol<*>, variable: DataFlowVariable) { @@ -84,7 +73,7 @@ class DataFlowVariableStorage { } private fun createAliasVariable(fir: FirElement, variable: DataFlowVariable) { - AliasedDataFlowVariable(counter++, fir, variable).also { storeVariable(it, fir) } + AliasedDataFlowVariable(debugIndexCounter++, fir, variable).also { storeVariable(it, fir) } } fun rebindAliasVariable(aliasVariable: DataFlowVariable, newVariable: DataFlowVariable) { @@ -122,7 +111,7 @@ class DataFlowVariableStorage { fun reset() { fir2DfiMap.clear() - counter = 1 + debugIndexCounter = 1 } private fun storeVariable(variable: DataFlowVariable, fir: FirElement) { 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 e5ef63e0932..1d296e7b6f6 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 @@ -40,30 +40,36 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC private val graphBuilder = ControlFlowGraphBuilder() private val logicSystem = LogicSystem(context) private val variableStorage = DataFlowVariableStorage() - private val edges = mutableMapOf, Flow>() + private val flowOnNodes = mutableMapOf, Flow>() /* * If there is no types from smartcasts function returns null + * + * Note that return value based on state of DataFlowAnalyzer (despite of stateless model of old frontend) */ fun getTypeUsingSmartcastInfo(qualifiedAccessExpression: FirQualifiedAccessExpression): Collection? { - val variable = qualifiedAccessExpression.variable?.real ?: return null + /* + * DataFlowAnalyzer holds variables only for declarations that have some smartcast (or can have) + * If there is no useful information there is no data flow variable also + */ + val variable = qualifiedAccessExpression.variable?.aliasedVariable ?: return null return graphBuilder.lastNode.flow.approvedFacts(variable)?.exactType ?: return null } // ----------------------------------- Named function ----------------------------------- fun enterFunction(function: FirFunction<*>) { - graphBuilder.enterFunction(function).passFlow() + graphBuilder.enterFunction(function).mergeIncomingFlow() } fun exitFunction(function: FirFunction<*>): ControlFlowGraph? { val (node, graph) = graphBuilder.exitFunction(function) - node.passFlow() + node.mergeIncomingFlow() for (valueParameter in function.valueParameters) { variableStorage.removeRealVariable(valueParameter.symbol) } if (graphBuilder.isTopLevel()) { - edges.clear() + flowOnNodes.clear() variableStorage.reset() } return graph @@ -72,38 +78,38 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC // ----------------------------------- Property ----------------------------------- fun enterProperty(property: FirProperty) { - graphBuilder.enterProperty(property).passFlow() + graphBuilder.enterProperty(property).mergeIncomingFlow() } fun exitProperty(property: FirProperty): ControlFlowGraph { val (node, graph) = graphBuilder.exitProperty(property) - node.passFlow() + node.mergeIncomingFlow() return graph } // ----------------------------------- Block ----------------------------------- fun enterBlock(block: FirBlock) { - val node = graphBuilder.enterBlock(block).passFlow(false) + val node = graphBuilder.enterBlock(block).mergeIncomingFlow() - val previousNode = node.usefulPreviousNodes.singleOrNull() as? WhenBranchConditionExitNode + val previousNode = node.alivePreviousNodes.singleOrNull() as? WhenBranchConditionExitNode if (previousNode != null) { node.flow = approveFactsAndUpdateImplicitReceivers(previousNode.variable, EqTrue, node.flow) } } fun exitBlock(block: FirBlock) { - graphBuilder.exitBlock(block).passFlow() + graphBuilder.exitBlock(block).mergeIncomingFlow() } // ----------------------------------- Operator call ----------------------------------- fun exitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall) { - val node = graphBuilder.exitTypeOperatorCall(typeOperatorCall).passFlow(false) + val node = graphBuilder.exitTypeOperatorCall(typeOperatorCall).mergeIncomingFlow() if (typeOperatorCall.operation !in FirOperation.TYPES) return val type = typeOperatorCall.conversionTypeRef.coneTypeSafe() ?: return - val varVariable = getOrCreateRealVariable(typeOperatorCall.argument)?.real ?: return + val operandVariable = getOrCreateRealVariable(typeOperatorCall.argument)?.aliasedVariable ?: return var flow = node.flow when (typeOperatorCall.operation) { @@ -118,34 +124,34 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC flow = flow.addNotApprovedFact( expressionVariable, - UnapprovedFirDataFlowInfo( - EqTrue, varVariable, chooseInfo(true) + ConditionalFirDataFlowInfo( + EqTrue, operandVariable, chooseInfo(true) ) ) flow = flow.addNotApprovedFact( expressionVariable, - UnapprovedFirDataFlowInfo( - EqFalse, varVariable, chooseInfo(false) + ConditionalFirDataFlowInfo( + EqFalse, operandVariable, chooseInfo(false) ) ) } FirOperation.AS -> { - flow = addApprovedFact(flow, varVariable, FirDataFlowInfo(setOf(type), emptySet())) + flow = addApprovedFact(flow, operandVariable, FirDataFlowInfo(setOf(type), emptySet())) } FirOperation.SAFE_AS -> { val expressionVariable = getOrCreateSyntheticVariable(typeOperatorCall) flow = flow.addNotApprovedFact( expressionVariable, - UnapprovedFirDataFlowInfo( - NotEqNull, varVariable, FirDataFlowInfo(setOf(type), emptySet()) + ConditionalFirDataFlowInfo( + NotEqNull, operandVariable, FirDataFlowInfo(setOf(type), emptySet()) ) ).addNotApprovedFact( expressionVariable, - UnapprovedFirDataFlowInfo( - EqNull, varVariable, FirDataFlowInfo(emptySet(), setOf(type)) + ConditionalFirDataFlowInfo( + EqNull, operandVariable, FirDataFlowInfo(emptySet(), setOf(type)) ) ) } @@ -157,7 +163,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC } fun exitOperatorCall(operatorCall: FirOperatorCall) { - val node = graphBuilder.exitOperatorCall(operatorCall).passFlow(false) + val node = graphBuilder.exitOperatorCall(operatorCall).mergeIncomingFlow() when (val operation = operatorCall.operation) { FirOperation.EQ, FirOperation.NOT_EQ, FirOperation.IDENTITY, FirOperation.NOT_IDENTITY -> { val leftOperand = operatorCall.arguments[0] @@ -192,7 +198,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC getRealVariablesForSafeCallChain(operand).takeIf { it.isNotEmpty() }?.let { operandVariables -> operandVariables.forEach { operandVariable -> flow = flow.addNotApprovedFact( - expressionVariable, UnapprovedFirDataFlowInfo( + expressionVariable, ConditionalFirDataFlowInfo( isEq.toEqBoolean(), operandVariable, FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) @@ -208,7 +214,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC val constValue = (const.value as Boolean) val shouldInvert = isEq xor constValue - flow.notApprovedFacts[operandVariable].forEach { info -> + flow.conditionalInfos[operandVariable].forEach { info -> flow = flow.addNotApprovedFact(expressionVariable, info.let { if (shouldInvert) it.invert() else it }) } } @@ -241,12 +247,12 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC facts.forEach { (variable, info) -> flow = flow.addNotApprovedFact( expressionVariable, - UnapprovedFirDataFlowInfo( + ConditionalFirDataFlowInfo( EqTrue, variable, info ) ).addNotApprovedFact( expressionVariable, - UnapprovedFirDataFlowInfo( + ConditionalFirDataFlowInfo( EqFalse, variable, info.invert() ) ) @@ -265,7 +271,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC operandVariables.forEach { operandVariable -> flow = flow.addNotApprovedFact( - expressionVariable, UnapprovedFirDataFlowInfo( + expressionVariable, ConditionalFirDataFlowInfo( condition, operandVariable, FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) @@ -289,17 +295,17 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC // ----------------------------------- Jump ----------------------------------- fun exitJump(jump: FirJump<*>) { - graphBuilder.exitJump(jump).passFlow() + graphBuilder.exitJump(jump).mergeIncomingFlow() } // ----------------------------------- When ----------------------------------- fun enterWhenExpression(whenExpression: FirWhenExpression) { - graphBuilder.enterWhenExpression(whenExpression).passFlow() + graphBuilder.enterWhenExpression(whenExpression).mergeIncomingFlow() } fun enterWhenBranchCondition(whenBranch: FirWhenBranch) { - val node = graphBuilder.enterWhenBranchCondition(whenBranch).passFlow(false) + val node = graphBuilder.enterWhenBranchCondition(whenBranch).mergeIncomingFlow() val previousNode = node.previousNodes.single() if (previousNode is WhenBranchConditionExitNode) { node.flow = approveFactsAndUpdateImplicitReceivers(previousNode.variable, EqFalse, node.flow) @@ -308,20 +314,20 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC } fun exitWhenBranchCondition(whenBranch: FirWhenBranch) { - val node = graphBuilder.exitWhenBranchCondition(whenBranch).passFlow(true) - + val node = graphBuilder.exitWhenBranchCondition(whenBranch).mergeIncomingFlow() + node.flow.freeze() val conditionVariable = getOrCreateVariable(whenBranch.condition) node.variable = conditionVariable } fun exitWhenBranchResult(whenBranch: FirWhenBranch) { - val node = graphBuilder.exitWhenBranchResult(whenBranch).passFlow(false) + val node = graphBuilder.exitWhenBranchResult(whenBranch).mergeIncomingFlow() val conditionVariable = getOrCreateVariable(whenBranch.condition) node.flow = node.flow.removeSyntheticVariable(conditionVariable).apply { freeze() } } fun exitWhenExpression(whenExpression: FirWhenExpression) { - val node = graphBuilder.exitWhenExpression(whenExpression).passFlow() + val node = graphBuilder.exitWhenExpression(whenExpression).mergeIncomingFlow() var flow = node.flow val subjectSymbol = whenExpression.subjectVariable?.symbol if (subjectSymbol != null) { @@ -334,74 +340,74 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC fun enterWhileLoop(loop: FirLoop) { val (loopEnterNode, loopConditionEnterNode) = graphBuilder.enterWhileLoop(loop) - loopEnterNode.passFlow() - loopConditionEnterNode.passFlow() + loopEnterNode.mergeIncomingFlow() + loopConditionEnterNode.mergeIncomingFlow() } fun exitWhileLoopCondition(loop: FirLoop) { - graphBuilder.exitWhileLoopCondition(loop).passFlow() + graphBuilder.exitWhileLoopCondition(loop).mergeIncomingFlow() } fun exitWhileLoop(loop: FirLoop) { graphBuilder.exitWhileLoop(loop).also { (blockExitNode, exitNode) -> - blockExitNode.passFlow() - exitNode.passFlow() + blockExitNode.mergeIncomingFlow() + exitNode.mergeIncomingFlow() } } // ----------------------------------- Do while Loop ----------------------------------- fun enterDoWhileLoop(loop: FirLoop) { - graphBuilder.enterDoWhileLoop(loop).passFlow() + graphBuilder.enterDoWhileLoop(loop).mergeIncomingFlow() } fun enterDoWhileLoopCondition(loop: FirLoop) { val (loopBlockExitNode, loopConditionEnterNode) = graphBuilder.enterDoWhileLoopCondition(loop) - loopBlockExitNode.passFlow() - loopConditionEnterNode.passFlow() + loopBlockExitNode.mergeIncomingFlow() + loopConditionEnterNode.mergeIncomingFlow() } fun exitDoWhileLoop(loop: FirLoop) { - graphBuilder.exitDoWhileLoop(loop).passFlow() + graphBuilder.exitDoWhileLoop(loop).mergeIncomingFlow() } // ----------------------------------- Try-catch-finally ----------------------------------- fun enterTryExpression(tryExpression: FirTryExpression) { - graphBuilder.enterTryExpression(tryExpression).passFlow() + graphBuilder.enterTryExpression(tryExpression).mergeIncomingFlow() } fun exitTryMainBlock(tryExpression: FirTryExpression) { - graphBuilder.exitTryMainBlock(tryExpression).passFlow() + graphBuilder.exitTryMainBlock(tryExpression).mergeIncomingFlow() } fun enterCatchClause(catch: FirCatch) { - graphBuilder.enterCatchClause(catch).passFlow() + graphBuilder.enterCatchClause(catch).mergeIncomingFlow() } fun exitCatchClause(catch: FirCatch) { - graphBuilder.exitCatchClause(catch).passFlow() + graphBuilder.exitCatchClause(catch).mergeIncomingFlow() } fun enterFinallyBlock(tryExpression: FirTryExpression) { // TODO - graphBuilder.enterFinallyBlock(tryExpression).passFlow() + graphBuilder.enterFinallyBlock(tryExpression).mergeIncomingFlow() } fun exitFinallyBlock(tryExpression: FirTryExpression) { // TODO - graphBuilder.exitFinallyBlock(tryExpression).passFlow() + graphBuilder.exitFinallyBlock(tryExpression).mergeIncomingFlow() } fun exitTryExpression(tryExpression: FirTryExpression) { // TODO - graphBuilder.exitTryExpression(tryExpression).passFlow() + graphBuilder.exitTryExpression(tryExpression).mergeIncomingFlow() } // ----------------------------------- Resolvable call ----------------------------------- fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression) { - graphBuilder.exitQualifiedAccessExpression(qualifiedAccessExpression).passFlow() + graphBuilder.exitQualifiedAccessExpression(qualifiedAccessExpression).mergeIncomingFlow() } fun enterFunctionCall(functionCall: FirFunctionCall) { @@ -409,7 +415,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC } fun exitFunctionCall(functionCall: FirFunctionCall) { - val node = graphBuilder.exitFunctionCall(functionCall).passFlow(false) + val node = graphBuilder.exitFunctionCall(functionCall).mergeIncomingFlow() if (functionCall.isBooleanNot()) { exitBooleanNot(functionCall, node) return @@ -434,11 +440,11 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC } fun exitConstExpresion(constExpression: FirConstExpression<*>) { - graphBuilder.exitConstExpresion(constExpression).passFlow() + graphBuilder.exitConstExpresion(constExpression).mergeIncomingFlow() } fun exitVariableDeclaration(variable: FirVariable<*>) { - val node = graphBuilder.exitVariableDeclaration(variable).passFlow(false) + val node = graphBuilder.exitVariableDeclaration(variable).mergeIncomingFlow() val initializer = variable.initializer ?: return /* @@ -463,33 +469,34 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC } fun exitVariableAssignment(assignment: FirVariableAssignment) { - graphBuilder.exitVariableAssignment(assignment).passFlow() + graphBuilder.exitVariableAssignment(assignment).mergeIncomingFlow() val lhsVariable = variableStorage[assignment.resolvedSymbol ?: return] ?: return val rhsVariable = variableStorage[assignment.rValue.resolvedSymbol ?: return]?.takeIf { !it.isSynthetic } ?: return variableStorage.rebindAliasVariable(lhsVariable, rhsVariable) } fun exitThrowExceptionNode(throwExpression: FirThrowExpression) { - graphBuilder.exitThrowExceptionNode(throwExpression).passFlow() + graphBuilder.exitThrowExceptionNode(throwExpression).mergeIncomingFlow() } // ----------------------------------- Boolean operators ----------------------------------- fun enterBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression) { - graphBuilder.enterBinaryAnd(binaryLogicExpression).passFlow() + graphBuilder.enterBinaryAnd(binaryLogicExpression).mergeIncomingFlow() } fun exitLeftBinaryAndArgument(binaryLogicExpression: FirBinaryLogicExpression) { val (leftNode, rightNode) = graphBuilder.exitLeftBinaryAndArgument(binaryLogicExpression) - leftNode.passFlow(true) - rightNode.passFlow(false) + leftNode.mergeIncomingFlow() + leftNode.flow.freeze() + rightNode.mergeIncomingFlow() val leftOperandVariable = getOrCreateVariable(leftNode.previousNodes.first().fir) val flow = approveFactsAndUpdateImplicitReceivers(leftOperandVariable, EqTrue, rightNode.flow) rightNode.flow = flow.also { it.freeze() } } fun exitBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression) { - val node = graphBuilder.exitBinaryAnd(binaryLogicExpression).passFlow(false) + val node = graphBuilder.exitBinaryAnd(binaryLogicExpression).mergeIncomingFlow() val (leftVariable, rightVariable) = binaryLogicExpression.getVariables() val flowFromLeft = node.leftOperandNode.flow @@ -503,19 +510,19 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC val rightIsTrue = approveFact(rightVariable, EqTrue, flowFromRight) ?: mutableMapOf() val rightIsFalse = approveFact(rightVariable, EqFalse, flowFromRight) - flowFromRight.approvedFacts.forEach { (variable, info) -> - val actualInfo = flowFromLeft.approvedFacts[variable]?.let { info - it } ?: info + flowFromRight.approvedInfos.forEach { (variable, info) -> + val actualInfo = flowFromLeft.approvedInfos[variable]?.let { info - it } ?: info if (actualInfo.isNotEmpty) rightIsTrue.compute(variable) { _, existingInfo -> info + existingInfo } } logicSystem.andForVerifiedFacts(leftIsTrue, rightIsTrue)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(EqTrue, variable, info)) + flow.addNotApprovedFact(andVariable, ConditionalFirDataFlowInfo(EqTrue, variable, info)) } } logicSystem.orForVerifiedFacts(leftIsFalse, rightIsFalse)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info)) + flow.addNotApprovedFact(andVariable, ConditionalFirDataFlowInfo(EqFalse, variable, info)) } } node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable) @@ -527,15 +534,16 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC fun exitLeftBinaryOrArgument(binaryLogicExpression: FirBinaryLogicExpression) { val (leftNode, rightNode) = graphBuilder.exitLeftBinaryOrArgument(binaryLogicExpression) - leftNode.passFlow(true) - rightNode.passFlow(false) + leftNode.mergeIncomingFlow() + leftNode.flow.freeze() + rightNode.mergeIncomingFlow() val leftOperandVariable = getOrCreateVariable(leftNode.previousNodes.first().fir) val flow = approveFactsAndUpdateImplicitReceivers(leftOperandVariable, EqFalse, rightNode.flow) rightNode.flow = flow.also { it.freeze() } } fun exitBinaryOr(binaryLogicExpression: FirBinaryLogicExpression) { - val node = graphBuilder.exitBinaryOr(binaryLogicExpression).passFlow(false) + val node = graphBuilder.exitBinaryOr(binaryLogicExpression).mergeIncomingFlow() val (leftVariable, rightVariable) = binaryLogicExpression.getVariables() val flowFromLeft = node.leftOperandNode.flow @@ -551,12 +559,12 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC logicSystem.orForVerifiedFacts(leftIsTrue, rightIsTrue)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(EqTrue, variable, info)) + flow.addNotApprovedFact(orVariable, ConditionalFirDataFlowInfo(EqTrue, variable, info)) } } logicSystem.andForVerifiedFacts(leftIsFalse, rightIsFalse)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info)) + flow.addNotApprovedFact(orVariable, ConditionalFirDataFlowInfo(EqFalse, variable, info)) } } node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable) @@ -571,11 +579,11 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC // ----------------------------------- Annotations ----------------------------------- fun enterAnnotationCall(annotationCall: FirAnnotationCall) { - graphBuilder.enterAnnotationCall(annotationCall).passFlow() + graphBuilder.enterAnnotationCall(annotationCall).mergeIncomingFlow() } fun exitAnnotationCall(annotationCall: FirAnnotationCall) { - graphBuilder.exitAnnotationCall(annotationCall).passFlow() + graphBuilder.exitAnnotationCall(annotationCall).mergeIncomingFlow() } // ----------------------------------- Init block ----------------------------------- @@ -585,7 +593,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC } fun exitInitBlock(initBlock: FirAnonymousInitializer) { - graphBuilder.exitInitBlock(initBlock).passFlow() + graphBuilder.exitInitBlock(initBlock).mergeIncomingFlow() } // ------------------------------------------------------------------------------------------------------------------------- @@ -597,16 +605,14 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC getOrCreateVariable(leftOperand) to getOrCreateVariable(rightOperand) private var CFGNode<*>.flow: Flow - get() = edges[this] ?: Flow.EMPTY + get() = flowOnNodes[this] ?: Flow.EMPTY set(value) { - edges[this] = value + flowOnNodes[this] = value } - private fun > T.passFlow(shouldFreeze: Boolean = false): T = this.also { node -> - val previousFlows = node.usefulPreviousNodes.map { it.flow } - val flow = logicSystem.or(previousFlows).also { - if (shouldFreeze) it.freeze() - } + private fun > T.mergeIncomingFlow(): T = this.also { node -> + val previousFlows = node.alivePreviousNodes.map { it.flow } + val flow = logicSystem.or(previousFlows) if (previousFlows.size > 1) { receiverStack.forEachIndexed { index, receiver -> val variable = variableStorage[receiver.boundSymbol] ?: return@forEachIndexed @@ -633,7 +639,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC } private fun getOrCreateRealVariable(symbol: FirBasedSymbol<*>): DataFlowVariable = - variableStorage.getOrCreateNewRealVariable(symbol).real + variableStorage.getOrCreateNewRealVariable(symbol).aliasedVariable private fun getOrCreateVariable(fir: FirElement): DataFlowVariable { val symbol = fir.resolvedSymbol @@ -695,7 +701,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC private fun updateReceiverType(flow: Flow, variable: DataFlowVariable) { val symbol = (variable.fir as? FirSymbolOwner<*>)?.symbol ?: return val index = receiverStack.getReceiverIndex(symbol) ?: return - val info = flow.approvedFacts[variable] ?: return + val info = flow.approvedInfos[variable] ?: return updateReceiverType(index, info) } @@ -703,7 +709,7 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC val types = info.exactType.toMutableList().also { it += receiverStack.getOriginalType(index) } - receiverStack.replaceReceiverType(index, context.myIntersectTypes(types)!!) + receiverStack.replaceReceiverType(index, context.intersectTypesOrNull(types)!!) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt index d777e8ca74c..64afc7476be 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt @@ -8,13 +8,13 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.render -data class UnapprovedFirDataFlowInfo( +data class ConditionalFirDataFlowInfo( val condition: Condition, val variable: DataFlowVariable, val info: FirDataFlowInfo ) { - fun invert(): UnapprovedFirDataFlowInfo { - return UnapprovedFirDataFlowInfo(condition.invert(), variable, info) + fun invert(): ConditionalFirDataFlowInfo { + return ConditionalFirDataFlowInfo(condition.invert(), variable, info) } override fun toString(): String { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt index 0482796a6de..3a4a2cd9a27 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt @@ -8,8 +8,8 @@ package org.jetbrains.kotlin.fir.resolve.dfa import com.google.common.collect.HashMultimap class Flow( - val approvedFacts: MutableMap = mutableMapOf(), - val notApprovedFacts: HashMultimap = HashMultimap.create(), + val approvedInfos: MutableMap = mutableMapOf(), + val conditionalInfos: HashMultimap = HashMultimap.create(), private var state: State = State.Building ) { private val isFrozen: Boolean get() = state == State.Frozen @@ -20,46 +20,46 @@ class Flow( fun addApprovedFact(variable: DataFlowVariable, info: FirDataFlowInfo): Flow { if (isFrozen) return copyForBuilding().addApprovedFact(variable, info) - approvedFacts.compute(variable) { _, existingInfo -> + approvedInfos.compute(variable) { _, existingInfo -> if (existingInfo == null) info else existingInfo + info } return this } - fun addNotApprovedFact(variable: DataFlowVariable, info: UnapprovedFirDataFlowInfo): Flow { + fun addNotApprovedFact(variable: DataFlowVariable, info: ConditionalFirDataFlowInfo): Flow { if (isFrozen) return copyForBuilding().addNotApprovedFact(variable, info) - notApprovedFacts.put(variable, info) + conditionalInfos.put(variable, info) return this } fun copyNotApprovedFacts( from: DataFlowVariable, to: DataFlowVariable, - transform: ((UnapprovedFirDataFlowInfo) -> UnapprovedFirDataFlowInfo)? = null + transform: ((ConditionalFirDataFlowInfo) -> ConditionalFirDataFlowInfo)? = null ): Flow { if (isFrozen) return copyForBuilding().copyNotApprovedFacts(from, to, transform) var facts = if (from.isSynthetic) { - notApprovedFacts.removeAll(from) + conditionalInfos.removeAll(from) } else { - notApprovedFacts[from] + conditionalInfos[from] } if (transform != null) { facts = facts.mapTo(mutableSetOf(), transform) } - notApprovedFacts.putAll(to, facts) + conditionalInfos.putAll(to, facts) return this } fun approvedFacts(variable: DataFlowVariable): FirDataFlowInfo? { - return approvedFacts[variable] + return approvedInfos[variable] } fun removeVariableFromFlow(variable: DataFlowVariable): Flow { if (isFrozen) return copyForBuilding().removeVariableFromFlow(variable) - notApprovedFacts.removeAll(variable) - approvedFacts.remove(variable) + conditionalInfos.removeAll(variable) + approvedInfos.remove(variable) return this } @@ -79,7 +79,7 @@ class Flow( } fun copyForBuilding(): Flow { - return Flow(approvedFacts.toMutableMap(), notApprovedFacts.copy(), State.Building) + return Flow(approvedInfos.toMutableMap(), conditionalInfos.copy(), State.Building) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt index 61e6f90c490..e4f797e4af4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt @@ -14,28 +14,27 @@ class LogicSystem(private val context: DataFlowInferenceContext) { storages.singleOrNull()?.let { return it } - val approvedFacts = mutableMapOf().apply { - storages.map { it.approvedFacts.keys } - .intersectSets() - .forEach { variable -> - val infos = storages.map { it.approvedFacts[variable]!! } - if (infos.isNotEmpty()) { - this[variable] = context.or(infos) - } + val approvedFacts = mutableMapOf() + storages.map { it.approvedInfos.keys } + .intersectSets() + .forEach { variable -> + val infos = storages.map { it.approvedInfos[variable]!! } + if (infos.isNotEmpty()) { + approvedFacts[variable] = context.or(infos) } - } - - val notApprovedFacts = HashMultimap.create() - .apply { - storages.map { it.notApprovedFacts.keySet() } - .intersectSets() - .forEach { variable -> - val infos = storages.map { it.notApprovedFacts[variable] }.intersectSets() - if (infos.isNotEmpty()) { - this.putAll(variable, infos) - } - } } + + + val notApprovedFacts = HashMultimap.create() + storages.map { it.conditionalInfos.keySet() } + .intersectSets() + .forEach { variable -> + val infos = storages.map { it.conditionalInfos[variable] }.intersectSets() + if (infos.isNotEmpty()) { + notApprovedFacts.putAll(variable, infos) + } + } + return Flow(approvedFacts, notApprovedFacts) } @@ -70,7 +69,7 @@ class LogicSystem(private val context: DataFlowInferenceContext) { } fun approveFactsInsideFlow(variable: DataFlowVariable, condition: Condition, flow: Flow): Pair> { - val notApprovedFacts: Set = flow.notApprovedFacts[variable] + val notApprovedFacts: Set = flow.conditionalInfos[variable] if (notApprovedFacts.isEmpty()) { return flow to emptyList() } @@ -87,10 +86,10 @@ class LogicSystem(private val context: DataFlowInferenceContext) { newFacts.asMap().forEach { (variable, infos) -> @Suppress("NAME_SHADOWING") val infos = ArrayList(infos) - flow.approvedFacts[variable]?.let { + flow.approvedInfos[variable]?.let { infos.add(it) } - flow.approvedFacts[variable] = context.and(infos) + flow.approvedInfos[variable] = context.and(infos) if (variable.isThisReference) { updatedReceivers += variable } @@ -99,7 +98,7 @@ class LogicSystem(private val context: DataFlowInferenceContext) { } fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap { - val notApprovedFacts: Set = flow.notApprovedFacts[variable] + val notApprovedFacts: Set = flow.conditionalInfos[variable] if (notApprovedFacts.isEmpty()) { return mutableMapOf() } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt index 6f4e266acfd..5976df1f0a1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt @@ -31,12 +31,8 @@ sealed class CFGNode(val owner: ControlFlowGraph, val level: var isDead: Boolean = false } -val CFGNode<*>.usefulFollowingNodes: List> get() = if (isDead) followingNodes else followingNodes.filterNot { it.isDead } -val CFGNode<*>.usefulPreviousNodes: List> get() = if (isDead) previousNodes else previousNodes.filterNot { it.isDead } - -interface ReturnableNothingNode { - val returnsNothing: Boolean -} +val CFGNode<*>.aliveFollowingNodes: List> get() = if (isDead) followingNodes else followingNodes.filterNot { it.isDead } +val CFGNode<*>.alivePreviousNodes: List> get() = if (isDead) previousNodes else previousNodes.filterNot { it.isDead } interface EnterNode interface ExitNode @@ -48,8 +44,8 @@ class FunctionExitNode(owner: ControlFlowGraph, override val fir: FirFunction<*> // ----------------------------------- Property ----------------------------------- -class PropertyEnterNode(owner: ControlFlowGraph, override val fir: FirProperty, level: Int) : CFGNode(owner, level), EnterNode -class PropertyExitNode(owner: ControlFlowGraph, override val fir: FirProperty, level: Int) : CFGNode(owner, level), ExitNode +class PropertyInitializerEnterNode(owner: ControlFlowGraph, override val fir: FirProperty, level: Int) : CFGNode(owner, level), EnterNode +class PropertyInitializerExitNode(owner: ControlFlowGraph, override val fir: FirProperty, level: Int) : CFGNode(owner, level), ExitNode // ----------------------------------- Init ----------------------------------- @@ -125,24 +121,20 @@ class ConstExpressionNode(owner: ControlFlowGraph, override val fir: FirConstExp class QualifiedAccessNode( owner: ControlFlowGraph, override val fir: FirQualifiedAccessExpression, - override val returnsNothing: Boolean, level: Int -) : CFGNode(owner, level), ReturnableNothingNode +) : CFGNode(owner, level) class FunctionCallNode( owner: ControlFlowGraph, override val fir: FirFunctionCall, - override val returnsNothing: Boolean, level: Int -) : CFGNode(owner, level), ReturnableNothingNode +) : CFGNode(owner, level) class ThrowExceptionNode( owner: ControlFlowGraph, override val fir: FirThrowExpression, level: Int -) : CFGNode(owner, level), ReturnableNothingNode { - override val returnsNothing: Boolean get() = true -} +) : CFGNode(owner, level) class StubNode(owner: ControlFlowGraph, level: Int) : CFGNode(owner, level) { init { 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 e6d4b55d68e..370c0d08be2 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 @@ -39,7 +39,7 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() { private val binaryAndExitNodes: Stack = stackOf() private val binaryOrExitNodes: Stack = stackOf() - private val topLevelVariableExitNodes: Stack = stackWithCallbacks( + private val topLevelVariableInitializerExitNodes: Stack = stackWithCallbacks( pushCallback = { exitNodes.push(it) }, popCallback = { exitNodes.pop() } ) @@ -127,11 +127,11 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() { // ----------------------------------- Property ----------------------------------- - fun enterProperty(property: FirProperty): PropertyEnterNode { + fun enterProperty(property: FirProperty): PropertyInitializerEnterNode { graphs.push(ControlFlowGraph("val ${property.name}")) - val enterNode = createPropertyEnterNode(property) - val exitNode = createPropertyExitNode(property) - topLevelVariableExitNodes.push(exitNode) + val enterNode = createPropertyInitializerEnterNode(property) + val exitNode = createPropertyInitializerExitNode(property) + topLevelVariableInitializerExitNodes.push(exitNode) lexicalScopes.push(stackOf(enterNode)) graph.enterNode = enterNode graph.exitNode = exitNode @@ -139,8 +139,8 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() { return enterNode } - fun exitProperty(property: FirProperty): Pair { - val topLevelVariableExitNode = topLevelVariableExitNodes.pop().also { + fun exitProperty(property: FirProperty): Pair { + val topLevelVariableExitNode = topLevelVariableInitializerExitNodes.pop().also { addNewSimpleNode(it) it.markAsDeadIfNecessary() } @@ -169,7 +169,6 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() { is FirBreakExpression -> loopExitNodes[jump.target.labeledElement] else -> throw IllegalArgumentException("Unknown jump type: ${jump.render()}") } - addNodeWithJump(node, nextNode) return node } @@ -456,7 +455,7 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() { fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression): QualifiedAccessNode { val returnsNothing = qualifiedAccessExpression.resultType.isNothing - val node = createQualifiedAccessNode(qualifiedAccessExpression, returnsNothing) + val node = createQualifiedAccessNode(qualifiedAccessExpression) if (returnsNothing) { addNodeThatReturnsNothing(node) } else { @@ -467,7 +466,7 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() { fun exitFunctionCall(functionCall: FirFunctionCall): FunctionCallNode { val returnsNothing = functionCall.resultType.isNothing - val node = createFunctionCallNode(functionCall, returnsNothing) + val node = createFunctionCallNode(functionCall) if (returnsNothing) { addNodeThatReturnsNothing(node) } else { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt index d88bf85c67b..84cf00ed4f9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt @@ -41,18 +41,18 @@ abstract class ControlFlowGraphNodeBuilder { protected fun createJumpNode(fir: FirJump<*>): JumpNode = JumpNode(graph, fir, levelCounter) - protected fun createQualifiedAccessNode( - fir: FirQualifiedAccessExpression, - returnsNothing: Boolean - ): QualifiedAccessNode = QualifiedAccessNode(graph, fir, returnsNothing, levelCounter) + protected fun createQualifiedAccessNode(fir: FirQualifiedAccessExpression): QualifiedAccessNode = + QualifiedAccessNode(graph, fir, levelCounter) protected fun createBlockEnterNode(fir: FirBlock): BlockEnterNode = BlockEnterNode(graph, fir, levelCounter) protected fun createBlockExitNode(fir: FirBlock): BlockExitNode = BlockExitNode(graph, fir, levelCounter) - protected fun createPropertyExitNode(fir: FirProperty): PropertyExitNode = PropertyExitNode(graph, fir, levelCounter) + protected fun createPropertyInitializerExitNode(fir: FirProperty): PropertyInitializerExitNode = + PropertyInitializerExitNode(graph, fir, levelCounter) - protected fun createPropertyEnterNode(fir: FirProperty): PropertyEnterNode = PropertyEnterNode(graph, fir, levelCounter) + protected fun createPropertyInitializerEnterNode(fir: FirProperty): PropertyInitializerEnterNode = + PropertyInitializerEnterNode(graph, fir, levelCounter) protected fun createFunctionEnterNode(fir: FirFunction<*>, isInPlace: Boolean): FunctionEnterNode = FunctionEnterNode(graph, fir, levelCounter).also { @@ -66,7 +66,7 @@ abstract class ControlFlowGraphNodeBuilder { if (!isInPlace) { graph.exitNode = it } - } + } protected fun createBinaryOrEnterNode(fir: FirBinaryLogicExpression): BinaryOrEnterNode = BinaryOrEnterNode(graph, fir, levelCounter) @@ -107,8 +107,8 @@ abstract class ControlFlowGraphNodeBuilder { protected fun createLoopBlockExitNode(fir: FirLoop): LoopBlockExitNode = LoopBlockExitNode(graph, fir, levelCounter) - protected fun createFunctionCallNode(fir: FirFunctionCall, returnsNothing: Boolean): FunctionCallNode = - FunctionCallNode(graph, fir, returnsNothing, levelCounter) + protected fun createFunctionCallNode(fir: FirFunctionCall): FunctionCallNode = + FunctionCallNode(graph, fir, levelCounter) protected fun createVariableAssignmentNode(fir: FirVariableAssignment): VariableAssignmentNode = VariableAssignmentNode(graph, fir, levelCounter) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt index b9c009257cc..bb9316da39e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphRenderer.kt @@ -141,8 +141,8 @@ fun CFGNode<*>.render(): String = is BinaryOrEnterRightOperandNode -> "Enter right part of ||" is BinaryOrExitNode -> "Exit ||" - is PropertyEnterNode -> "Enter property" - is PropertyExitNode -> "Exit property" + is PropertyInitializerEnterNode -> "Enter property" + is PropertyInitializerExitNode -> "Exit property" is InitBlockEnterNode -> "Enter init block" is InitBlockExitNode -> "Exit init block" is AnnotationEnterNode -> "Enter annotation"