Rename InvocationKind to EventOccurrencesRange

This commit is contained in:
Dmitriy Novozhilov
2020-06-19 15:22:31 +03:00
parent 1dfccf1416
commit d01817ce14
28 changed files with 158 additions and 162 deletions
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.cfa
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
@@ -37,7 +37,7 @@ class FirPropertyInitializationAnalyzer {
val reference = node.fir.calleeReference as? FirResolvedNamedReference ?: return
val symbol = reference.resolvedSymbol as? FirPropertySymbol ?: return
if (symbol !in localProperties) return
val kind = data.getValue(node)[symbol] ?: InvocationKind.ZERO
val kind = data.getValue(node)[symbol] ?: EventOccurrencesRange.ZERO
if (!kind.isDefinitelyVisited()) {
node.fir.source?.let {
reporter.report(FirErrors.UNINITIALIZED_VARIABLE.on(it, symbol))
@@ -47,20 +47,20 @@ class FirPropertyInitializationAnalyzer {
}
private class PropertyInitializationInfo(
map: PersistentMap<FirPropertySymbol, InvocationKind> = persistentMapOf()
) : ControlFlowInfo<PropertyInitializationInfo, FirPropertySymbol, InvocationKind>(map) {
map: PersistentMap<FirPropertySymbol, EventOccurrencesRange> = persistentMapOf()
) : ControlFlowInfo<PropertyInitializationInfo, FirPropertySymbol, EventOccurrencesRange>(map) {
companion object {
val EMPTY = PropertyInitializationInfo()
}
override val constructor: (PersistentMap<FirPropertySymbol, InvocationKind>) -> PropertyInitializationInfo =
override val constructor: (PersistentMap<FirPropertySymbol, EventOccurrencesRange>) -> PropertyInitializationInfo =
::PropertyInitializationInfo
fun merge(other: PropertyInitializationInfo): PropertyInitializationInfo {
var result = this
for (symbol in keys.union(other.keys)) {
val kind1 = this[symbol] ?: InvocationKind.ZERO
val kind2 = other[symbol] ?: InvocationKind.ZERO
val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO
val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO
result = result.put(symbol, kind1 or kind2)
}
return result
@@ -121,8 +121,8 @@ class FirPropertyInitializationAnalyzer {
dataForNode: PropertyInitializationInfo,
symbol: FirPropertySymbol
): PropertyInitializationInfo {
val existingKind = dataForNode[symbol] ?: InvocationKind.ZERO
val kind = existingKind and InvocationKind.EXACTLY_ONCE
val existingKind = dataForNode[symbol] ?: EventOccurrencesRange.ZERO
val kind = existingKind + EventOccurrencesRange.EXACTLY_ONCE
return dataForNode.put(symbol, kind)
}
}
@@ -193,10 +193,10 @@ class FirContractSerializer {
}
}
private fun invocationKindProtobufEnum(kind: InvocationKind): ProtoBuf.Effect.InvocationKind? = when (kind) {
InvocationKind.AT_MOST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE
InvocationKind.EXACTLY_ONCE -> ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE
InvocationKind.AT_LEAST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE
private fun invocationKindProtobufEnum(kind: EventOccurrencesRange): ProtoBuf.Effect.InvocationKind? = when (kind) {
EventOccurrencesRange.AT_MOST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE
EventOccurrencesRange.EXACTLY_ONCE -> ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE
EventOccurrencesRange.AT_LEAST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE
else -> null
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
@@ -69,7 +69,7 @@ fun FirAnonymousFunction.copy(
typeRef: FirTypeRef = this.typeRef,
label: FirLabel? = this.label,
controlFlowGraphReference: FirControlFlowGraphReference = this.controlFlowGraphReference,
invocationKind: InvocationKind? = this.invocationKind
eventOccurrencesRange: EventOccurrencesRange? = this.eventOccurrencesRange
): FirAnonymousFunction {
return buildAnonymousFunction {
this.source = source
@@ -85,7 +85,7 @@ fun FirAnonymousFunction.copy(
this.typeRef = typeRef
this.label = label
this.controlFlowGraphReference = controlFlowGraphReference
this.invocationKind = invocationKind
this.eventOccurrencesRange = eventOccurrencesRange
}
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.deserialization
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription
import org.jetbrains.kotlin.fir.contracts.description.*
@@ -60,7 +60,7 @@ class FirContractDeserializer(private val c: FirDeserializationContext) {
val invocationKind = if (proto.hasKind())
proto.kind.toDescriptorInvocationKind() ?: return null
else
InvocationKind.UNKNOWN
EventOccurrencesRange.UNKNOWN
ConeCallsEffectDeclaration(callable, invocationKind)
}
}
@@ -141,10 +141,10 @@ class FirContractDeserializer(private val c: FirDeserializationContext) {
ConeBooleanValueParameterReference(valueParameterIndex, name)
}
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): InvocationKind? = when (this) {
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> InvocationKind.AT_MOST_ONCE
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> InvocationKind.EXACTLY_ONCE
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> InvocationKind.AT_LEAST_ONCE
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): EventOccurrencesRange? = when (this) {
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> EventOccurrencesRange.AT_MOST_ONCE
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> EventOccurrencesRange.EXACTLY_ONCE
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> EventOccurrencesRange.AT_LEAST_ONCE
}
private fun extractType(proto: ProtoBuf.Expression): ConeKotlinType? {
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.dfa.cfg
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.declarations.*
@@ -207,7 +207,7 @@ class ControlFlowGraphBuilder {
}
fun enterAnonymousFunction(anonymousFunction: FirAnonymousFunction): Pair<PostponedLambdaEnterNode?, FunctionEnterNode> {
val invocationKind = anonymousFunction.invocationKind
val invocationKind = anonymousFunction.eventOccurrencesRange
var previousNodeIsNew = false
val symbol = anonymousFunction.symbol
@@ -256,15 +256,15 @@ class ControlFlowGraphBuilder {
}
}
private val InvocationKind?.hasTowardEdge: Boolean
private val EventOccurrencesRange?.hasTowardEdge: Boolean
get() = when (this) {
InvocationKind.AT_MOST_ONCE, InvocationKind.UNKNOWN -> true
EventOccurrencesRange.AT_MOST_ONCE, EventOccurrencesRange.UNKNOWN -> true
else -> false
}
private val InvocationKind?.hasBackEdge: Boolean
private val EventOccurrencesRange?.hasBackEdge: Boolean
get() = when (this) {
InvocationKind.AT_LEAST_ONCE, InvocationKind.UNKNOWN -> true
EventOccurrencesRange.AT_LEAST_ONCE, EventOccurrencesRange.UNKNOWN -> true
else -> false
}
@@ -293,7 +293,7 @@ class ControlFlowGraphBuilder {
lastNodes.push(postponedExitNode)
}
val invocationKind = anonymousFunction.invocationKind
val invocationKind = anonymousFunction.eventOccurrencesRange
if (invocationKind != null) {
addEdge(exitNode, postponedExitNode, preferredKind = EdgeKind.CfgForward)
} else {
@@ -301,7 +301,7 @@ class ControlFlowGraphBuilder {
CFGNode.addJustKindEdge(postponedEnterNode, postponedExitNode, kind, propagateDeadness = true)
}
if (invocationKind == InvocationKind.EXACTLY_ONCE && shouldPassFlowFromInplaceLambda.top()) {
if (invocationKind == EventOccurrencesRange.EXACTLY_ONCE && shouldPassFlowFromInplaceLambda.top()) {
exitsFromCompletedPostponedAnonymousFunctions += postponedExitNode
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.transformers
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.contracts.description.ConeCallsEffectDeclaration
import org.jetbrains.kotlin.fir.contracts.effects
@@ -19,14 +19,14 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.compose
object InvocationKindTransformer : FirTransformer<Nothing?>() {
private object ArgumentsTransformer : FirTransformer<Pair<Map<FirExpression, InvocationKind>, InvocationKind?>>() {
override fun <E : FirElement> transformElement(element: E, data: Pair<Map<FirExpression, InvocationKind>, InvocationKind?>): CompositeTransformResult<E> {
private object ArgumentsTransformer : FirTransformer<Pair<Map<FirExpression, EventOccurrencesRange>, EventOccurrencesRange?>>() {
override fun <E : FirElement> transformElement(element: E, data: Pair<Map<FirExpression, EventOccurrencesRange>, EventOccurrencesRange?>): CompositeTransformResult<E> {
return element.compose()
}
override fun transformAnonymousFunction(
anonymousFunction: FirAnonymousFunction,
data: Pair<Map<FirExpression, InvocationKind>, InvocationKind?>
data: Pair<Map<FirExpression, EventOccurrencesRange>, EventOccurrencesRange?>
): CompositeTransformResult<FirStatement> {
val kind = data.second ?: data.first[anonymousFunction]
if (kind != null) {
@@ -37,7 +37,7 @@ object InvocationKindTransformer : FirTransformer<Nothing?>() {
override fun transformLambdaArgumentExpression(
lambdaArgumentExpression: FirLambdaArgumentExpression,
data: Pair<Map<FirExpression, InvocationKind>, InvocationKind?>
data: Pair<Map<FirExpression, EventOccurrencesRange>, EventOccurrencesRange?>
): CompositeTransformResult<FirStatement> {
return data.first[lambdaArgumentExpression]?.let {
(lambdaArgumentExpression.transformChildren(this, data.first to it) as FirStatement).compose()
@@ -46,7 +46,7 @@ object InvocationKindTransformer : FirTransformer<Nothing?>() {
override fun transformNamedArgumentExpression(
namedArgumentExpression: FirNamedArgumentExpression,
data: Pair<Map<FirExpression, InvocationKind>, InvocationKind?>
data: Pair<Map<FirExpression, EventOccurrencesRange>, EventOccurrencesRange?>
): CompositeTransformResult<FirStatement> {
return data.first[namedArgumentExpression]?.let {
(namedArgumentExpression.transformChildren(this, data.first to it) as FirStatement).compose()
@@ -74,7 +74,7 @@ object InvocationKindTransformer : FirTransformer<Nothing?>() {
parameter to argument
}.toMap()
val invocationKindMapping = mutableMapOf<FirExpression, InvocationKind>()
val invocationKindMapping = mutableMapOf<FirExpression, EventOccurrencesRange>()
for (effect in callsEffects) {
// TODO: Support callsInPlace contracts on receivers
val valueParameter = function.valueParameters.getOrNull(effect.valueParameterReference.parameterIndex) ?: continue
@@ -83,7 +83,7 @@ object InvocationKindTransformer : FirTransformer<Nothing?>() {
}
if (isInline) {
for (argument in functionCall.arguments) {
invocationKindMapping.putIfAbsent(argument, InvocationKind.UNKNOWN)
invocationKindMapping.putIfAbsent(argument, EventOccurrencesRange.UNKNOWN)
}
}
if (invocationKindMapping.isEmpty()) {
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.contracts.description.*
@@ -65,7 +65,7 @@ class ConeEffectExtractor(
FirContractsDslNames.CALLS_IN_PLACE -> {
val reference = functionCall.arguments[0].accept(this, null) as? ConeValueParameterReference
?: return null
val kind = functionCall.arguments.getOrNull(1)?.parseInvocationKind() ?: InvocationKind.UNKNOWN
val kind = functionCall.arguments.getOrNull(1)?.parseInvocationKind() ?: EventOccurrencesRange.UNKNOWN
ConeCallsEffectDeclaration(reference, kind)
}
@@ -165,14 +165,14 @@ class ConeEffectExtractor(
return ConeIsInstancePredicate(arg, type, isNegated)
}
private fun FirExpression.parseInvocationKind(): InvocationKind? {
private fun FirExpression.parseInvocationKind(): EventOccurrencesRange? {
if (this !is FirQualifiedAccessExpression) return null
val resolvedId = toResolvedCallableSymbol()?.callableId ?: return null
return when (resolvedId) {
FirContractsDslNames.EXACTLY_ONCE_KIND -> InvocationKind.EXACTLY_ONCE
FirContractsDslNames.AT_LEAST_ONCE_KIND -> InvocationKind.AT_LEAST_ONCE
FirContractsDslNames.AT_MOST_ONCE_KIND -> InvocationKind.AT_MOST_ONCE
FirContractsDslNames.UNKNOWN_KIND -> InvocationKind.UNKNOWN
FirContractsDslNames.EXACTLY_ONCE_KIND -> EventOccurrencesRange.EXACTLY_ONCE
FirContractsDslNames.AT_LEAST_ONCE_KIND -> EventOccurrencesRange.AT_LEAST_ONCE
FirContractsDslNames.AT_MOST_ONCE_KIND -> EventOccurrencesRange.AT_MOST_ONCE
FirContractsDslNames.UNKNOWN_KIND -> EventOccurrencesRange.UNKNOWN
else -> null
}
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.declarations
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
@@ -37,7 +37,7 @@ abstract class FirAnonymousFunction : FirFunction<FirAnonymousFunction>, FirExpr
abstract override val typeRef: FirTypeRef
abstract override val symbol: FirAnonymousFunctionSymbol
abstract val label: FirLabel?
abstract val invocationKind: InvocationKind?
abstract val eventOccurrencesRange: EventOccurrencesRange?
abstract val isLambda: Boolean
abstract override val typeParameters: List<FirTypeParameter>
@@ -53,7 +53,7 @@ abstract class FirAnonymousFunction : FirFunction<FirAnonymousFunction>, FirExpr
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
abstract fun replaceInvocationKind(newInvocationKind: InvocationKind?)
abstract fun replaceInvocationKind(newEventOccurrencesRange: EventOccurrencesRange?)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirAnonymousFunction
@@ -6,19 +6,16 @@
package org.jetbrains.kotlin.fir.declarations.builder
import kotlin.contracts.*
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirDeclarationAttributes
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.builder.FirFunctionBuilder
import org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirBlock
@@ -28,7 +25,6 @@ import org.jetbrains.kotlin.fir.references.impl.FirEmptyControlFlowGraphReferenc
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.*
/*
* This file was generated automatically
@@ -49,7 +45,7 @@ class FirAnonymousFunctionBuilder : FirFunctionBuilder, FirAnnotationContainerBu
override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
lateinit var symbol: FirAnonymousFunctionSymbol
var label: FirLabel? = null
var invocationKind: InvocationKind? = null
var eventOccurrencesRange: EventOccurrencesRange? = null
var isLambda: Boolean by kotlin.properties.Delegates.notNull<Boolean>()
val typeParameters: MutableList<FirTypeParameter> = mutableListOf()
@@ -67,7 +63,7 @@ class FirAnonymousFunctionBuilder : FirFunctionBuilder, FirAnnotationContainerBu
typeRef,
symbol,
label,
invocationKind,
eventOccurrencesRange,
isLambda,
typeParameters,
)
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.declarations.impl
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
@@ -40,7 +40,7 @@ internal class FirAnonymousFunctionImpl(
override var typeRef: FirTypeRef,
override val symbol: FirAnonymousFunctionSymbol,
override var label: FirLabel?,
override var invocationKind: InvocationKind?,
override var eventOccurrencesRange: EventOccurrencesRange?,
override val isLambda: Boolean,
override val typeParameters: MutableList<FirTypeParameter>,
) : FirAnonymousFunction() {
@@ -122,7 +122,7 @@ internal class FirAnonymousFunctionImpl(
typeRef = newTypeRef
}
override fun replaceInvocationKind(newInvocationKind: InvocationKind?) {
invocationKind = newInvocationKind
override fun replaceInvocationKind(newInvocationKind: EventOccurrencesRange?) {
eventOccurrencesRange = newInvocationKind
}
}
@@ -449,8 +449,8 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
anonymousFunction.valueParameters.renderParameters()
print(": ")
anonymousFunction.returnTypeRef.accept(this)
if (anonymousFunction.invocationKind != null) {
print(" <kind=${anonymousFunction.invocationKind}> ")
if (anonymousFunction.eventOccurrencesRange != null) {
print(" <kind=${anonymousFunction.eventOccurrencesRange}> ")
}
if (mode.renderLambdaBodies) {
anonymousFunction.body?.renderBody()
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.contracts.description
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
/**
* Effect with condition attached to it.
@@ -41,7 +41,7 @@ class ConeReturnsEffectDeclaration(val value: ConeConstantReference) : ConeEffec
* Effect which specifies, that during execution of subroutine, callable [valueParameterReference] will be invoked
* [kind] amount of times, and will never be invoked after subroutine call is finished.
*/
class ConeCallsEffectDeclaration(val valueParameterReference: ConeValueParameterReference, val kind: InvocationKind) : ConeEffectDeclaration() {
class ConeCallsEffectDeclaration(val valueParameterReference: ConeValueParameterReference, val kind: EventOccurrencesRange) : ConeEffectDeclaration() {
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitCallsEffectDeclaration(this, data)
}
@@ -266,7 +266,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
parentArg(function, "F", anonymousFunction)
+symbol("FirAnonymousFunctionSymbol")
+field(label, nullable = true)
+field(invocationKindType, nullable = true, withReplace = true).apply {
+field(eventOccurrencesRangeType, nullable = true, withReplace = true).apply {
isMutable = true
}
+booleanField("isLambda")
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.tree.generator
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
@@ -25,7 +25,7 @@ val jumpTargetType = type("fir", "FirTarget")
val constKindType = generatedType("expressions", "FirConstKind")
val operationType = type("fir.expressions", "FirOperation")
val classKindType = type(ClassKind::class)
val invocationKindType = type(InvocationKind::class)
val eventOccurrencesRangeType = type(EventOccurrencesRange::class)
val varianceType = type(Variance::class)
val nameType = type(Name::class)
val visibilityType = type(Visibility::class)
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.cfg
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
interface ControlFlowBuilder {
// Subroutines
fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null)
fun enterSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange? = null)
fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode
fun exitSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange? = null): Pseudocode
val currentSubroutine: KtElement
val returnSubroutine: KtElement
@@ -50,7 +50,7 @@ interface ControlFlowBuilder {
fun declareVariable(property: KtVariableDeclaration)
fun declareFunction(subroutine: KtElement, pseudocode: Pseudocode)
fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, invocationKind: InvocationKind)
fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, eventOccurrencesRange: EventOccurrencesRange)
fun declareEntryOrObject(entryOrObject: KtClassOrObject)
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.cfg
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -139,12 +139,12 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.exitTryFinally()
}
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
delegateBuilder.enterSubroutine(subroutine, invocationKind)
override fun enterSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange?) {
delegateBuilder.enterSubroutine(subroutine, eventOccurrencesRange)
}
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode =
delegateBuilder.exitSubroutine(subroutine, invocationKind)
override fun exitSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange?): Pseudocode =
delegateBuilder.exitSubroutine(subroutine, eventOccurrencesRange)
override val currentSubroutine: KtElement
get() = delegateBuilder.currentSubroutine
@@ -185,8 +185,8 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.declareFunction(subroutine, pseudocode)
}
override fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, invocationKind: InvocationKind) {
delegateBuilder.declareInlinedFunction(subroutine, pseudocode, invocationKind)
override fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, eventOccurrencesRange: EventOccurrencesRange) {
delegateBuilder.declareInlinedFunction(subroutine, pseudocode, eventOccurrencesRange)
}
override fun declareEntryOrObject(entryOrObject: KtClassOrObject) {
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValu
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.contracts.description.canBeRevisited
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
import org.jetbrains.kotlin.descriptors.*
@@ -79,8 +79,8 @@ class ControlFlowProcessor(
return pseudocode
}
private fun generate(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode {
builder.enterSubroutine(subroutine, invocationKind)
private fun generate(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange? = null): Pseudocode {
builder.enterSubroutine(subroutine, eventOccurrencesRange)
val cfpVisitor = CFPVisitor(builder)
if (subroutine is KtDeclarationWithBody && subroutine !is KtSecondaryConstructor) {
val valueParameters = subroutine.valueParameters
@@ -97,7 +97,7 @@ class ControlFlowProcessor(
} else {
cfpVisitor.generateInstructions(subroutine)
}
return builder.exitSubroutine(subroutine, invocationKind)
return builder.exitSubroutine(subroutine, eventOccurrencesRange)
}
private fun generateImplicitReturnValue(bodyExpression: KtExpression, subroutine: KtElement) {
@@ -1035,11 +1035,11 @@ class ControlFlowProcessor(
return parent.parent is KtDoWhileExpression
}
private fun visitFunction(function: KtFunction, invocationKind: InvocationKind? = null) {
if (invocationKind == null) {
private fun visitFunction(function: KtFunction, eventOccurrencesRange: EventOccurrencesRange? = null) {
if (eventOccurrencesRange == null) {
processLocalDeclaration(function)
} else {
visitInlinedFunction(function, invocationKind)
visitInlinedFunction(function, eventOccurrencesRange)
}
val isAnonymousFunction = function is KtFunctionLiteral || function.name == null
@@ -1048,7 +1048,7 @@ class ControlFlowProcessor(
}
}
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, invocationKind: InvocationKind) {
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, eventOccurrencesRange: EventOccurrencesRange) {
// Defer emitting of inlined declaration
deferredGeneratorsStack.peek().add({ builder ->
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
@@ -1056,13 +1056,13 @@ class ControlFlowProcessor(
builder.bindLabel(beforeDeclaration)
if (!invocationKind.isDefinitelyVisited()) {
if (!eventOccurrencesRange.isDefinitelyVisited()) {
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
}
generate(lambdaFunctionLiteral, invocationKind)
generate(lambdaFunctionLiteral, eventOccurrencesRange)
if (invocationKind.canBeRevisited()) {
if (eventOccurrencesRange.canBeRevisited()) {
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
}
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -64,9 +64,9 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
return worker
}
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
override fun enterSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange?) {
val builder = builder
val shouldInlnie = invocationKind != null
val shouldInlnie = eventOccurrencesRange != null
if (builder != null && subroutine is KtFunctionLiteral) {
pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie)
} else {
@@ -76,16 +76,16 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
delegateBuilder.enterSubroutine(subroutine)
}
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode {
super.exitSubroutine(subroutine, invocationKind)
override fun exitSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange?): Pseudocode {
super.exitSubroutine(subroutine, eventOccurrencesRange)
delegateBuilder.exitBlockScope(subroutine)
val worker = popBuilder()
if (!builders.empty()) {
val builder = builders.peek()
if (invocationKind == null) {
if (eventOccurrencesRange == null) {
builder.declareFunction(subroutine, worker.pseudocode)
} else {
builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind)
builder.declareInlinedFunction(subroutine, worker.pseudocode, eventOccurrencesRange)
}
}
return worker.pseudocode
@@ -154,7 +154,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override val currentLoop: KtLoopExpression?
get() = if (loopInfo.empty()) null else loopInfo.peek().element
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
override fun enterSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange?) {
val blockInfo = SubroutineInfo(
subroutine,
/* entry point */ createUnboundLabel(),
@@ -215,7 +215,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
}
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode {
override fun exitSubroutine(subroutine: KtElement, eventOccurrencesRange: EventOccurrencesRange?): Pseudocode {
getSubroutineExitPoint(subroutine)?.let { bindLabel(it) }
pseudocode.addExitInstruction(SubroutineExitInstruction(subroutine, currentScope, false))
bindLabel(error)
@@ -273,8 +273,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
add(LocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope))
}
override fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, invocationKind: InvocationKind) {
add(InlinedLocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope, invocationKind))
override fun declareInlinedFunction(subroutine: KtElement, pseudocode: Pseudocode, eventOccurrencesRange: EventOccurrencesRange) {
add(InlinedLocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope, eventOccurrencesRange))
}
override fun declareEntryOrObject(entryOrObject: KtClassOrObject) {
@@ -21,14 +21,14 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.BlockScope
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.psi.KtElement
class InlinedLocalFunctionDeclarationInstruction(
element: KtElement,
body: Pseudocode,
blockScope: BlockScope,
val kind: InvocationKind
val kind: EventOccurrencesRange
) : LocalFunctionDeclarationInstruction(element, body, blockScope) {
override fun createCopy(): InstructionImpl = InlinedLocalFunctionDeclarationInstruction(element, body, blockScope, kind)
@@ -94,7 +94,7 @@ class ContractDeserializerImpl(
val invocationKind = if (proto.hasKind())
proto.kind.toDescriptorInvocationKind() ?: return null
else
InvocationKind.UNKNOWN
EventOccurrencesRange.UNKNOWN
CallsEffectDeclaration(callable, invocationKind)
}
}
@@ -165,10 +165,10 @@ class ContractDeserializerImpl(
BooleanVariableReference(parameterDescriptor)
}
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): InvocationKind? = when (this) {
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> InvocationKind.AT_MOST_ONCE
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> InvocationKind.EXACTLY_ONCE
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> InvocationKind.AT_LEAST_ONCE
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): EventOccurrencesRange? = when (this) {
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> EventOccurrencesRange.AT_MOST_ONCE
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> EventOccurrencesRange.EXACTLY_ONCE
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> EventOccurrencesRange.AT_LEAST_ONCE
}
private fun extractType(proto: ProtoBuf.Expression): KotlinType? {
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.contracts.parsing.effects
import org.jetbrains.kotlin.contracts.description.CallsEffectDeclaration
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.contracts.parsing.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
@@ -45,7 +45,7 @@ internal class PsiCallsEffectParser(
val kindArgument = resolvedCall.valueArgumentsByIndex?.getOrNull(1)
val kind = when (kindArgument) {
is DefaultValueArgument -> InvocationKind.UNKNOWN
is DefaultValueArgument -> EventOccurrencesRange.UNKNOWN
is ExpressionValueArgument -> kindArgument.valueArgument?.getArgumentExpression()?.toInvocationKind(callContext.bindingContext)
else -> null
}
@@ -59,15 +59,15 @@ internal class PsiCallsEffectParser(
return CallsEffectDeclaration(lambda, kind)
}
private fun KtExpression.toInvocationKind(bindingContext: BindingContext): InvocationKind? {
private fun KtExpression.toInvocationKind(bindingContext: BindingContext): EventOccurrencesRange? {
val descriptor = this.getResolvedCall(bindingContext)?.resultingDescriptor ?: return null
if (!descriptor.parents.first().isInvocationKindEnum()) return null
return when (descriptor.fqNameSafe.shortName()) {
ContractsDslNames.AT_MOST_ONCE_KIND -> InvocationKind.AT_MOST_ONCE
ContractsDslNames.EXACTLY_ONCE_KIND -> InvocationKind.EXACTLY_ONCE
ContractsDslNames.AT_LEAST_ONCE_KIND -> InvocationKind.AT_LEAST_ONCE
ContractsDslNames.UNKNOWN_KIND -> InvocationKind.UNKNOWN
ContractsDslNames.AT_MOST_ONCE_KIND -> EventOccurrencesRange.AT_MOST_ONCE
ContractsDslNames.EXACTLY_ONCE_KIND -> EventOccurrencesRange.EXACTLY_ONCE
ContractsDslNames.AT_LEAST_ONCE_KIND -> EventOccurrencesRange.AT_LEAST_ONCE
ContractsDslNames.UNKNOWN_KIND -> EventOccurrencesRange.UNKNOWN
else -> null
}
}
@@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.cfg.LeakingThisDescriptor;
import org.jetbrains.kotlin.cfg.TailRecursionKind;
import org.jetbrains.kotlin.contracts.description.InvocationKind;
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange;
import org.jetbrains.kotlin.contracts.model.Computation;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
@@ -221,7 +221,7 @@ public interface BindingContext {
WritableSlice<PropertyDescriptor, Boolean> IS_UNINITIALIZED = Slices.createSimpleSetSlice();
WritableSlice<PropertyDescriptor, Boolean> MUST_BE_LATEINIT = Slices.createSimpleSetSlice();
WritableSlice<KtLambdaExpression, InvocationKind> LAMBDA_INVOCATIONS = Slices.createSimpleSlice();
WritableSlice<KtLambdaExpression, EventOccurrencesRange> LAMBDA_INVOCATIONS = Slices.createSimpleSlice();
WritableSlice<KtLambdaExpression, Boolean> BLOCK = new SetSlice<KtLambdaExpression>(DO_NOTHING) {
@Override
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.contracts.description.CallsEffectDeclaration
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
@@ -147,7 +147,7 @@ class CapturingInClosureChecker : CallChecker {
val contractDescription = function.getUserData(ContractProviderKey)?.getContractDescription() ?: return false
val effect = contractDescription.effects.filterIsInstance<CallsEffectDeclaration>()
.find { it.variableReference.descriptor == parameter.original } ?: return false
return effect.kind == InvocationKind.EXACTLY_ONCE
return effect.kind == EventOccurrencesRange.EXACTLY_ONCE
}
private fun isExactlyOnceContract(bindingContext: BindingContext, argument: KtFunction): Boolean {
@@ -53,7 +53,7 @@ class ReturnsEffectDeclaration(val value: ConstantReference) : EffectDeclaration
* Effect which specifies, that during execution of subroutine, callable [variableReference] will be invoked
* [kind] amount of times, and will never be invoked after subroutine call is finished.
*/
class CallsEffectDeclaration(val variableReference: VariableReference, val kind: InvocationKind) : EffectDeclaration {
class CallsEffectDeclaration(val variableReference: VariableReference, val kind: EventOccurrencesRange) : EffectDeclaration {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitCallsEffectDeclaration(this, data)
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2018 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.contracts.description
import kotlin.math.max
import kotlin.math.min
enum class EventOccurrencesRange(private val left: Int, private val right: Int) {
ZERO(0, 0), // 0..0
AT_MOST_ONCE(0, 1), // 0..1
EXACTLY_ONCE(1, 1), // 1..1
AT_LEAST_ONCE(1, 2), // 1..*
UNKNOWN(0, 2); // 0..*
companion object {
private fun fromRange(left: Int, right: Int): EventOccurrencesRange = when (min(left, 1) to min(right, 2)) {
0 to 0 -> ZERO
0 to 1 -> AT_MOST_ONCE
1 to 1 -> EXACTLY_ONCE
1 to 2 -> AT_LEAST_ONCE
0 to 2 -> UNKNOWN
else -> throw IllegalArgumentException()
}
fun or(x: EventOccurrencesRange, y: EventOccurrencesRange): EventOccurrencesRange = fromRange(min(x.left, y.left), max(x.right, y.right))
fun plus(x: EventOccurrencesRange, y: EventOccurrencesRange): EventOccurrencesRange = fromRange(x.left + y.left, x.right + y.right)
}
infix fun or(other: EventOccurrencesRange): EventOccurrencesRange = Companion.or(this, other)
operator fun plus(other: EventOccurrencesRange): EventOccurrencesRange = Companion.plus(this, other)
}
fun EventOccurrencesRange.isDefinitelyVisited(): Boolean = this == EventOccurrencesRange.EXACTLY_ONCE || this == EventOccurrencesRange.AT_LEAST_ONCE
fun EventOccurrencesRange.canBeRevisited(): Boolean = this == EventOccurrencesRange.UNKNOWN || this == EventOccurrencesRange.AT_LEAST_ONCE
@@ -1,38 +0,0 @@
/*
* Copyright 2010-2018 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.contracts.description
import kotlin.math.max
import kotlin.math.min
enum class InvocationKind(private val left: Int, private val right: Int) {
ZERO(0, 0), // 0..0
AT_MOST_ONCE(0, 1), // 0..1
EXACTLY_ONCE(1, 1), // 1..1
AT_LEAST_ONCE(1, 2), // 1..*
UNKNOWN(0, 2); // 0..*
companion object {
private fun fromRange(left: Int, right: Int): InvocationKind = when (min(left, 1) to min(right, 2)) {
0 to 0 -> ZERO
0 to 1 -> AT_MOST_ONCE
1 to 1 -> EXACTLY_ONCE
1 to 2 -> AT_LEAST_ONCE
0 to 2 -> UNKNOWN
else -> throw IllegalArgumentException()
}
fun or(x: InvocationKind, y: InvocationKind): InvocationKind = fromRange(min(x.left, y.left), max(x.right, y.right))
fun and(x: InvocationKind, y: InvocationKind): InvocationKind = fromRange(x.left + y.left, x.right + y.right)
}
infix fun or(other: InvocationKind): InvocationKind = Companion.or(this, other)
infix fun and(other: InvocationKind): InvocationKind = Companion.and(this, other)
}
fun InvocationKind.isDefinitelyVisited(): Boolean = this == InvocationKind.EXACTLY_ONCE || this == InvocationKind.AT_LEAST_ONCE
fun InvocationKind.canBeRevisited(): Boolean = this == InvocationKind.UNKNOWN || this == InvocationKind.AT_LEAST_ONCE
@@ -16,12 +16,12 @@
package org.jetbrains.kotlin.contracts.model.structure
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.ESValue
import org.jetbrains.kotlin.contracts.model.SimpleEffect
data class ESCalls(val callable: ESValue, val kind: InvocationKind) : SimpleEffect() {
data class ESCalls(val callable: ESValue, val kind: EventOccurrencesRange) : SimpleEffect() {
override fun isImplies(other: ESEffect): Boolean? {
if (other !is ESCalls) return null
@@ -188,10 +188,10 @@ class ContractSerializer {
}
}
private fun invocationKindProtobufEnum(kind: InvocationKind): ProtoBuf.Effect.InvocationKind? = when (kind) {
InvocationKind.AT_MOST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE
InvocationKind.EXACTLY_ONCE -> ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE
InvocationKind.AT_LEAST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE
private fun invocationKindProtobufEnum(kind: EventOccurrencesRange): ProtoBuf.Effect.InvocationKind? = when (kind) {
EventOccurrencesRange.AT_MOST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE
EventOccurrencesRange.EXACTLY_ONCE -> ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE
EventOccurrencesRange.AT_LEAST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE
else -> null
}