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