FIR: Introduce DataFlowAnalyzerContext
This commit is contained in:
+56
-36
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
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.ConeBooleanConstantReference
|
||||||
import org.jetbrains.kotlin.fir.contracts.description.ConeConditionalEffectDeclaration
|
import org.jetbrains.kotlin.fir.contracts.description.ConeConditionalEffectDeclaration
|
||||||
import org.jetbrains.kotlin.fir.contracts.description.ConeConstantReference
|
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.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class DataFlowAnalyzerContext<FLOW : Flow>(
|
||||||
|
val graphBuilder: ControlFlowGraphBuilder,
|
||||||
|
val variableStorage: VariableStorage,
|
||||||
|
val flowOnNodes: MutableMap<CFGNode<*>, FLOW>,
|
||||||
|
val variablesForWhenConditions: MutableMap<WhenBranchConditionExitNode, DataFlowVariable>
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun <FLOW : Flow> empty(session: FirSession) =
|
||||||
|
DataFlowAnalyzerContext<FLOW>(
|
||||||
|
ControlFlowGraphBuilder(), VariableStorage(session),
|
||||||
|
mutableMapOf(), mutableMapOf()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(DfaInternals::class)
|
@OptIn(DfaInternals::class)
|
||||||
abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||||
protected val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents
|
protected val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents,
|
||||||
|
private val context: DataFlowAnalyzerContext<FLOW>
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
internal val KOTLIN_BOOLEAN_NOT = CallableId(FqName("kotlin"), FqName("Boolean"), Name.identifier("not"))
|
internal val KOTLIN_BOOLEAN_NOT = CallableId(FqName("kotlin"), FqName("Boolean"), Name.identifier("not"))
|
||||||
|
|
||||||
fun createFirDataFlowAnalyzer(
|
fun createFirDataFlowAnalyzer(
|
||||||
components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents
|
components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents,
|
||||||
): FirDataFlowAnalyzer<*> = object : FirDataFlowAnalyzer<PersistentFlow>(components) {
|
dataFlowAnalyzerContext: DataFlowAnalyzerContext<PersistentFlow>
|
||||||
private val receiverStack: ImplicitReceiverStackImpl
|
): FirDataFlowAnalyzer<*> =
|
||||||
get() = components.implicitReceiverStack as ImplicitReceiverStackImpl
|
object : FirDataFlowAnalyzer<PersistentFlow>(components, dataFlowAnalyzerContext) {
|
||||||
|
private val receiverStack: ImplicitReceiverStackImpl
|
||||||
|
get() = components.implicitReceiverStack as ImplicitReceiverStackImpl
|
||||||
|
|
||||||
override val logicSystem: PersistentLogicSystem = object : PersistentLogicSystem(components.inferenceComponents.ctx) {
|
override val logicSystem: PersistentLogicSystem = object : PersistentLogicSystem(components.inferenceComponents.ctx) {
|
||||||
override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) {
|
override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) {
|
||||||
val symbol = variable.identifier.symbol
|
val symbol = variable.identifier.symbol
|
||||||
|
|
||||||
val index = receiverStack.getReceiverIndex(symbol) ?: return
|
val index = receiverStack.getReceiverIndex(symbol) ?: return
|
||||||
val info = flow.getTypeStatement(variable)
|
val info = flow.getTypeStatement(variable)
|
||||||
|
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
receiverStack.replaceReceiverType(index, receiverStack.getOriginalType(index))
|
receiverStack.replaceReceiverType(index, receiverStack.getOriginalType(index))
|
||||||
} else {
|
} else {
|
||||||
val types = info.exactType.toMutableList().also {
|
val types = info.exactType.toMutableList().also {
|
||||||
it += receiverStack.getOriginalType(index)
|
it += receiverStack.getOriginalType(index)
|
||||||
|
}
|
||||||
|
receiverStack.replaceReceiverType(index, context.intersectTypesOrNull(types)!!)
|
||||||
}
|
}
|
||||||
receiverStack.replaceReceiverType(index, context.intersectTypesOrNull(types)!!)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateAllReceivers(flow: PersistentFlow) {
|
override fun updateAllReceivers(flow: PersistentFlow) {
|
||||||
receiverStack.forEach {
|
receiverStack.forEach {
|
||||||
variableStorage.getRealVariable(it.boundSymbol, it.receiverExpression, flow)?.let { variable ->
|
variableStorage.getRealVariable(it.boundSymbol, it.receiverExpression, flow)?.let { variable ->
|
||||||
processUpdatedReceiverVariable(flow, variable)
|
processUpdatedReceiverVariable(flow, variable)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract val logicSystem: LogicSystem<FLOW>
|
protected abstract val logicSystem: LogicSystem<FLOW>
|
||||||
private val context: ConeInferenceContext = components.inferenceComponents.ctx
|
|
||||||
|
|
||||||
private val graphBuilder = ControlFlowGraphBuilder()
|
private val graphBuilder get() = context.graphBuilder
|
||||||
protected val variableStorage: VariableStorage = VariableStorage(components.session)
|
protected val variableStorage get() = context.variableStorage
|
||||||
private val flowOnNodes = mutableMapOf<CFGNode<*>, FLOW>()
|
|
||||||
|
|
||||||
private val variablesForWhenConditions = mutableMapOf<WhenBranchConditionExitNode, DataFlowVariable>()
|
|
||||||
|
|
||||||
private var contractDescriptionVisitingMode = false
|
private var contractDescriptionVisitingMode = false
|
||||||
|
|
||||||
@@ -129,7 +144,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (graphBuilder.isTopLevel()) {
|
if (graphBuilder.isTopLevel()) {
|
||||||
flowOnNodes.clear()
|
context.flowOnNodes.clear()
|
||||||
variableStorage.reset()
|
variableStorage.reset()
|
||||||
graphBuilder.reset()
|
graphBuilder.reset()
|
||||||
}
|
}
|
||||||
@@ -388,7 +403,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
val node = graphBuilder.enterWhenBranchCondition(whenBranch).mergeIncomingFlow(updateReceivers = true)
|
val node = graphBuilder.enterWhenBranchCondition(whenBranch).mergeIncomingFlow(updateReceivers = true)
|
||||||
val previousNode = node.previousNodes.single()
|
val previousNode = node.previousNodes.single()
|
||||||
if (previousNode is WhenBranchConditionExitNode) {
|
if (previousNode is WhenBranchConditionExitNode) {
|
||||||
val conditionVariable = variablesForWhenConditions.remove(previousNode)!!
|
val conditionVariable = context.variablesForWhenConditions.remove(previousNode)!!
|
||||||
node.flow = logicSystem.approveStatementsInsideFlow(
|
node.flow = logicSystem.approveStatementsInsideFlow(
|
||||||
node.flow,
|
node.flow,
|
||||||
conditionVariable eq false,
|
conditionVariable eq false,
|
||||||
@@ -404,7 +419,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
|
|
||||||
val conditionExitFlow = conditionExitNode.flow
|
val conditionExitFlow = conditionExitNode.flow
|
||||||
val conditionVariable = variableStorage.getOrCreateVariable(conditionExitFlow, whenBranch.condition)
|
val conditionVariable = variableStorage.getOrCreateVariable(conditionExitFlow, whenBranch.condition)
|
||||||
variablesForWhenConditions[conditionExitNode] = conditionVariable
|
context.variablesForWhenConditions[conditionExitNode] = conditionVariable
|
||||||
branchEnterNode.flow = logicSystem.approveStatementsInsideFlow(
|
branchEnterNode.flow = logicSystem.approveStatementsInsideFlow(
|
||||||
conditionExitFlow,
|
conditionExitFlow,
|
||||||
conditionVariable eq true,
|
conditionVariable eq true,
|
||||||
@@ -424,7 +439,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
// previous node for syntheticElseNode can be not WhenBranchConditionExitNode in case of `when` without any branches
|
// 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
|
// in that case there will be when enter or subject access node
|
||||||
if (previousConditionExitNode != null) {
|
if (previousConditionExitNode != null) {
|
||||||
val conditionVariable = variablesForWhenConditions.remove(previousConditionExitNode)!!
|
val conditionVariable = context.variablesForWhenConditions.remove(previousConditionExitNode)!!
|
||||||
syntheticElseNode.flow = logicSystem.approveStatementsInsideFlow(
|
syntheticElseNode.flow = logicSystem.approveStatementsInsideFlow(
|
||||||
previousConditionExitNode.flow,
|
previousConditionExitNode.flow,
|
||||||
conditionVariable eq false,
|
conditionVariable eq false,
|
||||||
@@ -713,7 +728,12 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
exitVariableInitialization(node, assignment.rValue, property, assignment)
|
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 flow = node.flow
|
||||||
val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias(flow, property.symbol, assignment ?: property)
|
val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias(flow, property.symbol, assignment ?: property)
|
||||||
val isAssignment = assignment != null
|
val isAssignment = assignment != null
|
||||||
@@ -905,9 +925,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
// ------------------------------------------------------ Utils ------------------------------------------------------
|
// ------------------------------------------------------ Utils ------------------------------------------------------
|
||||||
|
|
||||||
private var CFGNode<*>.flow: FLOW
|
private var CFGNode<*>.flow: FLOW
|
||||||
get() = flowOnNodes.getValue(this.origin)
|
get() = context.flowOnNodes.getValue(this.origin)
|
||||||
set(value) {
|
set(value) {
|
||||||
flowOnNodes[this.origin] = value
|
context.flowOnNodes[this.origin] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private val CFGNode<*>.origin: CFGNode<*> get() = if (this is StubNode) firstPreviousNode else this
|
private val CFGNode<*>.origin: CFGNode<*> get() = if (this is StubNode) firstPreviousNode else this
|
||||||
@@ -941,7 +961,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
return logicSystem.forkFlow(this)
|
return logicSystem.forkFlow(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val CFGNode<*>.previousFlow : FLOW
|
private val CFGNode<*>.previousFlow: FLOW
|
||||||
get() = firstPreviousNode.flow
|
get() = firstPreviousNode.flow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -10,7 +10,9 @@ import org.jetbrains.kotlin.fir.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionStageRunner
|
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.FirDataFlowAnalyzer
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.dfa.PersistentFlow
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter
|
import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
|
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
||||||
@@ -101,6 +103,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
|
|||||||
|
|
||||||
class BodyResolveContext(
|
class BodyResolveContext(
|
||||||
val returnTypeCalculator: ReturnTypeCalculator,
|
val returnTypeCalculator: ReturnTypeCalculator,
|
||||||
|
val dataFlowAnalyzerContext: DataFlowAnalyzerContext<PersistentFlow>,
|
||||||
val targetedLocalClasses: Set<FirClass<*>> = emptySet()
|
val targetedLocalClasses: Set<FirClass<*>> = emptySet()
|
||||||
) {
|
) {
|
||||||
val fileImportsScope: MutableList<FirScope> = mutableListOf()
|
val fileImportsScope: MutableList<FirScope> = mutableListOf()
|
||||||
@@ -197,7 +200,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
|
|||||||
fun createSnapshotForLocalClasses(
|
fun createSnapshotForLocalClasses(
|
||||||
returnTypeCalculator: ReturnTypeCalculator,
|
returnTypeCalculator: ReturnTypeCalculator,
|
||||||
targetedLocalClasses: Set<FirClass<*>>
|
targetedLocalClasses: Set<FirClass<*>>
|
||||||
) = BodyResolveContext(returnTypeCalculator, targetedLocalClasses).apply {
|
) = BodyResolveContext(returnTypeCalculator, dataFlowAnalyzerContext, targetedLocalClasses).apply {
|
||||||
fileImportsScope.addAll(this@BodyResolveContext.fileImportsScope)
|
fileImportsScope.addAll(this@BodyResolveContext.fileImportsScope)
|
||||||
typeParametersScopes = this@BodyResolveContext.typeParametersScopes
|
typeParametersScopes = this@BodyResolveContext.typeParametersScopes
|
||||||
localScopes = this@BodyResolveContext.localScopes
|
localScopes = this@BodyResolveContext.localScopes
|
||||||
@@ -239,7 +242,8 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
|
|||||||
FirTypeResolveScopeForBodyResolve(this), session
|
FirTypeResolveScopeForBodyResolve(this), session
|
||||||
)
|
)
|
||||||
override val callCompleter: FirCallCompleter = FirCallCompleter(transformer, this)
|
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 syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(this)
|
||||||
override val integerLiteralTypeApproximator: IntegerLiteralTypeApproximationTransformer =
|
override val integerLiteralTypeApproximator: IntegerLiteralTypeApproximationTransformer =
|
||||||
IntegerLiteralTypeApproximationTransformer(symbolProvider, inferenceComponents.ctx)
|
IntegerLiteralTypeApproximationTransformer(symbolProvider, inferenceComponents.ctx)
|
||||||
|
|||||||
+3
-1
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.*
|
|||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
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.ReturnTypeCalculator
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFullBodyResolve
|
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFullBodyResolve
|
||||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||||
@@ -31,7 +32,8 @@ open class FirBodyResolveTransformer(
|
|||||||
) : FirAbstractBodyResolveTransformer(phase) {
|
) : FirAbstractBodyResolveTransformer(phase) {
|
||||||
private var packageFqName = FqName.ROOT
|
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 =
|
final override val components: BodyResolveTransformerComponents =
|
||||||
BodyResolveTransformerComponents(session, scopeSession, this, context)
|
BodyResolveTransformerComponents(session, scopeSession, this, context)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user