FIR: Get rid of RealVariable.originalType
Store original type only for local variable aliases The problem with the former is that RealVariable may be referenced via safe-calls and via usual calls, but its type is fixed ^KT-38444 In Progress
This commit is contained in:
+7
-3
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.types.*
|
|||||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
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
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
class DataFlowAnalyzerContext<FLOW : Flow>(
|
class DataFlowAnalyzerContext<FLOW : Flow>(
|
||||||
val graphBuilder: ControlFlowGraphBuilder,
|
val graphBuilder: ControlFlowGraphBuilder,
|
||||||
@@ -118,8 +119,8 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
var variable = variableStorage.getRealVariableWithoutUnwrappingAlias(symbol, qualifiedAccessExpression, flow) ?: return null
|
var variable = variableStorage.getRealVariableWithoutUnwrappingAlias(symbol, qualifiedAccessExpression, flow) ?: return null
|
||||||
val result = mutableListOf<ConeKotlinType>()
|
val result = mutableListOf<ConeKotlinType>()
|
||||||
flow.directAliasMap[variable]?.let {
|
flow.directAliasMap[variable]?.let {
|
||||||
result += it.originalType
|
result.addIfNotNull(it.originalType)
|
||||||
variable = it
|
variable = it.variable
|
||||||
}
|
}
|
||||||
flow.getTypeStatement(variable)?.exactType?.let { result += it }
|
flow.getTypeStatement(variable)?.exactType?.let { result += it }
|
||||||
return result.takeIf { it.isNotEmpty() }
|
return result.takeIf { it.isNotEmpty() }
|
||||||
@@ -783,7 +784,10 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer)?.let { initializerVariable ->
|
variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer)?.let { initializerVariable ->
|
||||||
logicSystem.addLocalVariableAlias(flow, propertyVariable, initializerVariable)
|
logicSystem.addLocalVariableAlias(
|
||||||
|
flow, propertyVariable,
|
||||||
|
RealVariableAndType(initializerVariable, initializer.coneType)
|
||||||
|
)
|
||||||
// node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null))
|
// node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ abstract class Flow {
|
|||||||
abstract fun getVariablesInTypeStatements(): Collection<RealVariable>
|
abstract fun getVariablesInTypeStatements(): Collection<RealVariable>
|
||||||
abstract fun removeOperations(variable: DataFlowVariable): Collection<Implication>
|
abstract fun removeOperations(variable: DataFlowVariable): Collection<Implication>
|
||||||
|
|
||||||
abstract val directAliasMap: Map<RealVariable, RealVariable>
|
abstract val directAliasMap: Map<RealVariable, RealVariableAndType>
|
||||||
abstract val backwardsAliasMap: Map<RealVariable, List<RealVariable>>
|
abstract val backwardsAliasMap: Map<RealVariable, List<RealVariable>>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Flow.unwrapVariable(variable: RealVariable): RealVariable {
|
fun Flow.unwrapVariable(variable: RealVariable): RealVariable {
|
||||||
return directAliasMap[variable] ?: variable
|
return directAliasMap[variable]?.variable ?: variable
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceContext) {
|
abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceContext) {
|
||||||
@@ -53,7 +53,7 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
|||||||
shouldRemoveSynthetics: Boolean,
|
shouldRemoveSynthetics: Boolean,
|
||||||
): FLOW
|
): FLOW
|
||||||
|
|
||||||
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariable)
|
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariableAndType)
|
||||||
abstract fun removeLocalVariableAlias(flow: FLOW, alias: RealVariable)
|
abstract fun removeLocalVariableAlias(flow: FLOW, alias: RealVariable)
|
||||||
|
|
||||||
protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection<Implication>
|
protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection<Implication>
|
||||||
@@ -190,4 +190,4 @@ fun <F : Flow> LogicSystem<F>.replaceVariableFromConditionInStatements(
|
|||||||
filter,
|
filter,
|
||||||
transform,
|
transform,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-9
@@ -9,6 +9,7 @@ import com.google.common.collect.ArrayListMultimap
|
|||||||
import kotlinx.collections.immutable.*
|
import kotlinx.collections.immutable.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeInferenceContext
|
import org.jetbrains.kotlin.fir.types.ConeInferenceContext
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.NoSuchElementException
|
import kotlin.NoSuchElementException
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ class PersistentFlow : Flow {
|
|||||||
* directAliasMap: { x -> a, y -> a}
|
* directAliasMap: { x -> a, y -> a}
|
||||||
* backwardsAliasMap: { a -> [x, y] }
|
* backwardsAliasMap: { a -> [x, y] }
|
||||||
*/
|
*/
|
||||||
override var directAliasMap: PersistentMap<RealVariable, RealVariable>
|
override var directAliasMap: PersistentMap<RealVariable, RealVariableAndType>
|
||||||
override var backwardsAliasMap: PersistentMap<RealVariable, PersistentList<RealVariable>>
|
override var backwardsAliasMap: PersistentMap<RealVariable, PersistentList<RealVariable>>
|
||||||
|
|
||||||
constructor(previousFlow: PersistentFlow) {
|
constructor(previousFlow: PersistentFlow) {
|
||||||
@@ -156,9 +157,9 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
|
|
||||||
private fun computeAliasesThatDontChange(
|
private fun computeAliasesThatDontChange(
|
||||||
flows: Collection<PersistentFlow>
|
flows: Collection<PersistentFlow>
|
||||||
): MutableMap<RealVariable, RealVariable> {
|
): MutableMap<RealVariable, RealVariableAndType> {
|
||||||
val flowsSize = flows.size
|
val flowsSize = flows.size
|
||||||
val aliasedVariablesThatDontChangeAlias = mutableMapOf<RealVariable, RealVariable>()
|
val aliasedVariablesThatDontChangeAlias = mutableMapOf<RealVariable, RealVariableAndType>()
|
||||||
|
|
||||||
flows.flatMapTo(mutableSetOf()) { it.directAliasMap.keys }.forEach { aliasedVariable ->
|
flows.flatMapTo(mutableSetOf()) { it.directAliasMap.keys }.forEach { aliasedVariable ->
|
||||||
val originals = flows.map { it.directAliasMap[aliasedVariable] ?: return@forEach }
|
val originals = flows.map { it.directAliasMap[aliasedVariable] ?: return@forEach }
|
||||||
@@ -173,7 +174,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun PersistentFlow.addVariableAliases(
|
private fun PersistentFlow.addVariableAliases(
|
||||||
aliasedVariablesThatDontChangeAlias: MutableMap<RealVariable, RealVariable>
|
aliasedVariablesThatDontChangeAlias: MutableMap<RealVariable, RealVariableAndType>
|
||||||
) {
|
) {
|
||||||
for ((alias, underlyingVariable) in aliasedVariablesThatDontChangeAlias) {
|
for ((alias, underlyingVariable) in aliasedVariablesThatDontChangeAlias) {
|
||||||
addLocalVariableAlias(this, alias, underlyingVariable)
|
addLocalVariableAlias(this, alias, underlyingVariable)
|
||||||
@@ -189,11 +190,11 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addLocalVariableAlias(flow: PersistentFlow, alias: RealVariable, underlyingVariable: RealVariable) {
|
override fun addLocalVariableAlias(flow: PersistentFlow, alias: RealVariable, underlyingVariable: RealVariableAndType) {
|
||||||
removeLocalVariableAlias(flow, alias)
|
removeLocalVariableAlias(flow, alias)
|
||||||
flow.directAliasMap = flow.directAliasMap.put(alias, underlyingVariable)
|
flow.directAliasMap = flow.directAliasMap.put(alias, underlyingVariable)
|
||||||
flow.backwardsAliasMap = flow.backwardsAliasMap.put(
|
flow.backwardsAliasMap = flow.backwardsAliasMap.put(
|
||||||
underlyingVariable,
|
underlyingVariable.variable,
|
||||||
{ persistentListOf(alias) },
|
{ persistentListOf(alias) },
|
||||||
{ variables -> variables + alias }
|
{ variables -> variables + alias }
|
||||||
)
|
)
|
||||||
@@ -201,7 +202,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
|
|
||||||
override fun removeLocalVariableAlias(flow: PersistentFlow, alias: RealVariable) {
|
override fun removeLocalVariableAlias(flow: PersistentFlow, alias: RealVariable) {
|
||||||
flow.updatedAliasDiff += alias
|
flow.updatedAliasDiff += alias
|
||||||
val original = flow.directAliasMap[alias] ?: return
|
val original = flow.directAliasMap[alias]?.variable ?: return
|
||||||
flow.directAliasMap = flow.directAliasMap.remove(alias)
|
flow.directAliasMap = flow.directAliasMap.remove(alias)
|
||||||
val variables = flow.backwardsAliasMap.getValue(original)
|
val variables = flow.backwardsAliasMap.getValue(original)
|
||||||
flow.backwardsAliasMap = flow.backwardsAliasMap.put(original, variables - alias)
|
flow.backwardsAliasMap = flow.backwardsAliasMap.put(original, variables - alias)
|
||||||
@@ -220,8 +221,8 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
flow = flow.previousFlow!!
|
flow = flow.previousFlow!!
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.exactType += variableUnderAlias.originalType
|
result.exactType.addIfNotNull(variableUnderAlias.originalType)
|
||||||
flow.approvedTypeStatements[variableUnderAlias]?.let { result += it }
|
flow.approvedTypeStatements[variableUnderAlias.variable]?.let { result += it }
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class VariableStorage(private val session: FirSession) {
|
|||||||
|
|
||||||
private fun getOrCreateRealVariable(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable {
|
private fun getOrCreateRealVariable(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable {
|
||||||
val variable = getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir)
|
val variable = getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir)
|
||||||
return flow.directAliasMap[variable] ?: variable
|
return flow.directAliasMap[variable]?.variable ?: variable
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirElement.unwrapElement(): FirElement = when (this) {
|
private fun FirElement.unwrapElement(): FirElement = when (this) {
|
||||||
@@ -85,13 +85,7 @@ class VariableStorage(private val session: FirSession) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val receiverVariable = receiver?.let { getOrCreateVariable(flow, it) }
|
val receiverVariable = receiver?.let { getOrCreateVariable(flow, it) }
|
||||||
val originalType: ConeKotlinType = when (originalFir) {
|
return RealVariable(identifier, isThisReference, receiverVariable, counter++)
|
||||||
is FirExpression -> originalFir.typeRef.coneTypeUnsafe()
|
|
||||||
is FirProperty -> originalFir.returnTypeRef.coneTypeUnsafe()
|
|
||||||
is FirVariableAssignment -> identifier.symbol.fir.extractReturnType()
|
|
||||||
else -> throw IllegalStateException("Should not be here: $originalFir")
|
|
||||||
}
|
|
||||||
return RealVariable(identifier, isThisReference, receiverVariable, originalType, counter++)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("getOrCreateRealVariableOrNull")
|
@JvmName("getOrCreateRealVariableOrNull")
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ class RealVariable(
|
|||||||
val identifier: Identifier,
|
val identifier: Identifier,
|
||||||
val isThisReference: Boolean,
|
val isThisReference: Boolean,
|
||||||
val explicitReceiverVariable: DataFlowVariable?,
|
val explicitReceiverVariable: DataFlowVariable?,
|
||||||
val originalType: ConeKotlinType,
|
|
||||||
variableIndexForDebug: Int
|
variableIndexForDebug: Int
|
||||||
) : DataFlowVariable(variableIndexForDebug) {
|
) : DataFlowVariable(variableIndexForDebug) {
|
||||||
override val isStable: Boolean by lazy {
|
override val isStable: Boolean by lazy {
|
||||||
@@ -74,6 +73,26 @@ class RealVariable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RealVariableAndType(val variable: RealVariable, val originalType: ConeKotlinType?) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as RealVariableAndType
|
||||||
|
|
||||||
|
if (variable != other.variable) return false
|
||||||
|
if (originalType != other.originalType) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = variable.hashCode()
|
||||||
|
result = 31 * result + originalType.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SyntheticVariable(val fir: FirElement, variableIndexForDebug: Int) : DataFlowVariable(variableIndexForDebug) {
|
class SyntheticVariable(val fir: FirElement, variableIndexForDebug: Int) : DataFlowVariable(variableIndexForDebug) {
|
||||||
override val isStable: Boolean get() = true
|
override val isStable: Boolean get() = true
|
||||||
|
|
||||||
@@ -220,4 +239,4 @@ infix fun RealVariable.typeNotEq(type: ConeKotlinType): TypeStatement =
|
|||||||
MutableTypeStatement(this, linkedSetOf(), LinkedHashSet<ConeKotlinType>().apply { this += type })
|
MutableTypeStatement(this, linkedSetOf(), LinkedHashSet<ConeKotlinType>().apply { this += type })
|
||||||
} else {
|
} else {
|
||||||
MutableTypeStatement(this)
|
MutableTypeStatement(this)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user