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.
This commit is contained in:
+1
-3
@@ -158,8 +158,6 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
|
||||
|
||||
override fun visitNode(node: CFGNode<*>, data: IllegalScopeContext) {}
|
||||
|
||||
override fun <T> 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
|
||||
|
||||
+2
-4
@@ -51,10 +51,8 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
|
||||
val reporter: DiagnosticReporter,
|
||||
val context: CheckerContext
|
||||
) : ControlFlowGraphVisitorVoid() {
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
|
||||
override fun <T> 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({}, {}).
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ private fun <I : ControlFlowInfo<I, *, *>> 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) {
|
||||
|
||||
-2
@@ -34,8 +34,6 @@ class LocalPropertyAndCapturedWriteCollector private constructor() : ControlFlow
|
||||
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
|
||||
override fun <T> visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {}
|
||||
|
||||
override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
|
||||
symbols[node.fir.symbol] = lambdaOrLocalFunctionStack.lastOrNull() == null
|
||||
}
|
||||
|
||||
-5
@@ -65,9 +65,4 @@ abstract class PathAwareControlFlowGraphVisitor<I : ControlFlowInfo<I, *, *>> :
|
||||
node: CFGNode<*>,
|
||||
data: PathAwareControlFlowInfo<I>
|
||||
): PathAwareControlFlowInfo<I> = data
|
||||
|
||||
override fun <T> visitUnionNode(
|
||||
node: T,
|
||||
data: PathAwareControlFlowInfo<I>
|
||||
): PathAwareControlFlowInfo<I> where T : CFGNode<*>, T : UnionNodeMarker = data
|
||||
}
|
||||
|
||||
-2
@@ -40,8 +40,6 @@ object FirTailrecFunctionChecker : FirSimpleFunctionChecker() {
|
||||
graph.traverse(object : ControlFlowGraphVisitorVoid() {
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
|
||||
override fun <T> visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {}
|
||||
|
||||
override fun visitTryMainBlockEnterNode(node: TryMainBlockEnterNode) {
|
||||
tryScopeCount++
|
||||
}
|
||||
|
||||
-2
@@ -82,8 +82,6 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
|
||||
) : ControlFlowGraphVisitorVoid() {
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
|
||||
override fun <T> 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
|
||||
|
||||
+1
-9
@@ -50,8 +50,6 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
) : ControlFlowGraphVisitorVoid() {
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
|
||||
override fun <T> 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 <T> 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") {
|
||||
|
||||
Reference in New Issue
Block a user