From f119839891d6756e1a2bb4272241b7ee70064a33 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 20 Mar 2020 14:36:29 +0300 Subject: [PATCH] FIR: Introduce DataFlowAnalyzerContext --- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 92 +++++++++++-------- .../FirAbstractBodyResolveTransformer.kt | 8 +- .../body/resolve/FirBodyResolveTransformer.kt | 4 +- 3 files changed, 65 insertions(+), 39 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 01e7cdfb302..65e48e34897 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 @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.contracts.description.ConeBooleanConstantReference import org.jetbrains.kotlin.fir.contracts.description.ConeConditionalEffectDeclaration import org.jetbrains.kotlin.fir.contracts.description.ConeConstantReference @@ -29,55 +30,69 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +class DataFlowAnalyzerContext( + val graphBuilder: ControlFlowGraphBuilder, + val variableStorage: VariableStorage, + val flowOnNodes: MutableMap, FLOW>, + val variablesForWhenConditions: MutableMap +) { + companion object { + fun empty(session: FirSession) = + DataFlowAnalyzerContext( + ControlFlowGraphBuilder(), VariableStorage(session), + mutableMapOf(), mutableMapOf() + ) + } +} + @OptIn(DfaInternals::class) abstract class FirDataFlowAnalyzer( - protected val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents + protected val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents, + private val context: DataFlowAnalyzerContext ) { companion object { internal val KOTLIN_BOOLEAN_NOT = CallableId(FqName("kotlin"), FqName("Boolean"), Name.identifier("not")) fun createFirDataFlowAnalyzer( - components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents - ): FirDataFlowAnalyzer<*> = object : FirDataFlowAnalyzer(components) { - private val receiverStack: ImplicitReceiverStackImpl - get() = components.implicitReceiverStack as ImplicitReceiverStackImpl + components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents, + dataFlowAnalyzerContext: DataFlowAnalyzerContext + ): FirDataFlowAnalyzer<*> = + object : FirDataFlowAnalyzer(components, dataFlowAnalyzerContext) { + private val receiverStack: ImplicitReceiverStackImpl + get() = components.implicitReceiverStack as ImplicitReceiverStackImpl - override val logicSystem: PersistentLogicSystem = object : PersistentLogicSystem(components.inferenceComponents.ctx) { - override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) { - val symbol = variable.identifier.symbol + override val logicSystem: PersistentLogicSystem = object : PersistentLogicSystem(components.inferenceComponents.ctx) { + override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) { + val symbol = variable.identifier.symbol - val index = receiverStack.getReceiverIndex(symbol) ?: return - val info = flow.getTypeStatement(variable) + val index = receiverStack.getReceiverIndex(symbol) ?: return + val info = flow.getTypeStatement(variable) - if (info == null) { - receiverStack.replaceReceiverType(index, receiverStack.getOriginalType(index)) - } else { - val types = info.exactType.toMutableList().also { - it += receiverStack.getOriginalType(index) + if (info == null) { + receiverStack.replaceReceiverType(index, receiverStack.getOriginalType(index)) + } else { + val types = info.exactType.toMutableList().also { + it += receiverStack.getOriginalType(index) + } + receiverStack.replaceReceiverType(index, context.intersectTypesOrNull(types)!!) } - receiverStack.replaceReceiverType(index, context.intersectTypesOrNull(types)!!) } - } - override fun updateAllReceivers(flow: PersistentFlow) { - receiverStack.forEach { - variableStorage.getRealVariable(it.boundSymbol, it.receiverExpression, flow)?.let { variable -> - processUpdatedReceiverVariable(flow, variable) + override fun updateAllReceivers(flow: PersistentFlow) { + receiverStack.forEach { + variableStorage.getRealVariable(it.boundSymbol, it.receiverExpression, flow)?.let { variable -> + processUpdatedReceiverVariable(flow, variable) + } } } } } - } } protected abstract val logicSystem: LogicSystem - private val context: ConeInferenceContext = components.inferenceComponents.ctx - private val graphBuilder = ControlFlowGraphBuilder() - protected val variableStorage: VariableStorage = VariableStorage(components.session) - private val flowOnNodes = mutableMapOf, FLOW>() - - private val variablesForWhenConditions = mutableMapOf() + private val graphBuilder get() = context.graphBuilder + protected val variableStorage get() = context.variableStorage private var contractDescriptionVisitingMode = false @@ -129,7 +144,7 @@ abstract class FirDataFlowAnalyzer( } } if (graphBuilder.isTopLevel()) { - flowOnNodes.clear() + context.flowOnNodes.clear() variableStorage.reset() graphBuilder.reset() } @@ -388,7 +403,7 @@ abstract class FirDataFlowAnalyzer( val node = graphBuilder.enterWhenBranchCondition(whenBranch).mergeIncomingFlow(updateReceivers = true) val previousNode = node.previousNodes.single() if (previousNode is WhenBranchConditionExitNode) { - val conditionVariable = variablesForWhenConditions.remove(previousNode)!! + val conditionVariable = context.variablesForWhenConditions.remove(previousNode)!! node.flow = logicSystem.approveStatementsInsideFlow( node.flow, conditionVariable eq false, @@ -404,7 +419,7 @@ abstract class FirDataFlowAnalyzer( val conditionExitFlow = conditionExitNode.flow val conditionVariable = variableStorage.getOrCreateVariable(conditionExitFlow, whenBranch.condition) - variablesForWhenConditions[conditionExitNode] = conditionVariable + context.variablesForWhenConditions[conditionExitNode] = conditionVariable branchEnterNode.flow = logicSystem.approveStatementsInsideFlow( conditionExitFlow, conditionVariable eq true, @@ -424,7 +439,7 @@ abstract class FirDataFlowAnalyzer( // previous node for syntheticElseNode can be not WhenBranchConditionExitNode in case of `when` without any branches // in that case there will be when enter or subject access node if (previousConditionExitNode != null) { - val conditionVariable = variablesForWhenConditions.remove(previousConditionExitNode)!! + val conditionVariable = context.variablesForWhenConditions.remove(previousConditionExitNode)!! syntheticElseNode.flow = logicSystem.approveStatementsInsideFlow( previousConditionExitNode.flow, conditionVariable eq false, @@ -713,7 +728,12 @@ abstract class FirDataFlowAnalyzer( exitVariableInitialization(node, assignment.rValue, property, assignment) } - private fun exitVariableInitialization(node: CFGNode<*>, initializer: FirExpression, property: FirProperty, assignment: FirVariableAssignment?) { + private fun exitVariableInitialization( + node: CFGNode<*>, + initializer: FirExpression, + property: FirProperty, + assignment: FirVariableAssignment? + ) { val flow = node.flow val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias(flow, property.symbol, assignment ?: property) val isAssignment = assignment != null @@ -905,9 +925,9 @@ abstract class FirDataFlowAnalyzer( // ------------------------------------------------------ Utils ------------------------------------------------------ private var CFGNode<*>.flow: FLOW - get() = flowOnNodes.getValue(this.origin) + get() = context.flowOnNodes.getValue(this.origin) set(value) { - flowOnNodes[this.origin] = value + context.flowOnNodes[this.origin] = value } private val CFGNode<*>.origin: CFGNode<*> get() = if (this is StubNode) firstPreviousNode else this @@ -941,7 +961,7 @@ abstract class FirDataFlowAnalyzer( return logicSystem.forkFlow(this) } - private val CFGNode<*>.previousFlow : FLOW + private val CFGNode<*>.previousFlow: FLOW get() = firstPreviousNode.flow } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt index 2d79e068d71..978d9263673 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt @@ -10,7 +10,9 @@ import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.ResolutionStageRunner +import org.jetbrains.kotlin.fir.resolve.dfa.DataFlowAnalyzerContext import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer +import org.jetbrains.kotlin.fir.resolve.dfa.PersistentFlow import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents import org.jetbrains.kotlin.fir.resolve.transformers.* @@ -101,6 +103,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb class BodyResolveContext( val returnTypeCalculator: ReturnTypeCalculator, + val dataFlowAnalyzerContext: DataFlowAnalyzerContext, val targetedLocalClasses: Set> = emptySet() ) { val fileImportsScope: MutableList = mutableListOf() @@ -197,7 +200,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb fun createSnapshotForLocalClasses( returnTypeCalculator: ReturnTypeCalculator, targetedLocalClasses: Set> - ) = BodyResolveContext(returnTypeCalculator, targetedLocalClasses).apply { + ) = BodyResolveContext(returnTypeCalculator, dataFlowAnalyzerContext, targetedLocalClasses).apply { fileImportsScope.addAll(this@BodyResolveContext.fileImportsScope) typeParametersScopes = this@BodyResolveContext.typeParametersScopes localScopes = this@BodyResolveContext.localScopes @@ -239,7 +242,8 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb FirTypeResolveScopeForBodyResolve(this), session ) override val callCompleter: FirCallCompleter = FirCallCompleter(transformer, this) - override val dataFlowAnalyzer: FirDataFlowAnalyzer<*> = FirDataFlowAnalyzer.createFirDataFlowAnalyzer(this) + override val dataFlowAnalyzer: FirDataFlowAnalyzer<*> = + FirDataFlowAnalyzer.createFirDataFlowAnalyzer(this, context.dataFlowAnalyzerContext) override val syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(this) override val integerLiteralTypeApproximator: IntegerLiteralTypeApproximationTransformer = IntegerLiteralTypeApproximationTransformer(symbolProvider, inferenceComponents.ctx) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt index a8e8943b002..88aaaabe81e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.dfa.DataFlowAnalyzerContext import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFullBodyResolve import org.jetbrains.kotlin.fir.scopes.addImportingScopes @@ -31,7 +32,8 @@ open class FirBodyResolveTransformer( ) : FirAbstractBodyResolveTransformer(phase) { private var packageFqName = FqName.ROOT - final override val context: BodyResolveContext = outerBodyResolveContext ?: BodyResolveContext(returnTypeCalculator) + final override val context: BodyResolveContext = + outerBodyResolveContext ?: BodyResolveContext(returnTypeCalculator, DataFlowAnalyzerContext.empty(session)) final override val components: BodyResolveTransformerComponents = BodyResolveTransformerComponents(session, scopeSession, this, context)