All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.fir.analysis.cfa.PathAwareControlFlowInfo.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.fir.analysis.cfa

import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.CFGNode
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.EdgeLabel
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.NormalPath
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.TryExpressionExitNode

abstract class PathAwareControlFlowInfo

, S : ControlFlowInfo>( map: PersistentMap, ) : ControlFlowInfo(map) { internal val infoAtNormalPath: S get() = map.getValue(NormalPath) private val hasNormalPath: Boolean get() = map.containsKey(NormalPath) fun applyLabel(node: CFGNode<*>, label: EdgeLabel): P { if (label.isNormal) { // Special case: when we exit the try expression, null label means a normal path. // Filter out any info bound to non-null label // One day, if we allow multiple edges between nodes with different labels, e.g., labeling all paths in try/catch/finally, // instead of this kind of special handling, proxy enter/exit nodes per label are preferred. if (node is TryExpressionExitNode) { return if (hasNormalPath) { constructor(persistentMapOf(NormalPath to infoAtNormalPath)) } else { /* This means no info for normal path. */ empty() } } // In general, null label means no additional path info, hence return `this` as-is. @Suppress("UNCHECKED_CAST") return this as P } val hasAbnormalLabels = map.keys.any { !it.isNormal } return if (hasAbnormalLabels) { // { |-> ... l1 |-> I1, l2 |-> I2, ... } // | l1 // path exit: if the given info has non-null labels, this acts like a filtering // { |-> I1 } // NB: remove the path info if (map.keys.contains(label)) { constructor(persistentMapOf(NormalPath to map[label]!!)) } else { /* This means no info for the specific label. */ empty() } } else { // { |-> ... } // empty path info // | l1 // path entry // { l1 -> ... } // now, every info bound to the label constructor(persistentMapOf(label to infoAtNormalPath)) } } override fun merge(other: P): P { var resultMap = persistentMapOf() for (label in keys.union(other.keys)) { // disjoint merging to preserve paths. i.e., merge the property initialization info if and only if both have the key. // merge({ |-> I1 }, { |-> I2, l1 |-> I3 }) // == { |-> merge(I1, I2), l1 |-> I3 } val i1 = this[label] val i2 = other[label] resultMap = when { i1 != null && i2 != null -> resultMap.put(label, i1.merge(i2)) i1 != null -> resultMap.put(label, i1) i2 != null -> resultMap.put(label, i2) else -> throw IllegalStateException() } } return constructor(resultMap) } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy