FIR DFA: check for reassignments of LHS when handling ?..

`x?.y != null` does not imply that `x != null` if e.g. an argument to
`y` has reassigned `x` in the meantime.

The same is true for `x == y` and `functionWithContract(x, y)`, but
those are somewhat harder to implement since there is no easy way to
find the last node of a certain argument.

^KT-55096
This commit is contained in:
pyos
2022-11-14 20:45:18 +01:00
committed by teamcity
parent ae1048f8a9
commit 5cc08fb314
11 changed files with 164 additions and 22 deletions
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.fir.resolve.dfa
abstract class Flow {
abstract val approvedTypeStatements: TypeStatements
abstract val knownVariables: Set<RealVariable>
abstract fun unwrapVariable(variable: RealVariable): RealVariable
abstract fun getTypeStatement(variable: RealVariable): TypeStatement?
}
@@ -23,6 +23,7 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
abstract fun recordNewAssignment(flow: FLOW, variable: RealVariable, index: Int)
abstract fun removeAllAboutVariable(flow: FLOW, variable: RealVariable)
abstract fun copyAllInformation(from: FLOW, to: FLOW)
abstract fun isSameValueIn(a: FLOW, b: FLOW, variable: RealVariable): Boolean
abstract fun translateVariableFromConditionInStatements(
flow: FLOW,
@@ -22,7 +22,7 @@ typealias PersistentImplications = PersistentMap<DataFlowVariable, PersistentLis
class PersistentFlow : Flow {
val previousFlow: PersistentFlow?
override var approvedTypeStatements: PersistentApprovedTypeStatements
var approvedTypeStatements: PersistentApprovedTypeStatements
var logicStatements: PersistentImplications
val level: Int
@@ -60,6 +60,9 @@ class PersistentFlow : Flow {
assignmentIndex = persistentMapOf()
}
override val knownVariables: Set<RealVariable>
get() = approvedTypeStatements.keys + directAliasMap.keys
override fun unwrapVariable(variable: RealVariable): RealVariable =
directAliasMap[variable] ?: variable
@@ -126,8 +129,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
}
val approvedTypeStatements = result.approvedTypeStatements.builder()
val allVariablesWithStatements = flows.flatMapTo(mutableSetOf()) { it.approvedTypeStatements.keys + it.directAliasMap.keys }
allVariablesWithStatements.forEach computeStatement@{ variable ->
flows.flatMapTo(mutableSetOf()) { it.knownVariables }.forEach computeStatement@{ variable ->
val statement = if (variable in result.directAliasMap) {
return@computeStatement // statements about alias == statements about aliased variable
} else if (!allExecute) {
@@ -321,6 +323,9 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
removeAllAboutVariable(flow, variable)
flow.assignmentIndex = flow.assignmentIndex.put(variable, index)
}
override fun isSameValueIn(a: PersistentFlow, b: PersistentFlow, variable: RealVariable): Boolean =
a.assignmentIndex[variable] == b.assignmentIndex[variable]
}
private fun lowestCommonFlow(left: PersistentFlow, right: PersistentFlow): PersistentFlow {