FIR DFA: clean up LogicSystem API

Receivers have nothing to do with it.
This commit is contained in:
pyos
2022-11-09 20:48:07 +01:00
committed by teamcity
parent 1506c493c8
commit 5796f0eb07
5 changed files with 84 additions and 106 deletions
@@ -9,10 +9,8 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
import org.jetbrains.kotlin.fir.resolve.dfa.LogicSystem import org.jetbrains.kotlin.fir.resolve.dfa.*
import org.jetbrains.kotlin.fir.resolve.dfa.PersistentFlow
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveContext import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveContext
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
@@ -54,6 +52,12 @@ internal open class StubBodyResolveTransformerComponents(
override val logicSystem: LogicSystem<PersistentFlow> override val logicSystem: LogicSystem<PersistentFlow>
get() = error("Should not be called") get() = error("Should not be called")
override val receiverStack: Iterable<ImplicitReceiverValue<*>>
get() = error("Should not be called")
override fun receiverUpdated(symbol: FirBasedSymbol<*>, types: Set<ConeKotlinType>?) =
error("Should not be called")
override fun getTypeUsingSmartcastInfo( override fun getTypeUsingSmartcastInfo(
symbol: FirBasedSymbol<*>, symbol: FirBasedSymbol<*>,
expression: FirExpression expression: FirExpression
@@ -51,12 +51,6 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
override val variableStorage: VariableStorageImpl override val variableStorage: VariableStorageImpl
get() = dataFlowInfo.variableStorage as VariableStorageImpl get() = dataFlowInfo.variableStorage as VariableStorageImpl
override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) =
throw IllegalStateException("Receiver variable update is not possible for this logic system")
override fun updateAllReceivers(flow: PersistentFlow) =
throw IllegalStateException("Update of all receivers is not possible for this logic system")
override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean { override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean {
return !isNullableNothing return !isNullableNothing
} }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.* import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.resolve.dfa.contracts.buildContractFir import org.jetbrains.kotlin.fir.resolve.dfa.contracts.buildContractFir
import org.jetbrains.kotlin.fir.resolve.dfa.contracts.createArgumentsMapping import org.jetbrains.kotlin.fir.resolve.dfa.contracts.createArgumentsMapping
@@ -92,39 +93,28 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
dataFlowAnalyzerContext: DataFlowAnalyzerContext<PersistentFlow> dataFlowAnalyzerContext: DataFlowAnalyzerContext<PersistentFlow>
): FirDataFlowAnalyzer<*> = ): FirDataFlowAnalyzer<*> =
object : FirDataFlowAnalyzer<PersistentFlow>(components, dataFlowAnalyzerContext) { object : FirDataFlowAnalyzer<PersistentFlow>(components, dataFlowAnalyzerContext) {
private val receiverStack: PersistentImplicitReceiverStack override val receiverStack: PersistentImplicitReceiverStack
get() = components.implicitReceiverStack as PersistentImplicitReceiverStack get() = components.implicitReceiverStack as PersistentImplicitReceiverStack
private val visibilityChecker = components.session.visibilityChecker private val visibilityChecker = components.session.visibilityChecker
private val typeContext = components.session.typeContext
override fun receiverUpdated(symbol: FirBasedSymbol<*>, types: Set<ConeKotlinType>?) {
val index = receiverStack.getReceiverIndex(symbol) ?: return
val originalType = receiverStack.getOriginalType(index)
val type = if (types?.isNotEmpty() == true) {
typeContext.intersectTypes(types.toMutableList().also { it += originalType })
} else {
originalType
}
receiverStack.replaceReceiverType(index, type)
}
override val logicSystem: PersistentLogicSystem = override val logicSystem: PersistentLogicSystem =
object : PersistentLogicSystem(components.session.typeContext) { object : PersistentLogicSystem(components.session.typeContext) {
override val variableStorage: VariableStorageImpl override val variableStorage: VariableStorageImpl
get() = dataFlowAnalyzerContext.variableStorage get() = dataFlowAnalyzerContext.variableStorage
override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) {
val symbol = variable.identifier.symbol
val index = receiverStack.getReceiverIndex(symbol) ?: return
val info = flow.getType(variable)
val type = if (info?.isNotEmpty() == true) {
val types = info.toMutableList()
types += receiverStack.getOriginalType(index)
context.intersectTypesOrNull(types)!!
} else {
receiverStack.getOriginalType(index)
}
receiverStack.replaceReceiverType(index, type)
}
override fun updateAllReceivers(flow: PersistentFlow) {
receiverStack.forEach {
variableStorage.getRealVariable(flow, it.boundSymbol, it.receiverExpression)?.let { variable ->
processUpdatedReceiverVariable(flow, variable)
}
}
}
override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean { override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean {
if (this.isNullableNothing) return false if (this.isNullableNothing) return false
return when (this) { return when (this) {
@@ -151,6 +141,8 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
protected abstract val logicSystem: LogicSystem<FLOW> protected abstract val logicSystem: LogicSystem<FLOW>
protected abstract val receiverStack: Iterable<ImplicitReceiverValue<*>>
protected abstract fun receiverUpdated(symbol: FirBasedSymbol<*>, types: Set<ConeKotlinType>?)
private val graphBuilder get() = context.graphBuilder private val graphBuilder get() = context.graphBuilder
private val variableStorage get() = context.variableStorage private val variableStorage get() = context.variableStorage
@@ -263,7 +255,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
if (graphBuilder.isTopLevel()) { if (graphBuilder.isTopLevel()) {
context.reset() context.reset()
} else { } else {
logicSystem.updateAllReceivers(graph.enterNode.flow) resetReceivers(graph.enterNode.flow)
} }
return FirControlFlowGraphReferenceImpl(graph, DataFlowInfo(variableStorage, flowOnNodes)) return FirControlFlowGraphReferenceImpl(graph, DataFlowInfo(variableStorage, flowOnNodes))
} }
@@ -285,7 +277,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
enterCapturingStatement(functionEnterNode, anonymousFunction) enterCapturingStatement(functionEnterNode, anonymousFunction)
else -> {} else -> {}
} }
logicSystem.updateAllReceivers(flowOnEntry) resetReceivers(flowOnEntry)
} }
private fun exitAnonymousFunction(anonymousFunction: FirAnonymousFunction): FirControlFlowGraphReference { private fun exitAnonymousFunction(anonymousFunction: FirAnonymousFunction): FirControlFlowGraphReference {
@@ -302,7 +294,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
functionExitNode.mergeIncomingFlow() functionExitNode.mergeIncomingFlow()
postponedLambdaExitNode?.mergeIncomingFlow() postponedLambdaExitNode?.mergeIncomingFlow()
logicSystem.updateAllReceivers(graph.enterNode.flow) resetReceivers(graph.enterNode.flow)
return FirControlFlowGraphReferenceImpl(graph) return FirControlFlowGraphReferenceImpl(graph)
} }
@@ -444,7 +436,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
flow.addTypeStatement(operandVariable typeEq type) flow.addTypeStatement(operandVariable typeEq type)
} }
if (!type.canBeNull) { if (!type.canBeNull) {
flow.assumeNotNull(operandVariable, shouldRemoveSynthetics = true) flow.commitOperationStatement(operandVariable notEq null, shouldRemoveSynthetics = true)
} else { } else {
val expressionVariable = variableStorage.createSyntheticVariable(typeOperatorCall) val expressionVariable = variableStorage.createSyntheticVariable(typeOperatorCall)
flow.addImplication((expressionVariable notEq null) implies (operandVariable notEq null)) flow.addImplication((expressionVariable notEq null) implies (operandVariable notEq null))
@@ -669,17 +661,10 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
// Add `Any` to the set of possible types; the intersection type `T? & Any` will be reduced to `T` after smartcast. // Add `Any` to the set of possible types; the intersection type `T? & Any` will be reduced to `T` after smartcast.
val (node, unionNode) = graphBuilder.exitCheckNotNullCall(checkNotNullCall, callCompleted) val (node, unionNode) = graphBuilder.exitCheckNotNullCall(checkNotNullCall, callCompleted)
val argumentVariable = variableStorage.getOrCreateVariable(node.previousFlow, checkNotNullCall.argument) val argumentVariable = variableStorage.getOrCreateVariable(node.previousFlow, checkNotNullCall.argument)
node.mergeIncomingFlow().assumeNotNull(argumentVariable, shouldRemoveSynthetics = false) node.mergeIncomingFlow().commitOperationStatement(argumentVariable notEq null, shouldRemoveSynthetics = false)
unionNode?.unionFlowFromArguments() unionNode?.unionFlowFromArguments()
} }
private fun FLOW.assumeNotNull(variable: DataFlowVariable, shouldRemoveSynthetics: Boolean) {
logicSystem.commitOperationStatement(this, variable notEq null, shouldRemoveSynthetics)
if (variable is RealVariable) {
addTypeStatement(variable typeEq any)
}
}
// ----------------------------------- When ----------------------------------- // ----------------------------------- When -----------------------------------
fun enterWhenExpression(whenExpression: FirWhenExpression) { fun enterWhenExpression(whenExpression: FirWhenExpression) {
@@ -692,7 +677,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val previousNode = node.previousNodes.single() val previousNode = node.previousNodes.single()
if (previousNode is WhenBranchConditionExitNode) { if (previousNode is WhenBranchConditionExitNode) {
val conditionVariable = context.variablesForWhenConditions.remove(previousNode)!! val conditionVariable = context.variablesForWhenConditions.remove(previousNode)!!
logicSystem.commitOperationStatement(flow, conditionVariable eq false, shouldRemoveSynthetics = true) flow.commitOperationStatement(conditionVariable eq false, shouldRemoveSynthetics = true)
} }
} }
@@ -702,7 +687,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val conditionVariable = variableStorage.getOrCreateVariable(conditionExitFlow, whenBranch.condition) val conditionVariable = variableStorage.getOrCreateVariable(conditionExitFlow, whenBranch.condition)
context.variablesForWhenConditions[conditionExitNode] = conditionVariable context.variablesForWhenConditions[conditionExitNode] = conditionVariable
branchEnterNode.flow = conditionExitFlow.fork().also { branchEnterNode.flow = conditionExitFlow.fork().also {
logicSystem.commitOperationStatement(it, conditionVariable eq true, shouldRemoveSynthetics = false) it.commitOperationStatement(conditionVariable eq true, shouldRemoveSynthetics = false)
} }
} }
@@ -719,7 +704,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
if (previousConditionExitNode != null) { if (previousConditionExitNode != null) {
val conditionVariable = context.variablesForWhenConditions.remove(previousConditionExitNode)!! val conditionVariable = context.variablesForWhenConditions.remove(previousConditionExitNode)!!
syntheticElseNode.flow = previousConditionExitNode.flow.fork().also { syntheticElseNode.flow = previousConditionExitNode.flow.fork().also {
logicSystem.commitOperationStatement(it, conditionVariable eq false, shouldRemoveSynthetics = true) it.commitOperationStatement(conditionVariable eq false, shouldRemoveSynthetics = true)
} }
} else { } else {
syntheticElseNode.mergeIncomingFlow() syntheticElseNode.mergeIncomingFlow()
@@ -739,7 +724,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val singlePreviousNode = exitNode.previousNodes.singleOrNull { !it.isDead } val singlePreviousNode = exitNode.previousNodes.singleOrNull { !it.isDead }
if (singlePreviousNode is LoopConditionExitNode) { if (singlePreviousNode is LoopConditionExitNode) {
val variable = variableStorage.getOrCreateVariable(exitNode.previousFlow, singlePreviousNode.fir) val variable = variableStorage.getOrCreateVariable(exitNode.previousFlow, singlePreviousNode.fir)
logicSystem.commitOperationStatement(exitNode.flow, variable eq false, shouldRemoveSynthetics = true) exitNode.flow.commitOperationStatement(variable eq false, shouldRemoveSynthetics = true)
} }
exitCapturingStatement(exitNode.fir) exitCapturingStatement(exitNode.fir)
} }
@@ -757,7 +742,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
loopBlockEnterNode.flow = conditionExitFlow.fork().also { loopBlockEnterNode.flow = conditionExitFlow.fork().also {
val conditionVariable = variableStorage.getVariable(conditionExitFlow, loop.condition) val conditionVariable = variableStorage.getVariable(conditionExitFlow, loop.condition)
if (conditionVariable != null) { if (conditionVariable != null) {
logicSystem.commitOperationStatement(it, conditionVariable eq true, shouldRemoveSynthetics = false) it.commitOperationStatement(conditionVariable eq true, shouldRemoveSynthetics = false)
} }
} }
} }
@@ -867,7 +852,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
logicSystem.copyAllInformation(flowFromPreviousSafeCall, flow) logicSystem.copyAllInformation(flowFromPreviousSafeCall, flow)
} }
val receiverVariable = variableStorage.getOrCreateVariable(node.flow, safeCall.receiver) val receiverVariable = variableStorage.getOrCreateVariable(node.flow, safeCall.receiver)
flow.assumeNotNull(receiverVariable, shouldRemoveSynthetics = true) flow.commitOperationStatement(receiverVariable notEq null, shouldRemoveSynthetics = true)
} }
fun exitSafeCall(safeCall: FirSafeCallExpression) { fun exitSafeCall(safeCall: FirSafeCallExpression) {
@@ -941,7 +926,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
private fun UnionFunctionCallArgumentsNode.unionFlowFromArguments() { private fun UnionFunctionCallArgumentsNode.unionFlowFromArguments() {
flow = logicSystem.unionFlow(previousNodes.map { it.flow }).also { flow = logicSystem.unionFlow(previousNodes.map { it.flow }).also {
logicSystem.updateAllReceivers(it) resetReceivers(it)
} }
} }
@@ -987,7 +972,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val lastNode = graphBuilder.lastNode val lastNode = graphBuilder.lastNode
when (val value = effect.value) { when (val value = effect.value) {
ConeConstantReference.WILDCARD -> { ConeConstantReference.WILDCARD -> {
logicSystem.commitOperationStatement(lastNode.flow, argumentVariable eq true, shouldRemoveSynthetics = true) lastNode.flow.commitOperationStatement(argumentVariable eq true, shouldRemoveSynthetics = true)
} }
is ConeBooleanConstantReference -> { is ConeBooleanConstantReference -> {
@@ -1145,7 +1130,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val leftOperandVariable = variableStorage.getOrCreateVariable(parentFlow, leftNode.firstPreviousNode.fir) val leftOperandVariable = variableStorage.getOrCreateVariable(parentFlow, leftNode.firstPreviousNode.fir)
leftNode.flow = parentFlow.fork() leftNode.flow = parentFlow.fork()
rightNode.flow = parentFlow.fork().also { rightNode.flow = parentFlow.fork().also {
logicSystem.commitOperationStatement(it, leftOperandVariable eq isAnd, shouldRemoveSynthetics = false) it.commitOperationStatement(leftOperandVariable eq isAnd, shouldRemoveSynthetics = false)
} }
} }
@@ -1174,7 +1159,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
if (!node.leftOperandNode.isDead && node.rightOperandNode.isDead) { if (!node.leftOperandNode.isDead && node.rightOperandNode.isDead) {
// If the right operand does not terminate, then we know that the value of the entire expression // If the right operand does not terminate, then we know that the value of the entire expression
// has to be `onlyLeftEvaluated`, and it has to be produced by the left operand. // has to be `onlyLeftEvaluated`, and it has to be produced by the left operand.
logicSystem.commitOperationStatement(flow, leftVariable eq onlyLeftEvaluated, shouldRemoveSynthetics = true) flow.commitOperationStatement(leftVariable eq onlyLeftEvaluated, shouldRemoveSynthetics = true)
} else { } else {
// If `left && right` is true, then both are true (and evaluated). // If `left && right` is true, then both are true (and evaluated).
// If `left || right` is false, then both are false. // If `left || right` is false, then both are false.
@@ -1196,9 +1181,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
).values.forEach { flow.addImplication((operatorVariable eq onlyLeftEvaluated) implies it) } ).values.forEach { flow.addImplication((operatorVariable eq onlyLeftEvaluated) implies it) }
} }
logicSystem.updateAllReceivers(flow) resetReceivers(flow)
node.flow = flow
variableStorage.removeSyntheticVariable(leftVariable) variableStorage.removeSyntheticVariable(leftVariable)
variableStorage.removeSyntheticVariable(rightVariable) variableStorage.removeSyntheticVariable(rightVariable)
} }
@@ -1264,10 +1247,12 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val (lhsExitNode, lhsIsNotNullNode, rhsEnterNode) = graphBuilder.exitElvisLhs(elvisExpression) val (lhsExitNode, lhsIsNotNullNode, rhsEnterNode) = graphBuilder.exitElvisLhs(elvisExpression)
val flow = lhsExitNode.mergeIncomingFlow() val flow = lhsExitNode.mergeIncomingFlow()
val lhsVariable = variableStorage.getOrCreateVariable(flow, elvisExpression.lhs) val lhsVariable = variableStorage.getOrCreateVariable(flow, elvisExpression.lhs)
lhsIsNotNullNode.flow = flow.fork().also { it.assumeNotNull(lhsVariable, shouldRemoveSynthetics = false) } lhsIsNotNullNode.flow = flow.fork().also {
it.commitOperationStatement(lhsVariable notEq null, shouldRemoveSynthetics = false)
}
rhsEnterNode.flow = flow.fork().also { rhsEnterNode.flow = flow.fork().also {
logicSystem.commitOperationStatement(it, lhsVariable eq null, shouldRemoveSynthetics = false) it.commitOperationStatement(lhsVariable eq null, shouldRemoveSynthetics = false)
logicSystem.updateAllReceivers(it) resetReceivers(it)
} }
} }
@@ -1277,7 +1262,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
mergePostponedLambdaExitsNode?.mergeIncomingFlow() mergePostponedLambdaExitsNode?.mergeIncomingFlow()
if (isLhsNotNull) { if (isLhsNotNull) {
val lhsVariable = variableStorage.getOrCreateVariable(node.previousFlow, elvisExpression.lhs) val lhsVariable = variableStorage.getOrCreateVariable(node.previousFlow, elvisExpression.lhs)
flow.assumeNotNull(lhsVariable, shouldRemoveSynthetics = true) flow.commitOperationStatement(lhsVariable notEq null, shouldRemoveSynthetics = true)
} }
if (!components.session.languageVersionSettings.supportsFeature(LanguageFeature.BooleanElvisBoundSmartCasts)) return if (!components.session.languageVersionSettings.supportsFeature(LanguageFeature.BooleanElvisBoundSmartCasts)) return
@@ -1344,7 +1329,15 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
return logicSystem.joinFlow(previousFlows).also { return logicSystem.joinFlow(previousFlows).also {
flow = it flow = it
if (updateReceivers || previousFlows.size + deadForwardCount > 1) { if (updateReceivers || previousFlows.size + deadForwardCount > 1) {
logicSystem.updateAllReceivers(it) resetReceivers(it)
}
}
}
private fun resetReceivers(flow: FLOW) {
receiverStack.forEach {
variableStorage.getRealVariable(flow, it.boundSymbol, it.receiverExpression)?.let { variable ->
receiverUpdated(it.boundSymbol, flow.getType(variable))
} }
} }
} }
@@ -1366,10 +1359,24 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
private fun FLOW.addTypeStatement(info: TypeStatement) { private fun FLOW.addTypeStatement(info: TypeStatement) {
logicSystem.addTypeStatement(this, info) logicSystem.addTypeStatement(this, info)
if (info.variable.isThisReference) {
receiverUpdated(info.variable.identifier.symbol, getType(info.variable))
}
} }
private fun FLOW.fork(): FLOW { private fun FLOW.fork(): FLOW =
return logicSystem.forkFlow(this) logicSystem.forkFlow(this)
private fun FLOW.commitOperationStatement(statement: OperationStatement, shouldRemoveSynthetics: Boolean) {
logicSystem.approveOperationStatement(this, statement, shouldRemoveSynthetics).values.forEach {
addTypeStatement(it)
}
if (statement.operation == Operation.NotEqNull) {
val variable = statement.variable
if (variable is RealVariable) {
addTypeStatement(variable typeEq any)
}
}
} }
private val CFGNode<*>.previousFlow: FLOW private val CFGNode<*>.previousFlow: FLOW
@@ -8,18 +8,19 @@ package org.jetbrains.kotlin.fir.resolve.dfa
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceContext) { abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceContext) {
// ------------------------------- Flow operations ------------------------------- // --------------------------- Flow graph constructors ---------------------------
abstract fun createEmptyFlow(): FLOW abstract fun createEmptyFlow(): FLOW
abstract fun forkFlow(flow: FLOW): FLOW abstract fun forkFlow(flow: FLOW): FLOW
abstract fun joinFlow(flows: Collection<FLOW>): FLOW abstract fun joinFlow(flows: Collection<FLOW>): FLOW
abstract fun unionFlow(flows: Collection<FLOW>): FLOW abstract fun unionFlow(flows: Collection<FLOW>): FLOW
// -------------------------------- Flow mutators --------------------------------
abstract fun addTypeStatement(flow: FLOW, statement: TypeStatement) abstract fun addTypeStatement(flow: FLOW, statement: TypeStatement)
abstract fun addImplication(flow: FLOW, implication: Implication) abstract fun addImplication(flow: FLOW, implication: Implication)
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariable)
abstract fun recordNewAssignment(flow: FLOW, variable: RealVariable, index: Int)
abstract fun removeAllAboutVariable(flow: FLOW, variable: RealVariable) abstract fun removeAllAboutVariable(flow: FLOW, variable: RealVariable)
abstract fun copyAllInformation(from: FLOW, to: FLOW)
abstract fun translateVariableFromConditionInStatements( abstract fun translateVariableFromConditionInStatements(
flow: FLOW, flow: FLOW,
@@ -30,27 +31,17 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
transform: (Implication) -> Implication? = { it }, transform: (Implication) -> Implication? = { it },
) )
abstract fun commitOperationStatement(flow: FLOW, statement: OperationStatement, shouldRemoveSynthetics: Boolean) // This does *not* commit the results to the flow (but it does mutate the flow if shouldRemoveSynthetics=true)
abstract fun approveOperationStatement(
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariable) flow: FLOW,
approvedStatement: OperationStatement,
abstract fun recordNewAssignment(flow: FLOW, variable: RealVariable, index: Int) shouldRemoveSynthetics: Boolean = false
): TypeStatements
abstract fun copyAllInformation(from: FLOW, to: FLOW)
protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection<Implication>
protected abstract fun ConeKotlinType.isAcceptableForSmartcast(): Boolean protected abstract fun ConeKotlinType.isAcceptableForSmartcast(): Boolean
// ------------------------------- Callbacks for updating implicit receiver stack -------------------------------
abstract fun processUpdatedReceiverVariable(flow: FLOW, variable: RealVariable)
abstract fun updateAllReceivers(flow: FLOW)
// ------------------------------- Public TypeStatement util functions ------------------------------- // ------------------------------- Public TypeStatement util functions -------------------------------
abstract fun approveOperationStatement(flow: FLOW, approvedStatement: OperationStatement): TypeStatements
fun orForTypeStatements(left: TypeStatements, right: TypeStatements): TypeStatements = when { fun orForTypeStatements(left: TypeStatements, right: TypeStatements): TypeStatements = when {
left.isEmpty() -> left left.isEmpty() -> left
right.isEmpty() -> right right.isEmpty() -> right
@@ -220,9 +220,6 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
val newExactType = oldExactType?.addAll(statement.exactType) ?: statement.exactType.toPersistentSet() val newExactType = oldExactType?.addAll(statement.exactType) ?: statement.exactType.toPersistentSet()
if (newExactType === oldExactType) return if (newExactType === oldExactType) return
flow.approvedTypeStatements = flow.approvedTypeStatements.put(variable, PersistentTypeStatement(variable, newExactType)) flow.approvedTypeStatements = flow.approvedTypeStatements.put(variable, PersistentTypeStatement(variable, newExactType))
if (variable.isThisReference) {
processUpdatedReceiverVariable(flow, variable)
}
} }
override fun addImplication(flow: PersistentFlow, implication: Implication) { override fun addImplication(flow: PersistentFlow, implication: Implication) {
@@ -256,16 +253,10 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
} }
} }
override fun commitOperationStatement(flow: PersistentFlow, statement: OperationStatement, shouldRemoveSynthetics: Boolean) { override fun approveOperationStatement(
approveOperationStatementsInternal(flow, statement, shouldRemoveSynthetics).values.forEach {
addTypeStatement(flow, it)
}
}
private fun approveOperationStatementsInternal(
flow: PersistentFlow, flow: PersistentFlow,
approvedStatement: OperationStatement, approvedStatement: OperationStatement,
shouldRemoveSynthetics: Boolean shouldRemoveSynthetics: Boolean,
): TypeStatements { ): TypeStatements {
val approvedTypeStatements: ArrayListMultimap<RealVariable, TypeStatement> = ArrayListMultimap.create() val approvedTypeStatements: ArrayListMultimap<RealVariable, TypeStatement> = ArrayListMultimap.create()
val queue = LinkedList<OperationStatement>().apply { this += approvedStatement } val queue = LinkedList<OperationStatement>().apply { this += approvedStatement }
@@ -291,15 +282,6 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
return approvedTypeStatements.asMap().mapValues { and(it.value) } return approvedTypeStatements.asMap().mapValues { and(it.value) }
} }
override fun approveOperationStatement(
flow: PersistentFlow,
approvedStatement: OperationStatement,
): TypeStatements = approveOperationStatementsInternal(flow, approvedStatement, shouldRemoveSynthetics = false)
override fun getImplicationsWithVariable(flow: PersistentFlow, variable: DataFlowVariable): Collection<Implication> {
return flow.logicStatements[variable] ?: emptyList()
}
override fun recordNewAssignment(flow: PersistentFlow, variable: RealVariable, index: Int) { override fun recordNewAssignment(flow: PersistentFlow, variable: RealVariable, index: Int) {
removeAllAboutVariable(flow, variable) removeAllAboutVariable(flow, variable)
flow.assignmentIndex = flow.assignmentIndex.put(variable, index) flow.assignmentIndex = flow.assignmentIndex.put(variable, index)