Get rid of DelegatingDataFlowInfo::parent property
It's been used to bring immutability to DelegatingDataFlowInfo But in case of statements sequence like: x = 1 ... x = 1 it would lead to huge DelegatingDataFlowInfo where each of getCollectedNullability call works for O(n) where n is amount of assignments The solution is to get rid of reference to parent and to update relevant maps properly In next commits immutable maps will be used instead of making copies each time
This commit is contained in:
+30
-70
@@ -30,50 +30,11 @@ import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class DelegatingDataFlowInfo private constructor(
|
internal class DelegatingDataFlowInfo private constructor(
|
||||||
private val parent: DataFlowInfo?,
|
override val completeNullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||||
private val nullabilityInfo: Map<DataFlowValue, Nullability>,
|
override val completeTypeInfo: SetMultimap<DataFlowValue, KotlinType>
|
||||||
// Also immutable
|
|
||||||
private val typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
|
||||||
/**
|
|
||||||
* Value for which type info was cleared or reassigned at this point
|
|
||||||
* so parent type info should not be in use
|
|
||||||
*/
|
|
||||||
private val valueWithGivenTypeInfo: DataFlowValue?
|
|
||||||
) : DataFlowInfo {
|
) : DataFlowInfo {
|
||||||
|
|
||||||
constructor() : this(null, emptyMap(), newTypeInfo(), null)
|
constructor() : this(emptyMap(), newTypeInfo())
|
||||||
|
|
||||||
override val completeNullabilityInfo: Map<DataFlowValue, Nullability>
|
|
||||||
get() {
|
|
||||||
val result = hashMapOf<DataFlowValue, Nullability>()
|
|
||||||
var info: DelegatingDataFlowInfo? = this
|
|
||||||
while (info != null) {
|
|
||||||
for ((key, value) in info.nullabilityInfo) {
|
|
||||||
if (!result.containsKey(key)) {
|
|
||||||
result.put(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info = info.parent as DelegatingDataFlowInfo?
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override val completeTypeInfo: SetMultimap<DataFlowValue, KotlinType>
|
|
||||||
get() {
|
|
||||||
val result = newTypeInfo()
|
|
||||||
val withGivenTypeInfo = HashSet<DataFlowValue>()
|
|
||||||
var info: DelegatingDataFlowInfo? = this
|
|
||||||
while (info != null) {
|
|
||||||
for (key in info.typeInfo.keySet()) {
|
|
||||||
if (!withGivenTypeInfo.contains(key)) {
|
|
||||||
result.putAll(key, info.typeInfo.get(key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info.valueWithGivenTypeInfo?.let { withGivenTypeInfo.add(it) }
|
|
||||||
info = info.parent as DelegatingDataFlowInfo?
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCollectedNullability(key: DataFlowValue) = getNullability(key, false)
|
override fun getCollectedNullability(key: DataFlowValue) = getNullability(key, false)
|
||||||
|
|
||||||
@@ -83,7 +44,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
if (stableOnly && !key.isStable) {
|
if (stableOnly && !key.isStable) {
|
||||||
key.immanentNullability
|
key.immanentNullability
|
||||||
} else {
|
} else {
|
||||||
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
|
completeNullabilityInfo.getOrDefault(key, key.immanentNullability)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun putNullabilityAndTypeInfo(
|
private fun putNullabilityAndTypeInfo(
|
||||||
@@ -151,7 +112,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
enrichWithNotNull: Boolean,
|
enrichWithNotNull: Boolean,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): Set<KotlinType> {
|
): Set<KotlinType> {
|
||||||
val types = collectTypesFromMeAndParents(key, languageVersionSettings)
|
val types = completeTypeInfo[key]
|
||||||
if (!enrichWithNotNull || getCollectedNullability(key).canBeNull()) {
|
if (!enrichWithNotNull || getCollectedNullability(key).canBeNull()) {
|
||||||
return types
|
return types
|
||||||
}
|
}
|
||||||
@@ -262,23 +223,6 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
return if (changed) create(this, resultNullabilityInfo, if (newTypeInfo.isEmpty) EMPTY_TYPE_INFO else newTypeInfo) else this
|
return if (changed) create(this, resultNullabilityInfo, if (newTypeInfo.isEmpty) EMPTY_TYPE_INFO else newTypeInfo) else this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectTypesFromMeAndParents(value: DataFlowValue, languageVersionSettings: LanguageVersionSettings): Set<KotlinType> {
|
|
||||||
val types = LinkedHashSet<KotlinType>()
|
|
||||||
|
|
||||||
var current: DataFlowInfo? = this
|
|
||||||
while (current != null) {
|
|
||||||
if (current is DelegatingDataFlowInfo) {
|
|
||||||
types.addAll(current.typeInfo.get(value))
|
|
||||||
current = if (value == current.valueWithGivenTypeInfo) null else current.parent
|
|
||||||
} else {
|
|
||||||
types.addAll(current.getCollectedTypes(value, languageVersionSettings))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return types
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun disequate(
|
override fun disequate(
|
||||||
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
|
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
@@ -381,7 +325,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
return create(null, resultNullabilityInfo, newTypeInfo)
|
return create(null, resultNullabilityInfo, newTypeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = if (typeInfo.isEmpty && nullabilityInfo.isEmpty()) "EMPTY" else "Non-trivial DataFlowInfo"
|
override fun toString() = if (completeTypeInfo.isEmpty && completeNullabilityInfo.isEmpty()) "EMPTY" else "Non-trivial DataFlowInfo"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val EMPTY_TYPE_INFO = newTypeInfo()
|
private val EMPTY_TYPE_INFO = newTypeInfo()
|
||||||
@@ -393,14 +337,14 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
|
|
||||||
private fun create(
|
private fun create(
|
||||||
parent: DataFlowInfo?,
|
parent: DataFlowInfo?,
|
||||||
nullabilityInfo: Map<DataFlowValue, Nullability>,
|
updatedNullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||||
// NB: typeInfo must be mutable here!
|
// NB: typeInfo must be mutable here!
|
||||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
updatedTypeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
||||||
valueWithGivenTypeInfo: DataFlowValue? = null
|
valueToClearPreviousTypeInfo: DataFlowValue? = null
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
val toDelete = newTypeInfo()
|
val toDelete = newTypeInfo()
|
||||||
for (value in typeInfo.keys()) {
|
for (value in updatedTypeInfo.keys()) {
|
||||||
for (type in typeInfo[value]) {
|
for (type in updatedTypeInfo[value]) {
|
||||||
// Remove original type (see also KT-10666)
|
// Remove original type (see also KT-10666)
|
||||||
if (value.type == type || type.contains { it.constructor is NewCapturedTypeConstructor }) {
|
if (value.type == type || type.contains { it.constructor is NewCapturedTypeConstructor }) {
|
||||||
toDelete.put(value, type)
|
toDelete.put(value, type)
|
||||||
@@ -408,12 +352,28 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ((value, type) in toDelete.entries()) {
|
for ((value, type) in toDelete.entries()) {
|
||||||
typeInfo.remove(value, type)
|
updatedTypeInfo.remove(value, type)
|
||||||
}
|
}
|
||||||
if (nullabilityInfo.isEmpty() && typeInfo.isEmpty && valueWithGivenTypeInfo == null) {
|
|
||||||
|
if (updatedNullabilityInfo.isEmpty() && updatedTypeInfo.isEmpty && valueToClearPreviousTypeInfo == null) {
|
||||||
return parent ?: DataFlowInfoFactory.EMPTY
|
return parent ?: DataFlowInfoFactory.EMPTY
|
||||||
}
|
}
|
||||||
return DelegatingDataFlowInfo(parent, nullabilityInfo, typeInfo, valueWithGivenTypeInfo)
|
|
||||||
|
val resultingNullabilityInfo = parent?.completeNullabilityInfo?.toMutableMap() ?: hashMapOf()
|
||||||
|
resultingNullabilityInfo.putAll(updatedNullabilityInfo)
|
||||||
|
|
||||||
|
val resultingTypeInfo =
|
||||||
|
LinkedHashMultimap.create<DataFlowValue, KotlinType>(
|
||||||
|
parent?.completeTypeInfo ?: newTypeInfo()
|
||||||
|
)
|
||||||
|
|
||||||
|
valueToClearPreviousTypeInfo?.let(resultingTypeInfo::removeAll)
|
||||||
|
|
||||||
|
for ((value, types) in updatedTypeInfo.asMap().entries) {
|
||||||
|
resultingTypeInfo.putAll(value, types)
|
||||||
|
}
|
||||||
|
|
||||||
|
return DelegatingDataFlowInfo(resultingNullabilityInfo, resultingTypeInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user