Extract ReadOnly*ControlFlowInfo interfaces from *ControlFlowInfo
It's necessary for further optimizations: not for all cases we actually need to build a map The naming is still a subject for discussion
This commit is contained in:
@@ -22,10 +22,10 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|||||||
typealias ImmutableMap<K, V> = javaslang.collection.Map<K, V>
|
typealias ImmutableMap<K, V> = javaslang.collection.Map<K, V>
|
||||||
typealias ImmutableHashMap<K, V> = javaslang.collection.HashMap<K, V>
|
typealias ImmutableHashMap<K, V> = javaslang.collection.HashMap<K, V>
|
||||||
|
|
||||||
abstract class ControlFlowInfo<S : ControlFlowInfo<S, D>, D>
|
abstract class ControlFlowInfo<S : ControlFlowInfo<S, D>, D : Any>
|
||||||
internal constructor(
|
internal constructor(
|
||||||
protected val map: ImmutableMap<VariableDescriptor, D> = ImmutableHashMap.empty()
|
protected val map: ImmutableMap<VariableDescriptor, D> = ImmutableHashMap.empty()
|
||||||
) : ImmutableMap<VariableDescriptor, D> by map {
|
) : ImmutableMap<VariableDescriptor, D> by map, ReadOnlyControlFlowInfo<D> {
|
||||||
abstract protected fun copy(newMap: ImmutableMap<VariableDescriptor, D>): S
|
abstract protected fun copy(newMap: ImmutableMap<VariableDescriptor, D>): S
|
||||||
|
|
||||||
override fun put(key: VariableDescriptor, value: D): S = put(key, value, this[key].getOrElse(null as D?))
|
override fun put(key: VariableDescriptor, value: D): S = put(key, value, this[key].getOrElse(null as D?))
|
||||||
@@ -41,6 +41,9 @@ internal constructor(
|
|||||||
return copy(map.put(key, value))
|
return copy(map.put(key, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getOrNull(variableDescriptor: VariableDescriptor): D? = this[variableDescriptor].getOrElse(null as D?)
|
||||||
|
override fun asMap() = this
|
||||||
|
|
||||||
fun retainAll(predicate: (VariableDescriptor) -> Boolean): S = copy(map.removeAll(map.keySet().filterNot(predicate)))
|
fun retainAll(predicate: (VariableDescriptor) -> Boolean): S = copy(map.removeAll(map.keySet().filterNot(predicate)))
|
||||||
|
|
||||||
override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*, *>)?.map
|
override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*, *>)?.map
|
||||||
@@ -53,16 +56,26 @@ internal constructor(
|
|||||||
operator fun <T> Tuple2<T, *>.component1(): T = _1()
|
operator fun <T> Tuple2<T, *>.component1(): T = _1()
|
||||||
operator fun <T> Tuple2<*, T>.component2(): T = _2()
|
operator fun <T> Tuple2<*, T>.component2(): T = _2()
|
||||||
|
|
||||||
fun <K, V> ImmutableMap<K, V>.getOrNull(k: K): V? = this[k].getOrElse(null as V?)
|
interface ReadOnlyControlFlowInfo<D : Any> {
|
||||||
|
fun getOrNull(variableDescriptor: VariableDescriptor): D?
|
||||||
|
// Only used in tests
|
||||||
|
fun asMap(): ImmutableMap<VariableDescriptor, D>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadOnlyInitControlFlowInfo : ReadOnlyControlFlowInfo<VariableControlFlowState> {
|
||||||
|
fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias ReadOnlyUseControlFlowInfo = ReadOnlyControlFlowInfo<VariableUseState>
|
||||||
|
|
||||||
class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) :
|
class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) :
|
||||||
ControlFlowInfo<InitControlFlowInfo, VariableControlFlowState>(map) {
|
ControlFlowInfo<InitControlFlowInfo, VariableControlFlowState>(map), ReadOnlyInitControlFlowInfo {
|
||||||
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) = InitControlFlowInfo(newMap)
|
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) = InitControlFlowInfo(newMap)
|
||||||
|
|
||||||
// this = output of EXHAUSTIVE_WHEN_ELSE instruction
|
// this = output of EXHAUSTIVE_WHEN_ELSE instruction
|
||||||
// merge = input of MergeInstruction
|
// merge = input of MergeInstruction
|
||||||
// returns true if definite initialization in when happens here
|
// returns true if definite initialization in when happens here
|
||||||
fun checkDefiniteInitializationInWhen(merge: InitControlFlowInfo): Boolean {
|
override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean {
|
||||||
for ((key, value) in iterator()) {
|
for ((key, value) in iterator()) {
|
||||||
if (value.initState == InitState.INITIALIZED_EXHAUSTIVELY &&
|
if (value.initState == InitState.INITIALIZED_EXHAUSTIVELY &&
|
||||||
merge.getOrNull(key)?.initState == InitState.INITIALIZED) {
|
merge.getOrNull(key)?.initState == InitState.INITIALIZED) {
|
||||||
@@ -74,7 +87,7 @@ class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlF
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UseControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) :
|
class UseControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) :
|
||||||
ControlFlowInfo<UseControlFlowInfo, VariableUseState>(map) {
|
ControlFlowInfo<UseControlFlowInfo, VariableUseState>(map), ReadOnlyUseControlFlowInfo {
|
||||||
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) = UseControlFlowInfo(newMap)
|
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) = UseControlFlowInfo(newMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -274,8 +274,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
pseudocode.traverse(TraversalOrder.FORWARD, initializers) {
|
pseudocode.traverse(TraversalOrder.FORWARD, initializers) {
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
enterData: ImmutableMap<VariableDescriptor, VariableControlFlowState>,
|
enterData: ReadOnlyInitControlFlowInfo,
|
||||||
exitData: ImmutableMap<VariableDescriptor, VariableControlFlowState> ->
|
exitData: ReadOnlyInitControlFlowInfo ->
|
||||||
|
|
||||||
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
|
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
|
||||||
if (ctxt.variableDescriptor == null) return@traverse
|
if (ctxt.variableDescriptor == null) return@traverse
|
||||||
@@ -532,7 +532,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
private fun recordInitializedVariables(
|
private fun recordInitializedVariables(
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
initializersMap: Map<Instruction, Edges<InitControlFlowInfo>>
|
initializersMap: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>>
|
||||||
) {
|
) {
|
||||||
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
|
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
|
||||||
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
|
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
|
||||||
@@ -554,8 +554,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val usedValueExpressions = hashSetOf<KtExpression>()
|
val usedValueExpressions = hashSetOf<KtExpression>()
|
||||||
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) {
|
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) {
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
enterData: ImmutableMap<VariableDescriptor, VariableUseState>,
|
enterData: ReadOnlyUseControlFlowInfo,
|
||||||
_: ImmutableMap<VariableDescriptor, VariableUseState> ->
|
_: ReadOnlyUseControlFlowInfo ->
|
||||||
|
|
||||||
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
|
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
|
||||||
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
|
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
|
||||||
@@ -1030,8 +1030,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
private inner class VariableInitContext(
|
private inner class VariableInitContext(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
map: MutableMap<Instruction, DiagnosticFactory<*>>,
|
map: MutableMap<Instruction, DiagnosticFactory<*>>,
|
||||||
`in`: ImmutableMap<VariableDescriptor, VariableControlFlowState>,
|
`in`: ReadOnlyInitControlFlowInfo,
|
||||||
out: ImmutableMap<VariableDescriptor, VariableControlFlowState>,
|
out: ReadOnlyInitControlFlowInfo,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
) : VariableContext(instruction, map) {
|
) : VariableContext(instruction, map) {
|
||||||
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
|
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
|
||||||
@@ -1040,7 +1040,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
private fun initialize(
|
private fun initialize(
|
||||||
variableDescriptor: VariableDescriptor?,
|
variableDescriptor: VariableDescriptor?,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo,
|
blockScopeVariableInfo: BlockScopeVariableInfo,
|
||||||
map: ImmutableMap<VariableDescriptor, VariableControlFlowState>
|
map: ReadOnlyInitControlFlowInfo
|
||||||
): VariableControlFlowState? {
|
): VariableControlFlowState? {
|
||||||
val state = map.getOrNull(variableDescriptor ?: return null)
|
val state = map.getOrNull(variableDescriptor ?: return null)
|
||||||
if (state != null) return state
|
if (state != null) return state
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, Set<VariableDescriptor>>()
|
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, Set<VariableDescriptor>>()
|
||||||
|
|
||||||
val variableInitializers: Map<Instruction, Edges<InitControlFlowInfo>> by lazy {
|
val variableInitializers: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> by lazy {
|
||||||
computeVariableInitializers()
|
computeVariableInitializers()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
// variable use
|
// variable use
|
||||||
|
|
||||||
val variableUseStatusData: Map<Instruction, Edges<UseControlFlowInfo>>
|
val variableUseStatusData: Map<Instruction, Edges<ReadOnlyUseControlFlowInfo>>
|
||||||
get() = pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) {
|
get() = pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) {
|
||||||
instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
|
instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
@NotNull BindingContext bindingContext
|
@NotNull BindingContext bindingContext
|
||||||
) {
|
) {
|
||||||
PseudocodeVariablesData pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode.getRootPseudocode(), bindingContext);
|
PseudocodeVariablesData pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode.getRootPseudocode(), bindingContext);
|
||||||
Map<Instruction, Edges<InitControlFlowInfo>> variableInitializers =
|
Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> variableInitializers =
|
||||||
pseudocodeVariablesData.getVariableInitializers();
|
pseudocodeVariablesData.getVariableInitializers();
|
||||||
Map<Instruction, Edges<UseControlFlowInfo>> useStatusData =
|
Map<Instruction, Edges<ReadOnlyControlFlowInfo<VariableUseState>>> useStatusData =
|
||||||
pseudocodeVariablesData.getVariableUseStatusData();
|
pseudocodeVariablesData.getVariableUseStatusData();
|
||||||
String initPrefix = " INIT:";
|
String initPrefix = " INIT:";
|
||||||
String usePrefix = " USE:";
|
String usePrefix = " USE:";
|
||||||
@@ -49,16 +49,16 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
|
|
||||||
dumpInstructions(pseudocode, out, (instruction, next, prev) -> {
|
dumpInstructions(pseudocode, out, (instruction, next, prev) -> {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
Edges<InitControlFlowInfo> initializersEdges = variableInitializers.get(instruction);
|
Edges<ReadOnlyInitControlFlowInfo> initializersEdges = variableInitializers.get(instruction);
|
||||||
Edges<InitControlFlowInfo> previousInitializersEdges = variableInitializers.get(prev);
|
Edges<ReadOnlyInitControlFlowInfo> previousInitializersEdges = variableInitializers.get(prev);
|
||||||
String initializersData = "";
|
String initializersData = "";
|
||||||
if (initializersEdges != null && !initializersEdges.equals(previousInitializersEdges)) {
|
if (initializersEdges != null && !initializersEdges.equals(previousInitializersEdges)) {
|
||||||
initializersData = dumpEdgesData(initPrefix, initializersEdges);
|
initializersData = dumpEdgesData(initPrefix, initializersEdges);
|
||||||
}
|
}
|
||||||
result.append(String.format("%1$-" + initializersColumnWidth + "s", initializersData));
|
result.append(String.format("%1$-" + initializersColumnWidth + "s", initializersData));
|
||||||
|
|
||||||
Edges<UseControlFlowInfo> useStatusEdges = useStatusData.get(instruction);
|
Edges<ReadOnlyControlFlowInfo<VariableUseState>> useStatusEdges = useStatusData.get(instruction);
|
||||||
Edges<UseControlFlowInfo> nextUseStatusEdges = useStatusData.get(next);
|
Edges<ReadOnlyControlFlowInfo<VariableUseState>> nextUseStatusEdges = useStatusData.get(next);
|
||||||
if (useStatusEdges != null && !useStatusEdges.equals(nextUseStatusEdges)) {
|
if (useStatusEdges != null && !useStatusEdges.equals(nextUseStatusEdges)) {
|
||||||
result.append(dumpEdgesData(usePrefix, useStatusEdges));
|
result.append(dumpEdgesData(usePrefix, useStatusEdges));
|
||||||
}
|
}
|
||||||
@@ -69,11 +69,11 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
private static int countDataColumnWidth(
|
private static int countDataColumnWidth(
|
||||||
@NotNull String prefix,
|
@NotNull String prefix,
|
||||||
@NotNull List<Instruction> instructions,
|
@NotNull List<Instruction> instructions,
|
||||||
@NotNull Map<Instruction, Edges<InitControlFlowInfo>> data
|
@NotNull Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> data
|
||||||
) {
|
) {
|
||||||
int maxWidth = 0;
|
int maxWidth = 0;
|
||||||
for (Instruction instruction : instructions) {
|
for (Instruction instruction : instructions) {
|
||||||
Edges<InitControlFlowInfo> edges = data.get(instruction);
|
Edges<ReadOnlyInitControlFlowInfo> edges = data.get(instruction);
|
||||||
if (edges == null) continue;
|
if (edges == null) continue;
|
||||||
int length = dumpEdgesData(prefix, edges).length();
|
int length = dumpEdgesData(prefix, edges).length();
|
||||||
if (maxWidth < length) {
|
if (maxWidth < length) {
|
||||||
@@ -85,10 +85,10 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static <S, I extends ControlFlowInfo<?, S>> String dumpEdgesData(String prefix, @NotNull Edges<I> edges) {
|
private static <S, I extends ReadOnlyControlFlowInfo<S>> String dumpEdgesData(String prefix, @NotNull Edges<I> edges) {
|
||||||
return prefix +
|
return prefix +
|
||||||
" in: " + renderVariableMap(edges.getIncoming()) +
|
" in: " + renderVariableMap(edges.getIncoming().asMap()) +
|
||||||
" out: " + renderVariableMap(edges.getOutgoing());
|
" out: " + renderVariableMap(edges.getOutgoing().asMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <S> String renderVariableMap(javaslang.collection.Map<VariableDescriptor, S> map) {
|
private static <S> String renderVariableMap(javaslang.collection.Map<VariableDescriptor, S> map) {
|
||||||
|
|||||||
Reference in New Issue
Block a user