From f2347d1954528048fcd7a5899931d65e2d4828c7 Mon Sep 17 00:00:00 2001 From: pyos Date: Wed, 30 Nov 2022 16:44:40 +0100 Subject: [PATCH] FIR DFA: use PersistentSet.Builder for exactType --- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 6 +- .../kotlin/fir/resolve/dfa/LogicSystem.kt | 70 +++++++++++-------- .../jetbrains/kotlin/fir/resolve/dfa/model.kt | 4 +- 3 files changed, 45 insertions(+), 35 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 fb29fce9e56..a5c61989d23 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 @@ -641,10 +641,10 @@ abstract class FirDataFlowAnalyzer( val newStatement = logicSystem.or(conditionExitAndBreakFlows.map { val atExit = it.getTypeStatement(variable) if (logicSystem.isSameValueIn(conditionEnterFlow, it, variable)) { - if (atExit != null) logicSystem.and(listOf(atExit, toAdd)) else toAdd + logicSystem.and(atExit, toAdd) } else { - atExit - } ?: return@forEach + atExit ?: return@forEach + } }) ?: return@forEach flow.addTypeStatement(newStatement) } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt index 3e731410781..c75e6a88e75 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt @@ -278,7 +278,7 @@ abstract class LogicSystem(private val context: ConeInferenceContext) { right.isEmpty() -> right else -> buildMap { for ((variable, leftStatement) in left) { - put(variable, or(listOf(leftStatement, right[variable] ?: continue))!!) + put(variable, or(listOf(leftStatement, right[variable] ?: continue)) ?: continue) } } } @@ -288,50 +288,62 @@ abstract class LogicSystem(private val context: ConeInferenceContext) { right.isEmpty() -> left else -> left.toMutableMap().apply { for ((variable, rightStatement) in right) { - this[variable] = this[variable]?.let { and(listOf(it, rightStatement))!! } ?: rightStatement + this[variable] = and(this[variable], rightStatement) } } } - private inline fun Collection.singleOrNew(exactType: () -> MutableSet): TypeStatement? = - when (size) { - 0 -> null - 1 -> first() - else -> { - val variable = first().variable - assert(all { it.variable == variable }) { "folding statements for different variables" } - MutableTypeStatement(variable, exactType()) - } - } - - private fun unifyTypes(types: Collection>): ConeKotlinType? { - if (types.any { it.isEmpty() }) return null - val intersected = types.map { ConeTypeIntersector.intersectTypes(context, it.toList()) } - val unified = context.commonSuperTypeOrNull(intersected) ?: return null - return when { - unified.isNullableAny -> null - unified.isAcceptableForSmartcast() -> unified - unified.canBeNull -> null - else -> context.anyType() - } - } - private operator fun MutableTypeStatement.plusAssign(other: TypeStatement) { exactType += other.exactType } - fun and(statements: Collection): TypeStatement? = - statements.singleOrNew { statements.flatMapTo(mutableSetOf()) { it.exactType } } + fun and(a: TypeStatement?, b: TypeStatement): TypeStatement = + a?.toMutable()?.apply { this += b } ?: b - fun or(statements: Collection): TypeStatement? = - statements.singleOrNew { unifyTypes(statements.map { it.exactType })?.let { mutableSetOf(it) } ?: mutableSetOf() } + fun and(statements: Collection): TypeStatement? { + when (statements.size) { + 0 -> return null + 1 -> return statements.first() + } + val iterator = statements.iterator() + val result = iterator.next().toMutable() + while (iterator.hasNext()) { + result += iterator.next() + } + return result + } + + fun or(statements: Collection): TypeStatement? { + when (statements.size) { + 0 -> return null + 1 -> return statements.first() + } + val variable = statements.first().variable + assert(statements.all { it.variable == variable }) { "folding statements for different variables" } + if (statements.any { it.isEmpty }) return null + val intersected = statements.map { ConeTypeIntersector.intersectTypes(context, it.exactType.toList()) } + val unified = context.commonSuperTypeOrNull(intersected) ?: return null + val result = when { + unified.isNullableAny -> return null + unified.isAcceptableForSmartcast() -> unified + unified.canBeNull -> return null + else -> context.anyType() + } + return PersistentTypeStatement(variable, persistentSetOf(result)) + } } private fun TypeStatement.toPersistent(): PersistentTypeStatement = when (this) { is PersistentTypeStatement -> this + // If this statement was obtained via `toMutable`, `toPersistentSet` will call `build`. else -> PersistentTypeStatement(variable, exactType.toPersistentSet()) } +private fun TypeStatement.toMutable(): MutableTypeStatement = when (this) { + is PersistentTypeStatement -> MutableTypeStatement(variable, exactType.builder()) + else -> MutableTypeStatement(variable, LinkedHashSet(exactType)) +} + @JvmName("replaceVariableInStatements") private fun MutableMap.replaceVariable(from: RealVariable, to: RealVariable?) { val existing = remove(from) ?: return diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt index ba73d624aa7..33e28af7c26 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt @@ -21,9 +21,7 @@ data class PersistentTypeStatement( class MutableTypeStatement( override val variable: RealVariable, override val exactType: MutableSet = linkedSetOf(), -) : TypeStatement() { - fun copy(): MutableTypeStatement = MutableTypeStatement(variable, LinkedHashSet(exactType)) -} +) : TypeStatement() // --------------------------------------- Aliases ---------------------------------------