From 166ddd9ea920cd181ffbdcb0e89fb272c1ae17b7 Mon Sep 17 00:00:00 2001 From: pyos Date: Wed, 18 Jan 2023 13:21:14 +0100 Subject: [PATCH] FIR CFA: make node unionness a runtime property Class exit node should only unify data flow if it is an anonymous object, in which case it only has one control flow input. Coversely, any other class exit node has normal merge semantics for its control flow inputs, but it won't have any data flow inputs. --- .../analysis/cfa/FirCallsEffectAnalyzer.kt | 4 +- .../cfa/FirPropertyInitializationAnalyzer.kt | 6 +-- .../fir/analysis/cfa/util/CfgTraverser.kt | 2 +- .../LocalPropertyAndCapturedWriteCollector.kt | 2 - .../util/PathAwareControlFlowGraphVisitor.kt | 5 -- .../declaration/FirTailrecFunctionChecker.kt | 2 - .../checkers/extended/CanBeValChecker.kt | 2 - .../checkers/extended/UnusedChecker.kt | 10 +--- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 2 +- .../dfa/cfg/ControlFlowGraphBuilder.kt | 17 +++---- .../dfa/cfg/ControlFlowGraphRenderer.kt | 2 +- .../kotlin/fir/resolve/dfa/cfg/CFGNode.kt | 50 +++++++++++++------ .../dfa/cfg/ControlFlowGraphVisitor.kt | 12 ++--- .../dfa/cfg/ControlFlowGraphVisitorVoid.kt | 16 ++---- 14 files changed, 59 insertions(+), 73 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt index 4089ab79944..892152c4805 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt @@ -158,8 +158,6 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() { override fun visitNode(node: CFGNode<*>, data: IllegalScopeContext) {} - override fun visitUnionNode(node: T, data: IllegalScopeContext) where T : CFGNode<*>, T : UnionNodeMarker {} - override fun visitFunctionEnterNode(node: FunctionEnterNode, data: IllegalScopeContext) { // TODO: this is not how CFG works, this should be done by FIR tree traversal. Especially considering that // none of these methods use anything from the CFG other than `node.fir`, which should've been a hint. @@ -237,7 +235,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() { node: FunctionCallNode, data: PathAwareLambdaInvocationInfo ): PathAwareLambdaInvocationInfo { - var dataForNode = visitUnionNode(node, data) + var dataForNode = visitNode(node, data) val functionSymbol = node.fir.toResolvedCallableSymbol() as? FirFunctionSymbol<*>? val contractDescription = functionSymbol?.resolvedContractDescription diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt index ad63991fab7..8110eeab160 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt @@ -51,10 +51,8 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec val reporter: DiagnosticReporter, val context: CheckerContext ) : ControlFlowGraphVisitorVoid() { - override fun visitNode(node: CFGNode<*>) {} - - override fun visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker { - // TODO: f({ x = 1 }, { x = 2 }) - which to report? + override fun visitNode(node: CFGNode<*>) { + // TODO: `node.isUnion` - f({ x = 1 }, { x = 2 }) - which to report? // Also this is currently indistinguishable from x = 1; f({}, {}). } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/CfgTraverser.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/CfgTraverser.kt index e398d7faee3..b6907b1eb48 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/CfgTraverser.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/CfgTraverser.kt @@ -45,7 +45,7 @@ private fun > ControlFlowGraph.collectDataForNodeIn TraverseDirection.Backward -> node.followingCfgNodes } // TODO: if data for previousNodes hasn't changed, then should be no need to recompute data for this one - val union = node is UnionNodeMarker + val union = node.isUnion val previousData = previousNodes.mapNotNull { val k = when (direction) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt index e183336de84..4890915008a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/LocalPropertyAndCapturedWriteCollector.kt @@ -34,8 +34,6 @@ class LocalPropertyAndCapturedWriteCollector private constructor() : ControlFlow override fun visitNode(node: CFGNode<*>) {} - override fun visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {} - override fun visitVariableDeclarationNode(node: VariableDeclarationNode) { symbols[node.fir.symbol] = lambdaOrLocalFunctionStack.lastOrNull() == null } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/PathAwareControlFlowGraphVisitor.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/PathAwareControlFlowGraphVisitor.kt index fc08b03336a..01e7987a3d1 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/PathAwareControlFlowGraphVisitor.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/util/PathAwareControlFlowGraphVisitor.kt @@ -65,9 +65,4 @@ abstract class PathAwareControlFlowGraphVisitor> : node: CFGNode<*>, data: PathAwareControlFlowInfo ): PathAwareControlFlowInfo = data - - override fun visitUnionNode( - node: T, - data: PathAwareControlFlowInfo - ): PathAwareControlFlowInfo where T : CFGNode<*>, T : UnionNodeMarker = data } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt index 845cbf8e63d..7ebfe8e9ba8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt @@ -40,8 +40,6 @@ object FirTailrecFunctionChecker : FirSimpleFunctionChecker() { graph.traverse(object : ControlFlowGraphVisitorVoid() { override fun visitNode(node: CFGNode<*>) {} - override fun visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {} - override fun visitTryMainBlockEnterNode(node: TryMainBlockEnterNode) { tryScopeCount++ } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt index 66545d0e2cf..d6250d70fba 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt @@ -82,8 +82,6 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() { ) : ControlFlowGraphVisitorVoid() { override fun visitNode(node: CFGNode<*>) {} - override fun visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {} - override fun visitVariableAssignmentNode(node: VariableAssignmentNode) { val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: return if (symbol !in localProperties) return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt index 56afae2bd28..75e7c7c5e04 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt @@ -50,8 +50,6 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() { ) : ControlFlowGraphVisitorVoid() { override fun visitNode(node: CFGNode<*>) {} - override fun visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {} - override fun visitVariableAssignmentNode(node: VariableAssignmentNode) { val variableSymbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: return val dataPerNode = data[node] ?: return @@ -182,12 +180,6 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() { ): PathAwareVariableStatusInfo = super.visitNode(node, data).withAnnotationsFrom(node) - override fun visitUnionNode( - node: T, - data: PathAwareVariableStatusInfo - ): PathAwareVariableStatusInfo where T : CFGNode<*>, T : UnionNodeMarker = - super.visitUnionNode(node, data).withAnnotationsFrom(node) - override fun visitVariableDeclarationNode( node: VariableDeclarationNode, data: PathAwareVariableStatusInfo @@ -289,7 +281,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() { node: FunctionCallNode, data: PathAwareVariableStatusInfo ): PathAwareVariableStatusInfo { - val dataForNode = visitUnionNode(node, data) + val dataForNode = visitNode(node, data) val reference = node.fir.calleeReference.resolved ?: return dataForNode val functionSymbol = reference.resolvedSymbol as? FirFunctionSymbol<*> ?: return dataForNode val symbol = if (functionSymbol.callableId.callableName.identifier == "invoke") { 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 67e427ecb35..2e026e929ba 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 @@ -1119,7 +1119,7 @@ abstract class FirDataFlowAnalyzer( // data flow for any of them until reaching a completed call. if (it is MergePostponedLambdaExitsNode) it.mergeIncomingFlow() else it.flow } - val result = logicSystem.joinFlow(previousFlows, union = this is UnionNodeMarker) + val result = logicSystem.joinFlow(previousFlows, isUnion) if (graphBuilder.lastNodeOrNull == this) { // Here it is, the new `lastNode`. If the previous state is the only predecessor, then there is actually // nothing to update; `addTypeStatement` has already ensured we have the correct information. 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 d3b12fd1189..98dec4910c9 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 @@ -273,7 +273,7 @@ class ControlFlowGraphBuilder { postponedLambdaExits.push(mutableListOf()) } - private fun unifyDataFlowFromPostponedLambdas(node: T, callCompleted: Boolean) where T : CFGNode<*>, T : UnionNodeMarker { + private fun unifyDataFlowFromPostponedLambdas(node: CFGNode<*>, callCompleted: Boolean) { val currentLevelExits = postponedLambdaExits.pop() if (currentLevelExits.isEmpty()) return @@ -449,10 +449,6 @@ class ControlFlowGraphBuilder { } } - // Classes are not initialized in place so no point in merging data flow - it will not be used. - val mergeDataFlow = klass is FirAnonymousObject && klass.classKind != ClassKind.ENUM_ENTRY - val exitKind = if (mergeDataFlow) EdgeKind.Forward else EdgeKind.CfgForward - val lastInPlaceExit = calledInPlace.fold<_, CFGNode<*>>(enterNode) { lastNode, graph -> // In local classes, we already have control flow (+ data flow) edge from `enterNode` // to first in-place initializer. @@ -461,10 +457,9 @@ class ControlFlowGraphBuilder { } graph.exitNode } - if (mergeDataFlow) { - // TODO: this is wrong. Not sure if it's possible to describe the correct data flow graph here. Things - // would be much easier if it was guaranteed that constructors are analyzed after all other members: - // they have no implicit return type anyway, and we could then pass correct data flow to them. + if (exitNode.isUnion) { + // => this is an anonymous object => there's only one constructor => can use `exitNode` + // to unify data flow from all in-place-called members, including said constructor. for (graph in calledInPlace) { addEdge(graph.exitNode, exitNode, preferredKind = EdgeKind.DfgForward) } @@ -486,7 +481,7 @@ class ControlFlowGraphBuilder { if (delegatedConstructorExit !== enterNode || delegatedConstructorExit.previousNodes.isEmpty()) { addEdgeToSubGraph(delegatedConstructorExit, graph.enterNode) } - addEdge(graph.exitNode, exitNode, preferredKind = exitKind) + addEdge(graph.exitNode, exitNode, preferredKind = if (exitNode.isUnion) EdgeKind.Forward else EdgeKind.CfgForward) } if (constructors.isEmpty()) { @@ -511,7 +506,7 @@ class ControlFlowGraphBuilder { enterNode.subGraphs = calledInPlace + constructors.values exitNode.subGraphs = calledLater - return exitNode.takeIf { mergeDataFlow } to popGraph() + return exitNode.takeIf { it.isUnion } to popGraph() } fun exitAnonymousObjectExpression(anonymousObjectExpression: FirAnonymousObjectExpression): AnonymousObjectExpressionExitNode? { 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 0184cbd58ad..f77fb483a01 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 @@ -70,7 +70,7 @@ class FirControlFlowGraphRenderVisitor( when { node.isDead -> "gray" node == node.owner.enterNode || node == node.owner.exitNode -> "red" - node is UnionNodeMarker -> "yellow" + node.isUnion -> "yellow" else -> null }?.let { attributes += "style=\"filled\"" diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt index f67ac32efe6..6056ecc6669 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.dfa.cfg import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.* @@ -31,6 +32,12 @@ sealed class CFGNode(val owner: ControlFlowGraph, val level: open val canThrow: Boolean get() = false + // a ---> b ---> d + // \-> c -/ + // Normal CFG semantics: a, then either b or c, then d + // If d is a union node: a, then *both* b and c in some unknown order, then d + open val isUnion: Boolean get() = false + companion object { @CfgInternals fun addEdge( @@ -107,7 +114,7 @@ sealed class CFGNode(val owner: ControlFlowGraph, val level: @CfgInternals fun updateDeadStatus() { - isDead = if (this is UnionNodeMarker) + isDead = if (isUnion) _incomingEdges?.let { map -> map.values.any { it.kind.isDead } } == true else _incomingEdges?.let { map -> map.size == previousNodes.size && map.values.all { it.kind.isDead || !it.kind.usedInCfa } } == true @@ -128,12 +135,6 @@ interface ExitNodeMarker interface GraphEnterNodeMarker : EnterNodeMarker interface GraphExitNodeMarker : ExitNodeMarker -// a ---> b ---> d -// \-> c -/ -// Normal CFG semantics: a, then either b or c, then d -// If d is an instance of this interface: a, then *both* b and c in some unknown order, then d -interface UnionNodeMarker - // ----------------------------------- EnterNode for declaration with CFG ----------------------------------- sealed class CFGNodeWithSubgraphs(owner: ControlFlowGraph, level: Int) : CFGNode(owner, level) { @@ -245,7 +246,10 @@ class ClassEnterNode(owner: ControlFlowGraph, override val fir: FirClass, level: } class ClassExitNode(owner: ControlFlowGraph, override val fir: FirClass, level: Int) : CFGNodeWithSubgraphs(owner, level), - GraphExitNodeMarker, UnionNodeMarker { + GraphExitNodeMarker { + + override val isUnion: Boolean + get() = fir is FirAnonymousObject && fir.classKind != ClassKind.ENUM_ENTRY @set:CfgInternals override lateinit var subGraphs: List @@ -305,7 +309,10 @@ class PropertyInitializerExitNode(owner: ControlFlowGraph, override val fir: Fir class DelegateExpressionExitNode(owner: ControlFlowGraph, override val fir: FirExpression, level: Int) - : CFGNode(owner, level), UnionNodeMarker { + : CFGNode(owner, level) { + + override val isUnion: Boolean get() = true + override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { return visitor.visitDelegateExpressionExitNode(this, data) } @@ -610,10 +617,13 @@ class ConstExpressionNode(owner: ControlFlowGraph, override val fir: FirConstExp // ----------------------------------- Check not null call ----------------------------------- class CheckNotNullCallNode(owner: ControlFlowGraph, override val fir: FirCheckNotNullCall, level: Int) - : CFGNode(owner, level), UnionNodeMarker { + : CFGNode(owner, level) { override val canThrow: Boolean get() = true + override val isUnion: Boolean + get() = true + override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { return visitor.visitCheckNotNullCallNode(this, data) } @@ -645,10 +655,14 @@ class ResolvedQualifierNode( } class FunctionCallNode(owner: ControlFlowGraph, override val fir: FirFunctionCall, level: Int) - : CFGNode(owner, level), UnionNodeMarker { + : CFGNode(owner, level) { + override val canThrow: Boolean get() = true + override val isUnion: Boolean + get() = true + override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { return visitor.visitFunctionCallNode(this, data) } @@ -671,7 +685,11 @@ class GetClassCallNode(owner: ControlFlowGraph, override val fir: FirGetClassCal } class DelegatedConstructorCallNode(owner: ControlFlowGraph, override val fir: FirDelegatedConstructorCall, level: Int) - : CFGNode(owner, level), UnionNodeMarker { + : CFGNode(owner, level) { + + override val isUnion: Boolean + get() = true + override val canThrow: Boolean get() = true // shouldn't matter since delegated constructor calls aren't wrapped in try-finally, but still @@ -681,7 +699,11 @@ class DelegatedConstructorCallNode(owner: ControlFlowGraph, override val fir: Fi } class StringConcatenationCallNode(owner: ControlFlowGraph, override val fir: FirStringConcatenationCall, level: Int) - : CFGNode(owner, level), UnionNodeMarker { + : CFGNode(owner, level) { + + override val isUnion: Boolean + get() = true + override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { return visitor.visitStringConcatenationCallNode(this, data) } @@ -804,4 +826,4 @@ class SmartCastExpressionExitNode(owner: ControlFlowGraph, override val fir: Fir override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { return visitor.visitSmartCastExpressionExitNode(this, data) } -} \ No newline at end of file +} diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt index c425cdf96ea..aac9fd965bf 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt @@ -8,8 +8,6 @@ package org.jetbrains.kotlin.fir.resolve.dfa.cfg abstract class ControlFlowGraphVisitor { abstract fun visitNode(node: CFGNode<*>, data: D): R - abstract fun visitUnionNode(node: T, data: D): R where T : CFGNode<*>, T : UnionNodeMarker - // ----------------------------------- Simple function ----------------------------------- open fun visitFunctionEnterNode(node: FunctionEnterNode, data: D): R { @@ -103,7 +101,7 @@ abstract class ControlFlowGraphVisitor { } open fun visitDelegateExpressionExitNode(node: DelegateExpressionExitNode, data: D): R { - return visitUnionNode(node, data) + return visitNode(node, data) } // ----------------------------------- Field ----------------------------------- @@ -296,7 +294,7 @@ abstract class ControlFlowGraphVisitor { // ----------------------------------- Check not null call ----------------------------------- open fun visitCheckNotNullCallNode(node: CheckNotNullCallNode, data: D): R { - return visitUnionNode(node, data) + return visitNode(node, data) } // ----------------------------------- Resolvable call ----------------------------------- @@ -310,7 +308,7 @@ abstract class ControlFlowGraphVisitor { } open fun visitFunctionCallNode(node: FunctionCallNode, data: D): R { - return visitUnionNode(node, data) + return visitNode(node, data) } open fun visitCallableReferenceNode(node: CallableReferenceNode, data: D): R { @@ -322,11 +320,11 @@ abstract class ControlFlowGraphVisitor { } open fun visitDelegatedConstructorCallNode(node: DelegatedConstructorCallNode, data: D): R { - return visitUnionNode(node, data) + return visitNode(node, data) } open fun visitStringConcatenationCallNode(node: StringConcatenationCallNode, data: D): R { - return visitUnionNode(node, data) + return visitNode(node, data) } open fun visitThrowExceptionNode(node: ThrowExceptionNode, data: D): R { diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt index 4daa005f205..6066672a982 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitorVoid.kt @@ -8,8 +8,6 @@ package org.jetbrains.kotlin.fir.resolve.dfa.cfg abstract class ControlFlowGraphVisitorVoid : ControlFlowGraphVisitor() { abstract fun visitNode(node: CFGNode<*>) - abstract fun visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker - // ----------------------------------- Simple function ----------------------------------- open fun visitFunctionEnterNode(node: FunctionEnterNode) { @@ -53,7 +51,7 @@ abstract class ControlFlowGraphVisitorVoid : ControlFlowGraphVisitor visitUnionNode(node: T, data: Nothing?) where T : CFGNode<*>, T : UnionNodeMarker { - visitUnionNode(node) - } - // ----------------------------------- Simple function ----------------------------------- final override fun visitFunctionEnterNode(node: FunctionEnterNode, data: Nothing?) {