[FIR] Add stage for resolve contract desription

This commit is contained in:
Dmitriy Novozhilov
2020-04-10 12:39:12 +03:00
parent 9b903b5e13
commit 452fb3e723
16 changed files with 468 additions and 8 deletions
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
@@ -18,10 +19,8 @@ import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCallBuilder
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
fun FirFunctionCall.copy(
@@ -100,6 +99,15 @@ fun FirTypeRef.resolvedTypeFromPrototype(
}
}
fun FirTypeRef.errorTypeFromPrototype(
diagnostic: ConeDiagnostic
): FirErrorTypeRef {
return buildErrorTypeRef {
source = this@errorTypeFromPrototype.source
this.diagnostic = diagnostic
}
}
fun FirTypeParameter.copy(
bounds: List<FirTypeRef> = this.bounds,
annotations: List<FirAnnotationCall> = this.annotations
@@ -953,6 +953,16 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
return controlFlowGraph
}
// ----------------------------------- Contract description -----------------------------------
fun enterContractDescription() {
graphBuilder.enterContractDescription().mergeIncomingFlow()
}
fun exitContractDescription() {
graphBuilder.exitContractDescription()
}
// ------------------------------------------------------ Utils ------------------------------------------------------
private var CFGNode<*>.flow: FLOW
@@ -104,6 +104,8 @@ fun CFGNode<*>.render(): String =
is LocalClassExitNode -> "Exit local class ${owner.name}"
is AnonymousObjectExitNode -> "Exit anonymous object"
is ContractDescriptionEnterNode -> "Enter contract description"
is AbstractBinaryExitNode -> throw IllegalStateException()
},
)
@@ -520,6 +520,13 @@ class StubNode(owner: ControlFlowGraph, level: Int, id: Int) : CFGNode<FirStub>(
}
}
class ContractDescriptionEnterNode(owner: ControlFlowGraph, level: Int, id: Int) : CFGNode<FirStub>(owner, level, id) {
override val fir: FirStub = FirStub
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitContractDescriptionEnterNode(this, data)
}
}
class VariableDeclarationNode(owner: ControlFlowGraph, override val fir: FirProperty, level: Int, id: Int) : CFGNode<FirProperty>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitVariableDeclarationNode(this, data)
@@ -870,6 +870,22 @@ class ControlFlowGraphBuilder {
}
}
// ----------------------------------- Contract description -----------------------------------
fun enterContractDescription(): CFGNode<*> {
graphs.push(ControlFlowGraph(null, "contract description", ControlFlowGraph.Kind.TopLevel))
val node = createContractDescriptionEnterNode().also {
graph.enterNode = it
}
lexicalScopes.push(stackOf(node))
return node
}
fun exitContractDescription() {
lexicalScopes.pop()
graphs.pop()
}
// -------------------------------------------------------------------------------------------------------------------------
private fun addNodeThatReturnsNothing(node: CFGNode<*>, preferredKind: EdgeKind = EdgeKind.Simple) {
@@ -11,6 +11,9 @@ import org.jetbrains.kotlin.fir.expressions.*
fun ControlFlowGraphBuilder.createStubNode(): StubNode = StubNode(graph, levelCounter, createId())
fun ControlFlowGraphBuilder.createContractDescriptionEnterNode(): ContractDescriptionEnterNode =
ContractDescriptionEnterNode(graph, levelCounter, createId())
fun ControlFlowGraphBuilder.createLoopExitNode(fir: FirLoop): LoopExitNode = LoopExitNode(graph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createLoopEnterNode(fir: FirLoop): LoopEnterNode = LoopEnterNode(graph, fir, levelCounter, createId())
@@ -269,6 +269,10 @@ abstract class ControlFlowGraphVisitor<out R, in D> {
return visitNode(node, data)
}
open fun visitContractDescriptionEnterNode(node: ContractDescriptionEnterNode, data: D): R {
return visitNode(node, data)
}
open fun visitVariableDeclarationNode(node: VariableDeclarationNode, data: D): R {
return visitNode(node, data)
}
@@ -53,6 +53,8 @@ class ConeTypeMismatchError(val expectedType: ConeKotlinType, val actualType: Co
get() = "Type mismatch. Expected: $expectedType, Actual: $actualType"
}
class ConeContractDescriptionError(override val reason: String) : ConeDiagnostic()
private fun describeSymbol(symbol: AbstractFirBasedSymbol<*>): String {
return when (symbol) {
is FirClassLikeSymbol<*> -> symbol.classId.asString()
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformerAdapter
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitTypeBodyResolveTransformerAdapter
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractResolveTransformerAdapter
import org.jetbrains.kotlin.fir.visitors.FirTransformer
// TODO: add FirSession parameter
@@ -22,6 +23,7 @@ fun FirResolvePhase.createTransformerByPhase(scopeSession: ScopeSession): FirTra
SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsTransformer()
TYPES -> FirTypeResolveTransformerAdapter(scopeSession)
STATUS -> FirStatusResolveTransformerAdapter()
CONTRACTS -> FirContractResolveTransformerAdapter(scopeSession)
IMPLICIT_TYPES_BODY_RESOLVE -> FirImplicitTypeBodyResolveTransformerAdapter(scopeSession)
BODY_RESOLVE -> FirBodyResolveTransformerAdapter(scopeSession)
}
@@ -38,7 +38,7 @@ open class FirBodyResolveTransformer(
BodyResolveTransformerComponents(session, scopeSession, this, context)
private val expressionsTransformer = FirExpressionsResolveTransformer(this)
private val declarationsTransformer = FirDeclarationsResolveTransformer(this)
protected open val declarationsTransformer = FirDeclarationsResolveTransformer(this)
private val controlFlowStatementsTransformer = FirControlFlowStatementsResolveTransformer(this)
override fun transformFile(file: FirFile, data: ResolutionMode): CompositeTransformResult<FirFile> {
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.visitors.*
import org.jetbrains.kotlin.name.Name
class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
private var primaryConstructorParametersScope: FirLocalScope? = null
private var containingClass: FirRegularClass? = null
@@ -66,7 +66,7 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer)
}
}
private inline fun <T> withTypeParametersOf(declaration: FirMemberDeclaration, crossinline l: () -> T): T {
protected inline fun <T> withTypeParametersOf(declaration: FirMemberDeclaration, crossinline l: () -> T): T {
if (declaration.typeParameters.isEmpty()) return l()
for (typeParameter in declaration.typeParameters) {
@@ -670,7 +670,7 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer)
return this
}
private inline fun <T> withLabelAndReceiverType(
protected inline fun <T> withLabelAndReceiverType(
labelName: Name?,
owner: FirDeclaration,
type: ConeKotlinType?,
@@ -0,0 +1,179 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
import org.jetbrains.kotlin.contracts.description.InvocationKind
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.contracts.description.*
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
class ConeEffectExtractor(
private val session: FirSession,
private val owner: FirContractDescriptionOwner,
private val valueParameters: List<FirValueParameter>
) : FirDefaultVisitor<ConeContractDescriptionElement?, Nothing?>() {
companion object {
private val BOOLEAN_AND = FirContractsDslNames.id("kotlin", "Boolean", "and")
private val BOOLEAN_OR = FirContractsDslNames.id("kotlin", "Boolean", "or")
private val BOOLEAN_NOT = FirContractsDslNames.id("kotlin", "Boolean", "not")
}
override fun visitElement(element: FirElement, data: Nothing?): ConeContractDescriptionElement? {
return null
}
override fun visitReturnExpression(returnExpression: FirReturnExpression, data: Nothing?): ConeContractDescriptionElement? {
return returnExpression.result.accept(this, data)
}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?): ConeContractDescriptionElement? {
val resolvedId = functionCall.toResolvedCallableSymbol()?.callableId ?: return null
return when (resolvedId) {
FirContractsDslNames.IMPLIES -> {
val effect = functionCall.explicitReceiver?.accept(this, null) as? ConeEffectDeclaration
?: return null
val condition = functionCall.argument.accept(this, null) as? ConeBooleanExpression
?: return null
ConeConditionalEffectDeclaration(effect, condition)
}
FirContractsDslNames.RETURNS -> {
val argument = functionCall.arguments.firstOrNull()
val value = if (argument == null) {
ConeConstantReference.WILDCARD
} else {
argument.accept(this, null) as? ConeConstantReference
?: return null
}
ConeReturnsEffectDeclaration(value)
}
FirContractsDslNames.RETURNS_NOT_NULL -> {
ConeReturnsEffectDeclaration(ConeConstantReference.NULL)
}
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
ConeCallsEffectDeclaration(reference, kind)
}
BOOLEAN_AND, BOOLEAN_OR -> {
val left = functionCall.explicitReceiver?.accept(this, null) as? ConeBooleanExpression ?: return null
val right = functionCall.argument.accept(this, null) as? ConeBooleanExpression ?: return null
val kind = when (resolvedId) {
BOOLEAN_AND -> LogicOperationKind.AND
BOOLEAN_OR -> LogicOperationKind.OR
else -> throw IllegalStateException()
}
ConeBinaryLogicExpression(left, right, kind)
}
BOOLEAN_NOT -> {
val arg = functionCall.explicitReceiver?.accept(this, null) as? ConeBooleanExpression ?: return null
ConeLogicalNot(arg)
}
else -> null
}
}
override fun visitBinaryLogicExpression(
binaryLogicExpression: FirBinaryLogicExpression,
data: Nothing?
): ConeContractDescriptionElement? {
val left = binaryLogicExpression.leftOperand.accept(this, null) as? ConeBooleanExpression ?: return null
val right = binaryLogicExpression.rightOperand.accept(this, null) as? ConeBooleanExpression ?: return null
return ConeBinaryLogicExpression(left, right, binaryLogicExpression.kind)
}
override fun visitOperatorCall(operatorCall: FirOperatorCall, data: Nothing?): ConeContractDescriptionElement? {
val isNegated = when (operatorCall.operation) {
FirOperation.EQ -> false
FirOperation.NOT_EQ -> true
else -> return null
}
val const = operatorCall.arguments[1] as? FirConstExpression<*> ?: return null
if (const.kind != FirConstKind.Null) return null
val arg = operatorCall.arguments[0].accept(this, null) as? ConeValueParameterReference ?: return null
return ConeIsNullPredicate(arg, isNegated)
}
override fun visitQualifiedAccessExpression(
qualifiedAccessExpression: FirQualifiedAccessExpression,
data: Nothing?
): ConeContractDescriptionElement? {
val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return null
val parameter = symbol.fir as? FirValueParameter ?: return null
val index = valueParameters.indexOf(parameter).takeUnless { it < 0 } ?: return null
val type = parameter.returnTypeRef.coneTypeUnsafe<ConeKotlinType>()
val name = parameter.name.asString()
return toValueParameterReference(type, index, name)
}
private fun toValueParameterReference(
type: ConeKotlinType,
index: Int,
name: String
): ConeValueParameterReference {
return if (type == session.builtinTypes.booleanType.type) {
ConeBooleanValueParameterReference(index, name)
} else {
ConeValueParameterReference(index, name)
}
}
override fun visitThisReceiverExpression(
thisReceiverExpression: FirThisReceiverExpression,
data: Nothing?
): ConeContractDescriptionElement? {
val declaration = thisReceiverExpression.calleeReference.boundSymbol?.fir ?: return null
return if (declaration == owner) {
val type = thisReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>() ?: return null
toValueParameterReference(type, -1, "this")
} else {
null
}
}
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Nothing?): ConeContractDescriptionElement? {
return when (constExpression.kind) {
FirConstKind.Null -> ConeConstantReference.NULL
FirConstKind.Boolean -> when (constExpression.value as Boolean) {
true -> ConeBooleanConstantReference.TRUE
false -> ConeBooleanConstantReference.FALSE
}
else -> null
}
}
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: Nothing?): ConeContractDescriptionElement? {
val arg = typeOperatorCall.argument.accept(this, data) as? ConeValueParameterReference ?: return null
val type = typeOperatorCall.conversionTypeRef.coneTypeSafe<ConeKotlinType>() ?: return null
val isNegated = typeOperatorCall.operation == FirOperation.NOT_IS
return ConeIsInstancePredicate(arg, type, isNegated)
}
private fun FirExpression.parseInvocationKind(): InvocationKind? {
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
else -> null
}
}
}
@@ -0,0 +1,139 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.contracts.FirRawContractDescription
import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription
import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.errorTypeFromPrototype
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeContractDescriptionError
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.compose
import org.jetbrains.kotlin.fir.visitors.transformSingle
class FirContractResolveTransformer(session: FirSession, scopeSession: ScopeSession) : FirBodyResolveTransformer(
session,
FirResolvePhase.CONTRACTS,
implicitTypeOnly = false,
scopeSession
) {
override val declarationsTransformer: FirDeclarationsResolveTransformer = FirDeclarationsContractResolveTransformer(this)
private class FirDeclarationsContractResolveTransformer(transformer: FirBodyResolveTransformer) : FirDeclarationsResolveTransformer(transformer) {
override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction,
data: ResolutionMode
): CompositeTransformResult<FirSimpleFunction> {
if (!simpleFunction.hasContractToResolve) {
simpleFunction.replaceResolvePhase(FirResolvePhase.CONTRACTS)
return simpleFunction.compose()
}
val containingDeclaration = context.containerIfAny
if (containingDeclaration != null && containingDeclaration !is FirClass<*>) {
simpleFunction.replaceResolvePhase(FirResolvePhase.CONTRACTS)
simpleFunction.replaceReturnTypeRef(
simpleFunction.returnTypeRef.errorTypeFromPrototype(
ConeContractDescriptionError("Local function can not be used in contract description")
)
)
return simpleFunction.compose()
}
@Suppress("UNCHECKED_CAST")
return withTypeParametersOf(simpleFunction) {
val receiverTypeRef = simpleFunction.receiverTypeRef
if (receiverTypeRef != null) {
withLabelAndReceiverType(simpleFunction.name, simpleFunction, receiverTypeRef.coneTypeUnsafe()) {
transformContractDescriptionOwner(simpleFunction)
}
} else {
transformContractDescriptionOwner(simpleFunction)
}
}
}
private fun <T : FirContractDescriptionOwner> transformContractDescriptionOwner(
owner: T
): CompositeTransformResult<T> {
dataFlowAnalyzer.enterContractDescription()
val contractDescription = owner.contractDescription
require(contractDescription is FirRawContractDescription)
val valueParameters = owner.valueParameters
val contractCall = withLocalScopeCleanup {
addLocalScope(FirLocalScope())
for (valueParameter in valueParameters) {
context.storeVariable(valueParameter)
}
context.withContainer(owner as FirDeclaration) {
contractDescription.contractCall.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
}
val resolvedId = contractCall.toResolvedCallableSymbol()?.callableId ?: return transformOwnerWithUnresolvedContract(owner)
if (resolvedId != FirContractsDslNames.CONTRACT) return transformOwnerWithUnresolvedContract(owner)
if (contractCall.arguments.size != 1) return transformOwnerOfErrorContract(owner)
val argument = contractCall.argument as? FirLambdaArgumentExpression ?: return transformOwnerOfErrorContract(owner)
val lambdaBody = (argument.expression as FirAnonymousFunction).body ?: return transformOwnerOfErrorContract(owner)
val resolvedContractDescription = buildResolvedContractDescription {
val effectExtractor = ConeEffectExtractor(session, owner, valueParameters)
for (statement in lambdaBody.statements) {
val effect = statement.accept(effectExtractor, null) as? ConeEffectDeclaration
if (effect == null) {
unresolvedEffects += statement
} else {
effects += effect
}
}
}
owner.replaceContractDescription(resolvedContractDescription)
dataFlowAnalyzer.exitContractDescription()
return owner.compose()
}
private fun <T : FirContractDescriptionOwner> transformOwnerWithUnresolvedContract(owner: T): CompositeTransformResult<T> {
val contractDescription = owner.contractDescription as FirRawContractDescription
val functionCall = contractDescription.contractCall
owner.replaceContractDescription(FirEmptyContractDescription)
owner.body.replaceFirstStatement(functionCall)
dataFlowAnalyzer.exitContractDescription()
return owner.compose()
}
private fun <T : FirContractDescriptionOwner> transformOwnerOfErrorContract(owner: T): CompositeTransformResult<T> {
// TODO
dataFlowAnalyzer.exitContractDescription()
return owner.compose()
}
private val FirContractDescriptionOwner.hasContractToResolve: Boolean
get() = contractDescription is FirRawContractDescription
}
}
private val FirContractDescriptionOwner.valueParameters: List<FirValueParameter>
get() = when (this) {
is FirSimpleFunction -> valueParameters
is FirPropertyAccessor -> valueParameters
else -> error()
}
private val FirContractDescriptionOwner.body: FirBlock
get() = when (this) {
is FirSimpleFunction -> body!!
is FirPropertyAccessor -> body!!
else -> error()
}
private fun FirContractDescriptionOwner.error(): Nothing = throw IllegalStateException("${this::class} can not be a contract owner")
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.AdapterForResolvePhase
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.compose
@AdapterForResolvePhase
class FirContractResolveTransformerAdapter(private val scopeSession: ScopeSession) : FirTransformer<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return element.compose()
}
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirDeclaration> {
val transformer = FirContractResolveTransformer(
file.session,
scopeSession
)
return file.transform(transformer, ResolutionMode.ContextIndependent)
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
object FirContractsDslNames {
// Internal marker-annotation for distinguishing our API
val CONTRACTS_DSL_ANNOTATION_FQN = id("kotlin.internal", "ContractsDsl")
// Types
val EFFECT = id("Effect")
val CONDITIONAL_EFFECT = id("ConditionalEffect")
val SIMPLE_EFFECT = id("SimpleEffect")
val RETURNS_EFFECT = id("Returns")
val RETURNS_NOT_NULL_EFFECT = id("ReturnsNotNull")
val CALLS_IN_PLACE_EFFECT = id("CallsInPlace")
// Structure-defining calls
val CONTRACT = id("contract")
val IMPLIES = simpleEffect("implies")
// Effect-declaration calls
val RETURNS = contractBuilder("returns")
val RETURNS_NOT_NULL = contractBuilder("returnsNotNull")
val CALLS_IN_PLACE = contractBuilder("callsInPlace")
// enum class InvocationKind
val INVOCATION_KIND_ENUM = id("InvocationKind")
val EXACTLY_ONCE_KIND = invocationKind("EXACTLY_ONCE")
val AT_LEAST_ONCE_KIND = invocationKind("AT_LEAST_ONCE")
val UNKNOWN_KIND = invocationKind("UNKNOWN")
val AT_MOST_ONCE_KIND = invocationKind("AT_MOST_ONCE")
private const val CONTRACT_BUILDER = "ContractBuilder"
private fun contractBuilder(name: String): CallableId = id(CONTRACT_PACKAGE, CONTRACT_BUILDER, name)
private fun invocationKind(name: String): CallableId = id(CONTRACT_PACKAGE, INVOCATION_KIND_ENUM.callableName.asString(), name)
private fun simpleEffect(name: String): CallableId = id(CONTRACT_PACKAGE, SIMPLE_EFFECT.callableName.asString(), name)
private fun id(name: String): CallableId = id(CONTRACT_PACKAGE, name)
private fun id(packageName: String, name: String): CallableId = id(packageName, className = null, name)
internal fun id(packageName: String, className: String?, name: String): CallableId {
return CallableId(
FqName(packageName),
className?.let { FqName(it) },
Name.identifier(name)
)
}
private const val CONTRACT_PACKAGE = "kotlin.contracts"
}
@@ -12,6 +12,7 @@ enum class FirResolvePhase {
SEALED_CLASS_INHERITORS,
TYPES,
STATUS,
CONTRACTS,
IMPLICIT_TYPES_BODY_RESOLVE,
BODY_RESOLVE;