[FIR] Properly track problems in contract description during effect extraction
This commit is contained in:
committed by
Space Team
parent
79d378f2bd
commit
5a92eb2c67
+82
-6
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtRealSourceElementKind
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
@@ -13,15 +12,16 @@ import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
|
||||
object FirContractChecker : FirFunctionChecker() {
|
||||
// TODO: The message should vary. Migrate this to [ConeEffectExtractor] when creating fine-grained errors.
|
||||
private const val UNEXPECTED_CONSTRUCTION = "unexpected construction in contract description"
|
||||
private val EMPTY_CONTRACT_MESSAGE = "Empty contract block is not allowed"
|
||||
|
||||
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration !is FirContractDescriptionOwner) return
|
||||
@@ -29,6 +29,9 @@ object FirContractChecker : FirFunctionChecker() {
|
||||
|
||||
checkUnresolvedEffects(contractDescription, context, reporter)
|
||||
checkContractNotAllowed(declaration, contractDescription, context, reporter)
|
||||
if (contractDescription.effects.isEmpty() && contractDescription.unresolvedEffects.isEmpty()) {
|
||||
reporter.reportOn(contractDescription.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, EMPTY_CONTRACT_MESSAGE, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkUnresolvedEffects(
|
||||
@@ -38,12 +41,11 @@ object FirContractChecker : FirFunctionChecker() {
|
||||
) {
|
||||
// Any statements that [ConeEffectExtractor] cannot extract effects will be in `unresolvedEffects`.
|
||||
for (unresolvedEffect in contractDescription.unresolvedEffects) {
|
||||
val statement = unresolvedEffect.statement
|
||||
if (statement.source == null || statement.source!!.kind is KtFakeSourceElementKind) continue
|
||||
val diagnostic = unresolvedEffect.effect.accept(DiagnosticExtractor, null) ?: continue
|
||||
|
||||
// TODO: report on fine-grained locations, e.g., ... implies unresolved => report on unresolved, not the entire statement.
|
||||
// but, sometimes, it's just reported on `contract`...
|
||||
reporter.reportOn(statement.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, UNEXPECTED_CONSTRUCTION, context)
|
||||
reporter.reportOn(unresolvedEffect.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, diagnostic.reason, context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,4 +66,78 @@ object FirContractChecker : FirFunctionChecker() {
|
||||
else if (declaration.symbol.callableId.isLocal || declaration.visibility == Visibilities.Local) contractNotAllowed("Contracts are not allowed for local functions")
|
||||
}
|
||||
|
||||
private object DiagnosticExtractor : ConeContractDescriptionVisitor<ConeDiagnostic?, Nothing?>() {
|
||||
override fun visitContractDescriptionElement(
|
||||
contractDescriptionElement: ConeContractDescriptionElement,
|
||||
data: Nothing?
|
||||
): ConeDiagnostic? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitConditionalEffectDeclaration(
|
||||
conditionalEffect: ConeConditionalEffectDeclaration,
|
||||
data: Nothing?
|
||||
): ConeDiagnostic? {
|
||||
return conditionalEffect.effect.accept(this, null) ?: conditionalEffect.condition.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitReturnsEffectDeclaration(returnsEffect: ConeReturnsEffectDeclaration, data: Nothing?): ConeDiagnostic? {
|
||||
return returnsEffect.value.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: Nothing?): ConeDiagnostic? {
|
||||
return callsEffect.valueParameterReference.accept(this, data)
|
||||
}
|
||||
|
||||
override fun visitErroneousCallsEffectDeclaration(
|
||||
callsEffect: ConeErroneousCallsEffectDeclaration,
|
||||
data: Nothing?
|
||||
): ConeDiagnostic {
|
||||
return callsEffect.diagnostic
|
||||
}
|
||||
|
||||
override fun visitLogicalBinaryOperationContractExpression(
|
||||
binaryLogicExpression: ConeBinaryLogicExpression,
|
||||
data: Nothing?
|
||||
): ConeDiagnostic? {
|
||||
return binaryLogicExpression.left.accept(this, null) ?: binaryLogicExpression.right.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitLogicalNot(logicalNot: ConeLogicalNot, data: Nothing?): ConeDiagnostic? {
|
||||
return logicalNot.arg.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitIsInstancePredicate(isInstancePredicate: ConeIsInstancePredicate, data: Nothing?): ConeDiagnostic? {
|
||||
return isInstancePredicate.arg.accept(this, data)
|
||||
}
|
||||
|
||||
override fun visitErroneousIsInstancePredicate(
|
||||
isInstancePredicate: ConeErroneousIsInstancePredicate,
|
||||
data: Nothing?
|
||||
): ConeDiagnostic {
|
||||
return isInstancePredicate.diagnostic
|
||||
}
|
||||
|
||||
override fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: Nothing?): ConeDiagnostic? {
|
||||
return isNullPredicate.arg.accept(this, data)
|
||||
}
|
||||
|
||||
override fun visitErroneousConstantReference(
|
||||
erroneousConstantReference: ConeErroneousConstantReference,
|
||||
data: Nothing?
|
||||
): ConeDiagnostic {
|
||||
return erroneousConstantReference.diagnostic
|
||||
}
|
||||
|
||||
override fun visitErroneousValueParameterReference(
|
||||
valueParameterReference: ConeErroneousValueParameterReference,
|
||||
data: Nothing?
|
||||
): ConeDiagnostic {
|
||||
return valueParameterReference.diagnostic
|
||||
}
|
||||
|
||||
override fun visitErroneousElement(element: ConeErroneousContractElement, data: Nothing?): ConeDiagnostic {
|
||||
return element.diagnostic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ 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.*
|
||||
import org.jetbrains.kotlin.fir.contracts.toFirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.toFirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
||||
@@ -24,7 +24,7 @@ class FirContractDeserializer(private val c: FirDeserializationContext) {
|
||||
fun loadContract(proto: ProtoBuf.Contract, owner: FirContractDescriptionOwner): FirContractDescription? {
|
||||
val effects = proto.effectList.map { loadPossiblyConditionalEffect(it, owner) ?: return null }
|
||||
return buildResolvedContractDescription {
|
||||
this.effects += effects.map { it.toFirEffectDeclaration() }
|
||||
this.effects += effects.map { it.toFirElement() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+100
-44
@@ -11,39 +11,49 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeContractDescriptionError
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.getContainingClass
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
||||
|
||||
class ConeEffectExtractor(
|
||||
private val session: FirSession,
|
||||
private val owner: FirContractDescriptionOwner,
|
||||
private val valueParameters: List<FirValueParameter>
|
||||
) : FirDefaultVisitor<ConeContractDescriptionElement?, Nothing?>() {
|
||||
) : 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
|
||||
private fun ConeContractDescriptionError.asElement(): ConeErroneousContractElement {
|
||||
return ConeErroneousContractElement(this)
|
||||
}
|
||||
|
||||
override fun visitReturnExpression(returnExpression: FirReturnExpression, data: Nothing?): ConeContractDescriptionElement? {
|
||||
override fun visitElement(element: FirElement, data: Nothing?): ConeContractDescriptionElement {
|
||||
return ConeContractDescriptionError.IllegalElement(element).asElement()
|
||||
}
|
||||
|
||||
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
|
||||
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?): ConeContractDescriptionElement {
|
||||
val resolvedId = functionCall.toResolvedCallableSymbol()?.callableId
|
||||
?: return ConeContractDescriptionError.UnresolvedCall(functionCall.calleeReference.name).asElement()
|
||||
|
||||
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
|
||||
val effect = functionCall.explicitReceiver?.asContractElement() as? ConeEffectDeclaration ?: noReceiver(resolvedId)
|
||||
val condition = functionCall.argument.asContractElement() as? ConeBooleanExpression ?: noArgument(resolvedId)
|
||||
ConeConditionalEffectDeclaration(effect, condition)
|
||||
}
|
||||
|
||||
@@ -52,8 +62,10 @@ class ConeEffectExtractor(
|
||||
val value = if (argument == null) {
|
||||
ConeConstantReference.WILDCARD
|
||||
} else {
|
||||
argument.accept(this, null) as? ConeConstantReference
|
||||
?: return null
|
||||
when (val value = argument.asContractElement()) {
|
||||
is ConeConstantReference -> value
|
||||
else -> ConeErroneousConstantReference(ConeContractDescriptionError.NotAConstant(value))
|
||||
}
|
||||
}
|
||||
ConeReturnsEffectDeclaration(value)
|
||||
}
|
||||
@@ -63,63 +75,80 @@ 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() ?: EventOccurrencesRange.UNKNOWN
|
||||
ConeCallsEffectDeclaration(reference, kind)
|
||||
val reference = functionCall.arguments[0].asContractValueExpression()
|
||||
when (val argument = functionCall.arguments.getOrNull(1)) {
|
||||
null -> ConeCallsEffectDeclaration(reference, EventOccurrencesRange.UNKNOWN)
|
||||
else -> when (val kind = argument.parseInvocationKind()) {
|
||||
null -> ConeErroneousCallsEffectDeclaration(reference, ConeContractDescriptionError.UnresolvedInvocationKind(argument))
|
||||
else -> 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 left = functionCall.explicitReceiver?.asContractBooleanExpression() ?: noReceiver(resolvedId)
|
||||
val right = functionCall.arguments.firstOrNull()?.asContractBooleanExpression() ?: noArgument(resolvedId)
|
||||
val kind = when (resolvedId) {
|
||||
BOOLEAN_AND -> LogicOperationKind.AND
|
||||
BOOLEAN_OR -> LogicOperationKind.OR
|
||||
else -> throw IllegalStateException()
|
||||
else -> shouldNotBeCalled()
|
||||
}
|
||||
ConeBinaryLogicExpression(left, right, kind)
|
||||
}
|
||||
|
||||
BOOLEAN_NOT -> {
|
||||
val arg = functionCall.explicitReceiver?.accept(this, null) as? ConeBooleanExpression ?: return null
|
||||
val arg = functionCall.explicitReceiver?.asContractBooleanExpression() ?: noReceiver(resolvedId)
|
||||
ConeLogicalNot(arg)
|
||||
}
|
||||
else -> null
|
||||
|
||||
else -> ConeContractDescriptionError.NotContractDsl(resolvedId).asElement()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
): ConeContractDescriptionElement {
|
||||
val left = binaryLogicExpression.leftOperand.asContractBooleanExpression()
|
||||
val right = binaryLogicExpression.rightOperand.asContractBooleanExpression()
|
||||
return ConeBinaryLogicExpression(left, right, binaryLogicExpression.kind)
|
||||
}
|
||||
|
||||
override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: Nothing?): ConeContractDescriptionElement? {
|
||||
val isNegated = when (equalityOperatorCall.operation) {
|
||||
override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: Nothing?): ConeContractDescriptionElement {
|
||||
val isNegated = when (val operation = equalityOperatorCall.operation) {
|
||||
FirOperation.EQ -> false
|
||||
FirOperation.NOT_EQ -> true
|
||||
else -> return null
|
||||
else -> return ConeContractDescriptionError.IllegalEqualityOperator(operation).asElement()
|
||||
}
|
||||
val const = equalityOperatorCall.arguments[1] as? FirConstExpression<*> ?: return null
|
||||
if (const.kind != ConstantValueKind.Null) return null
|
||||
val arg = equalityOperatorCall.arguments[0].accept(this, null) as? ConeValueParameterReference ?: return null
|
||||
|
||||
val argument = equalityOperatorCall.arguments[1]
|
||||
val const = argument as? FirConstExpression<*> ?: return ConeContractDescriptionError.NotAConstant(argument).asElement()
|
||||
if (const.kind != ConstantValueKind.Null) return ConeContractDescriptionError.IllegalConst(const, onlyNullAllowed = true).asElement()
|
||||
|
||||
val arg = equalityOperatorCall.arguments[0].asContractValueExpression()
|
||||
return ConeIsNullPredicate(arg, isNegated)
|
||||
}
|
||||
|
||||
override fun visitSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: Nothing?): ConeContractDescriptionElement? {
|
||||
override fun visitSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: Nothing?): ConeContractDescriptionElement {
|
||||
return smartCastExpression.originalExpression.accept(this, data)
|
||||
}
|
||||
|
||||
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
|
||||
): ConeContractDescriptionElement {
|
||||
val symbol = qualifiedAccessExpression.toResolvedCallableSymbol()
|
||||
?: run {
|
||||
val name = (qualifiedAccessExpression.calleeReference as? FirNamedReference)?.name ?: Name.special("unresolved")
|
||||
return ConeContractDescriptionError.UnresolvedCall(name).asElement()
|
||||
}
|
||||
val parameter = symbol.fir as? FirValueParameter
|
||||
?: return ConeErroneousValueParameterReference(
|
||||
ConeContractDescriptionError.IllegalParameter(symbol, "$symbol is not a value parameter")
|
||||
)
|
||||
val index = valueParameters.indexOf(parameter).takeUnless { it < 0 } ?: return ConeErroneousValueParameterReference(
|
||||
ConeContractDescriptionError.IllegalParameter(symbol, "Value paramter $symbol is not found in parameters of outer function")
|
||||
)
|
||||
val type = parameter.returnTypeRef.coneType
|
||||
|
||||
val name = parameter.name.asString()
|
||||
@@ -129,7 +158,7 @@ class ConeEffectExtractor(
|
||||
override fun visitPropertyAccessExpression(
|
||||
propertyAccessExpression: FirPropertyAccessExpression,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement? {
|
||||
): ConeContractDescriptionElement {
|
||||
return visitQualifiedAccessExpression(propertyAccessExpression, data)
|
||||
}
|
||||
|
||||
@@ -152,8 +181,9 @@ class ConeEffectExtractor(
|
||||
override fun visitThisReceiverExpression(
|
||||
thisReceiverExpression: FirThisReceiverExpression,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement? {
|
||||
val declaration = thisReceiverExpression.calleeReference.boundSymbol?.fir ?: return null
|
||||
): ConeContractDescriptionElement {
|
||||
val declaration = thisReceiverExpression.calleeReference.boundSymbol?.fir
|
||||
?: return ConeContractDescriptionError.UnresolvedThis(thisReceiverExpression).asElement()
|
||||
val callableOwner = owner as? FirCallableDeclaration
|
||||
val ownerHasReceiver = callableOwner?.receiverParameter != null
|
||||
val ownerIsMemberOfDeclaration = callableOwner?.getContainingClass(session) == declaration
|
||||
@@ -161,24 +191,24 @@ class ConeEffectExtractor(
|
||||
val type = thisReceiverExpression.typeRef.coneType
|
||||
toValueParameterReference(type, -1, "this")
|
||||
} else {
|
||||
null
|
||||
ConeContractDescriptionError.IllegalThis(thisReceiverExpression).asElement()
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Nothing?): ConeContractDescriptionElement? {
|
||||
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Nothing?): ConeContractDescriptionElement {
|
||||
return when (constExpression.kind) {
|
||||
ConstantValueKind.Null -> ConeConstantReference.NULL
|
||||
ConstantValueKind.Boolean -> when (constExpression.value as Boolean) {
|
||||
true -> ConeBooleanConstantReference.TRUE
|
||||
false -> ConeBooleanConstantReference.FALSE
|
||||
}
|
||||
else -> null
|
||||
else -> ConeContractDescriptionError.IllegalConst(constExpression, onlyNullAllowed = false).asElement()
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: Nothing?): ConeContractDescriptionElement? {
|
||||
val arg = typeOperatorCall.argument.accept(this, data) as? ConeValueParameterReference ?: return null
|
||||
val type = typeOperatorCall.conversionTypeRef.coneType
|
||||
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: Nothing?): ConeContractDescriptionElement {
|
||||
val arg = typeOperatorCall.argument.asContractValueExpression()
|
||||
val type = typeOperatorCall.conversionTypeRef.coneType.fullyExpandedType(session)
|
||||
val isNegated = typeOperatorCall.operation == FirOperation.NOT_IS
|
||||
return ConeIsInstancePredicate(arg, type, isNegated)
|
||||
}
|
||||
@@ -194,4 +224,30 @@ class ConeEffectExtractor(
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun noReceiver(callableId: CallableId): ConeErroneousContractElement {
|
||||
return ConeContractDescriptionError.NoReceiver(callableId.callableName).asElement()
|
||||
}
|
||||
|
||||
private fun noArgument(callableId: CallableId): ConeErroneousContractElement {
|
||||
return ConeContractDescriptionError.NoArgument(callableId.callableName).asElement()
|
||||
}
|
||||
|
||||
private fun FirElement.asContractElement(): ConeContractDescriptionElement {
|
||||
return accept(this@ConeEffectExtractor, null)
|
||||
}
|
||||
|
||||
private fun FirExpression.asContractBooleanExpression(): ConeBooleanExpression {
|
||||
return when (val element = asContractElement()) {
|
||||
is ConeBooleanExpression -> element
|
||||
else -> ConeContractDescriptionError.NotABooleanExpression(element).asElement()
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirExpression.asContractValueExpression(): ConeValueParameterReference {
|
||||
return when (val element = asContractElement()) {
|
||||
is ConeValueParameterReference -> element
|
||||
else -> ConeErroneousValueParameterReference(ConeContractDescriptionError.NotAParameterReference(element))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-7
@@ -5,15 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.FirRawContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildLegacyRawContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect
|
||||
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.toFirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.toFirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter
|
||||
@@ -179,11 +179,13 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
|
||||
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 += ConeUnresolvedEffect(statement)
|
||||
} else {
|
||||
effects += effect.toFirEffectDeclaration(statement.source)
|
||||
if (statement.source?.kind is KtFakeSourceElementKind.ImplicitReturn) continue
|
||||
when (val effect = statement.accept(effectExtractor, null)) {
|
||||
is ConeEffectDeclaration -> when (effect.erroneous) {
|
||||
false -> effects += effect.toFirElement(statement.source)
|
||||
true -> unresolvedEffects += effect.toFirElement(statement.source)
|
||||
}
|
||||
else -> unresolvedEffects += effect.toFirElement(statement.source)
|
||||
}
|
||||
}
|
||||
this.source = contractDescription.source
|
||||
|
||||
+83
-1
@@ -7,9 +7,14 @@ package org.jetbrains.kotlin.fir.resolve.diagnostics
|
||||
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnosticWithSource
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirOperation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCandidate
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -17,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirQualifierPart
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
@@ -138,7 +144,83 @@ object ConeVariableExpectedError : ConeDiagnostic {
|
||||
override val reason: String get() = "Variable expected"
|
||||
}
|
||||
|
||||
class ConeContractDescriptionError(override val reason: String) : ConeDiagnostic
|
||||
sealed class ConeContractDescriptionError : ConeDiagnostic {
|
||||
class IllegalElement(val element: FirElement) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "Illegal element in contract description"
|
||||
}
|
||||
|
||||
class UnresolvedCall(val name: Name) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "Unresolved call in contract description: ${name.asString()}"
|
||||
}
|
||||
|
||||
class NoReceiver(val name: Name) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "No receiver for call ${name.asString()} found"
|
||||
}
|
||||
|
||||
class NoArgument(val name: Name) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "No argument for call ${name.asString()} found"
|
||||
}
|
||||
|
||||
class NotAConstant(val element: Any) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "$element is not a constant reference"
|
||||
}
|
||||
|
||||
class IllegalConst(
|
||||
val element: FirConstExpression<*>,
|
||||
val onlyNullAllowed: Boolean
|
||||
) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = buildString {
|
||||
append(element.render())
|
||||
append("is not a null")
|
||||
if (!onlyNullAllowed) {
|
||||
append(", true or false")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NotAParameterReference(val element: ConeContractDescriptionElement) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "$element is not a parameter or receiver reference"
|
||||
}
|
||||
|
||||
class IllegalParameter(val symbol: FirCallableSymbol<*>, override val reason: String) : ConeContractDescriptionError()
|
||||
|
||||
class UnresolvedThis(val expression: FirThisReceiverExpression) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "Can't resolve this reference"
|
||||
}
|
||||
|
||||
class IllegalThis(val expression: FirThisReceiverExpression) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "Only this reference to extension receiver of a function is allowed"
|
||||
}
|
||||
|
||||
class UnresolvedInvocationKind(val element: FirElement) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "${element.render()} is not a valid invocation kind"
|
||||
}
|
||||
|
||||
class NotABooleanExpression(val element: ConeContractDescriptionElement) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "$element is not a boolean expression"
|
||||
}
|
||||
|
||||
class NotContractDsl(val callableId: CallableId) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "$callableId is not a part of contracts DSL"
|
||||
}
|
||||
|
||||
class IllegalEqualityOperator(val operation: FirOperation) : ConeContractDescriptionError() {
|
||||
override val reason: String
|
||||
get() = "$operation operator call is illegal in contract description"
|
||||
}
|
||||
}
|
||||
|
||||
class ConeIllegalAnnotationError(val name: Name) : ConeDiagnostic {
|
||||
override val reason: String get() = "Not a legal annotation: $name"
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.contracts
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirPureAbstractElement
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
/*
|
||||
* This file was generated automatically
|
||||
* DO NOT MODIFY IT MANUALLY
|
||||
*/
|
||||
|
||||
abstract class FirContractElementDeclaration : FirPureAbstractElement(), FirElement {
|
||||
abstract override val source: KtSourceElement?
|
||||
abstract val effect: ConeContractDescriptionElement
|
||||
|
||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitContractElementDeclaration(this, data)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <E : FirElement, D> transform(transformer: FirTransformer<D>, data: D): E =
|
||||
transformer.transformContractElementDeclaration(this, data) as E
|
||||
}
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.contracts
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirPureAbstractElement
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
@@ -16,9 +15,9 @@ import org.jetbrains.kotlin.fir.visitors.*
|
||||
* DO NOT MODIFY IT MANUALLY
|
||||
*/
|
||||
|
||||
abstract class FirEffectDeclaration : FirPureAbstractElement(), FirElement {
|
||||
abstract class FirEffectDeclaration : FirContractElementDeclaration() {
|
||||
abstract override val source: KtSourceElement?
|
||||
abstract val effect: ConeEffectDeclaration
|
||||
abstract override val effect: ConeEffectDeclaration
|
||||
|
||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitEffectDeclaration(this, data)
|
||||
|
||||
|
||||
+1
-2
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.contracts
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
/*
|
||||
@@ -18,7 +17,7 @@ import org.jetbrains.kotlin.fir.visitors.*
|
||||
abstract class FirResolvedContractDescription : FirContractDescription() {
|
||||
abstract override val source: KtSourceElement?
|
||||
abstract val effects: List<FirEffectDeclaration>
|
||||
abstract val unresolvedEffects: List<ConeUnresolvedEffect>
|
||||
abstract val unresolvedEffects: List<FirContractElementDeclaration>
|
||||
|
||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitResolvedContractDescription(this, data)
|
||||
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DuplicatedCode")
|
||||
|
||||
package org.jetbrains.kotlin.fir.contracts.builder
|
||||
|
||||
import kotlin.contracts.*
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement
|
||||
import org.jetbrains.kotlin.fir.contracts.impl.FirContractElementDeclarationImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
/*
|
||||
* This file was generated automatically
|
||||
* DO NOT MODIFY IT MANUALLY
|
||||
*/
|
||||
|
||||
@FirBuilderDsl
|
||||
class FirContractElementDeclarationBuilder {
|
||||
var source: KtSourceElement? = null
|
||||
lateinit var effect: ConeContractDescriptionElement
|
||||
|
||||
fun build(): FirContractElementDeclaration {
|
||||
return FirContractElementDeclarationImpl(
|
||||
source,
|
||||
effect,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun buildContractElementDeclaration(init: FirContractElementDeclarationBuilder.() -> Unit): FirContractElementDeclaration {
|
||||
contract {
|
||||
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
return FirContractElementDeclarationBuilder().apply(init).build()
|
||||
}
|
||||
+2
-2
@@ -10,9 +10,9 @@ package org.jetbrains.kotlin.fir.contracts.builder
|
||||
import kotlin.contracts.*
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect
|
||||
import org.jetbrains.kotlin.fir.contracts.impl.FirResolvedContractDescriptionImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.fir.visitors.*
|
||||
class FirResolvedContractDescriptionBuilder {
|
||||
var source: KtSourceElement? = null
|
||||
val effects: MutableList<FirEffectDeclaration> = mutableListOf()
|
||||
val unresolvedEffects: MutableList<ConeUnresolvedEffect> = mutableListOf()
|
||||
val unresolvedEffects: MutableList<FirContractElementDeclaration> = mutableListOf()
|
||||
|
||||
fun build(): FirResolvedContractDescription {
|
||||
return FirResolvedContractDescriptionImpl(
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DuplicatedCode")
|
||||
|
||||
package org.jetbrains.kotlin.fir.contracts.impl
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
/*
|
||||
* This file was generated automatically
|
||||
* DO NOT MODIFY IT MANUALLY
|
||||
*/
|
||||
|
||||
internal class FirContractElementDeclarationImpl(
|
||||
override val source: KtSourceElement?,
|
||||
override val effect: ConeContractDescriptionElement,
|
||||
) : FirContractElementDeclaration() {
|
||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
|
||||
|
||||
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirContractElementDeclarationImpl {
|
||||
return this
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -8,9 +8,9 @@
|
||||
package org.jetbrains.kotlin.fir.contracts.impl
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
/*
|
||||
@@ -21,14 +21,16 @@ import org.jetbrains.kotlin.fir.visitors.*
|
||||
internal class FirResolvedContractDescriptionImpl(
|
||||
override val source: KtSourceElement?,
|
||||
override val effects: MutableList<FirEffectDeclaration>,
|
||||
override val unresolvedEffects: MutableList<ConeUnresolvedEffect>,
|
||||
override val unresolvedEffects: MutableList<FirContractElementDeclaration>,
|
||||
) : FirResolvedContractDescription() {
|
||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||
effects.forEach { it.accept(visitor, data) }
|
||||
unresolvedEffects.forEach { it.accept(visitor, data) }
|
||||
}
|
||||
|
||||
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirResolvedContractDescriptionImpl {
|
||||
effects.transformInplace(transformer, data)
|
||||
unresolvedEffects.transformInplace(transformer, data)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
||||
@@ -314,6 +315,8 @@ abstract class FirDefaultVisitor<out R, in D> : FirVisitor<R, D>() {
|
||||
|
||||
override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: D): R = visitTypeRef(implicitTypeRef, data)
|
||||
|
||||
override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): R = visitContractElementDeclaration(effectDeclaration, data)
|
||||
|
||||
override fun visitLegacyRawContractDescription(legacyRawContractDescription: FirLegacyRawContractDescription, data: D): R = visitContractDescription(legacyRawContractDescription, data)
|
||||
|
||||
override fun visitRawContractDescription(rawContractDescription: FirRawContractDescription, data: D): R = visitContractDescription(rawContractDescription, data)
|
||||
|
||||
@@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
||||
@@ -314,6 +315,8 @@ abstract class FirDefaultVisitorVoid : FirVisitorVoid() {
|
||||
|
||||
override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef) = visitTypeRef(implicitTypeRef)
|
||||
|
||||
override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration) = visitContractElementDeclaration(effectDeclaration)
|
||||
|
||||
override fun visitLegacyRawContractDescription(legacyRawContractDescription: FirLegacyRawContractDescription) = visitContractDescription(legacyRawContractDescription)
|
||||
|
||||
override fun visitRawContractDescription(rawContractDescription: FirRawContractDescription) = visitContractDescription(rawContractDescription)
|
||||
|
||||
@@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
||||
@@ -731,7 +732,11 @@ abstract class FirTransformer<in D> : FirVisitor<FirElement, D>() {
|
||||
return transformElement(implicitTypeRef, data)
|
||||
}
|
||||
|
||||
open fun transformEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirEffectDeclaration {
|
||||
open fun transformContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: D): FirContractElementDeclaration {
|
||||
return transformElement(contractElementDeclaration, data)
|
||||
}
|
||||
|
||||
open fun transformEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirContractElementDeclaration {
|
||||
return transformElement(effectDeclaration, data)
|
||||
}
|
||||
|
||||
@@ -1323,7 +1328,11 @@ abstract class FirTransformer<in D> : FirVisitor<FirElement, D>() {
|
||||
return transformImplicitTypeRef(implicitTypeRef, data)
|
||||
}
|
||||
|
||||
final override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirEffectDeclaration {
|
||||
final override fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: D): FirContractElementDeclaration {
|
||||
return transformContractElementDeclaration(contractElementDeclaration, data)
|
||||
}
|
||||
|
||||
final override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirContractElementDeclaration {
|
||||
return transformEffectDeclaration(effectDeclaration, data)
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
||||
@@ -446,6 +447,8 @@ abstract class FirVisitor<out R, in D> {
|
||||
|
||||
open fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: D): R = visitElement(implicitTypeRef, data)
|
||||
|
||||
open fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: D): R = visitElement(contractElementDeclaration, data)
|
||||
|
||||
open fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): R = visitElement(effectDeclaration, data)
|
||||
|
||||
open fun visitContractDescription(contractDescription: FirContractDescription, data: D): R = visitElement(contractDescription, data)
|
||||
|
||||
@@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
||||
@@ -730,6 +731,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
|
||||
visitElement(implicitTypeRef)
|
||||
}
|
||||
|
||||
open fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration) {
|
||||
visitElement(contractElementDeclaration)
|
||||
}
|
||||
|
||||
open fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration) {
|
||||
visitElement(effectDeclaration)
|
||||
}
|
||||
@@ -1322,6 +1327,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
|
||||
visitImplicitTypeRef(implicitTypeRef)
|
||||
}
|
||||
|
||||
final override fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: Nothing?) {
|
||||
visitContractElementDeclaration(contractElementDeclaration)
|
||||
}
|
||||
|
||||
final override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: Nothing?) {
|
||||
visitEffectDeclaration(effectDeclaration)
|
||||
}
|
||||
|
||||
@@ -6,16 +6,27 @@
|
||||
package org.jetbrains.kotlin.fir.contracts
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildContractElementDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement
|
||||
import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration
|
||||
|
||||
val FirContractDescription.effects: List<FirEffectDeclaration>?
|
||||
get() = (this as? FirResolvedContractDescription)?.effects
|
||||
|
||||
fun ConeEffectDeclaration.toFirEffectDeclaration(source: KtSourceElement? = null): FirEffectDeclaration =
|
||||
fun ConeEffectDeclaration.toFirElement(source: KtSourceElement? = null): FirEffectDeclaration =
|
||||
buildEffectDeclaration {
|
||||
if (source != null) {
|
||||
this.source = source
|
||||
}
|
||||
effect = this@toFirEffectDeclaration
|
||||
effect = this@toFirElement
|
||||
}
|
||||
|
||||
|
||||
fun ConeContractDescriptionElement.toFirElement(source: KtSourceElement? = null): FirContractElementDeclaration =
|
||||
buildContractElementDeclaration {
|
||||
if (source != null) {
|
||||
this.source = source
|
||||
}
|
||||
effect = this@toFirElement
|
||||
}
|
||||
|
||||
+2
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.contracts.description
|
||||
|
||||
interface ConeContractDescriptionElement {
|
||||
fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R
|
||||
|
||||
val erroneous: Boolean
|
||||
}
|
||||
|
||||
abstract class ConeEffectDeclaration : ConeContractDescriptionElement {
|
||||
|
||||
+17
-1
@@ -23,6 +23,9 @@ abstract class ConeContractDescriptionVisitor<out R, in D> {
|
||||
open fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: D): R =
|
||||
visitEffectDeclaration(callsEffect, data)
|
||||
|
||||
open fun visitErroneousCallsEffectDeclaration(callsEffect: ConeErroneousCallsEffectDeclaration, data: D): R =
|
||||
visitCallsEffectDeclaration(callsEffect, data)
|
||||
|
||||
// Expressions
|
||||
open fun visitBooleanExpression(booleanExpression: ConeBooleanExpression, data: D): R =
|
||||
visitContractDescriptionElement(booleanExpression, data)
|
||||
@@ -35,6 +38,9 @@ abstract class ConeContractDescriptionVisitor<out R, in D> {
|
||||
open fun visitIsInstancePredicate(isInstancePredicate: ConeIsInstancePredicate, data: D): R =
|
||||
visitBooleanExpression(isInstancePredicate, data)
|
||||
|
||||
open fun visitErroneousIsInstancePredicate(isInstancePredicate: ConeErroneousIsInstancePredicate, data: D): R =
|
||||
visitIsInstancePredicate(isInstancePredicate, data)
|
||||
|
||||
open fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: D): R = visitBooleanExpression(isNullPredicate, data)
|
||||
|
||||
// Values
|
||||
@@ -45,9 +51,19 @@ abstract class ConeContractDescriptionVisitor<out R, in D> {
|
||||
open fun visitBooleanConstantDescriptor(booleanConstantDescriptor: ConeBooleanConstantReference, data: D): R =
|
||||
visitConstantDescriptor(booleanConstantDescriptor, data)
|
||||
|
||||
open fun visitErroneousConstantReference(erroneousConstantReference: ConeErroneousConstantReference, data: D): R =
|
||||
visitConstantDescriptor(erroneousConstantReference, data)
|
||||
|
||||
open fun visitValueParameterReference(valueParameterReference: ConeValueParameterReference, data: D): R =
|
||||
visitValue(valueParameterReference, data)
|
||||
|
||||
open fun visitBooleanValueParameterReference(booleanValueParameterReference: ConeBooleanValueParameterReference, data: D): R =
|
||||
visitValueParameterReference(booleanValueParameterReference, data)
|
||||
}
|
||||
|
||||
open fun visitErroneousValueParameterReference(valueParameterReference: ConeErroneousValueParameterReference, data: D): R =
|
||||
visitValueParameterReference(valueParameterReference, data)
|
||||
|
||||
// Error
|
||||
open fun visitErroneousElement(element: ConeErroneousContractElement, data: D): R =
|
||||
visitContractDescriptionElement(element, data)
|
||||
}
|
||||
|
||||
+26
-3
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.contracts.description
|
||||
|
||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
|
||||
/**
|
||||
* Effect with condition attached to it.
|
||||
@@ -22,6 +23,9 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
* - if [condition] is true, we *can't* reason that [effect] will be observed.
|
||||
*/
|
||||
class ConeConditionalEffectDeclaration(val effect: ConeEffectDeclaration, val condition: ConeBooleanExpression) : ConeEffectDeclaration() {
|
||||
override val erroneous: Boolean
|
||||
get() = effect.erroneous || condition.erroneous
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitConditionalEffectDeclaration(this, data)
|
||||
}
|
||||
@@ -31,9 +35,11 @@ class ConeConditionalEffectDeclaration(val effect: ConeEffectDeclaration, val co
|
||||
* Effect which specifies that subroutine returns some particular value
|
||||
*/
|
||||
class ConeReturnsEffectDeclaration(val value: ConeConstantReference) : ConeEffectDeclaration() {
|
||||
override val erroneous: Boolean
|
||||
get() = value.erroneous
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitReturnsEffectDeclaration(this, data)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +47,24 @@ 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: EventOccurrencesRange) : ConeEffectDeclaration() {
|
||||
open class ConeCallsEffectDeclaration(
|
||||
val valueParameterReference: ConeValueParameterReference,
|
||||
val kind: EventOccurrencesRange
|
||||
) : ConeEffectDeclaration() {
|
||||
override val erroneous: Boolean
|
||||
get() = valueParameterReference.erroneous
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitCallsEffectDeclaration(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
class ConeErroneousCallsEffectDeclaration(
|
||||
valueParameterReference: ConeValueParameterReference,
|
||||
val diagnostic: ConeDiagnostic
|
||||
) : ConeCallsEffectDeclaration(valueParameterReference, EventOccurrencesRange.UNKNOWN) {
|
||||
override val erroneous: Boolean
|
||||
get() = true
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitErroneousCallsEffectDeclaration(this, data)
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.contracts.description
|
||||
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
|
||||
class ConeErroneousContractElement(
|
||||
val diagnostic: ConeDiagnostic
|
||||
) : ConeEffectDeclaration(), ConeBooleanExpression, ConeContractDescriptionValue {
|
||||
override val erroneous: Boolean
|
||||
get() = true
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R {
|
||||
return contractDescriptionVisitor.visitErroneousElement(this, data)
|
||||
}
|
||||
}
|
||||
+6
@@ -8,12 +8,18 @@ package org.jetbrains.kotlin.fir.contracts.description
|
||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
||||
|
||||
class ConeBinaryLogicExpression(val left: ConeBooleanExpression, val right: ConeBooleanExpression, val kind: LogicOperationKind) : ConeBooleanExpression {
|
||||
override val erroneous: Boolean
|
||||
get() = left.erroneous || right.erroneous
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R {
|
||||
return contractDescriptionVisitor.visitLogicalBinaryOperationContractExpression(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
class ConeLogicalNot(val arg: ConeBooleanExpression) : ConeBooleanExpression {
|
||||
override val erroneous: Boolean
|
||||
get() = arg.erroneous
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitLogicalNot(this, data)
|
||||
}
|
||||
|
||||
+22
-2
@@ -5,9 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.contracts.description
|
||||
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
|
||||
class ConeIsInstancePredicate(val arg: ConeValueParameterReference, val type: ConeKotlinType, val isNegated: Boolean) : ConeBooleanExpression {
|
||||
open class ConeIsInstancePredicate(val arg: ConeValueParameterReference, val type: ConeKotlinType, val isNegated: Boolean) : ConeBooleanExpression {
|
||||
override val erroneous: Boolean
|
||||
get() = arg.erroneous
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitIsInstancePredicate(this, data)
|
||||
|
||||
@@ -15,10 +19,26 @@ class ConeIsInstancePredicate(val arg: ConeValueParameterReference, val type: Co
|
||||
ConeIsInstancePredicate(arg, type, isNegated.not())
|
||||
}
|
||||
|
||||
class ConeErroneousIsInstancePredicate(
|
||||
arg: ConeValueParameterReference,
|
||||
type: ConeKotlinType,
|
||||
isNegated: Boolean,
|
||||
val diagnostic: ConeDiagnostic
|
||||
) : ConeIsInstancePredicate(arg, type, isNegated) {
|
||||
override val erroneous: Boolean
|
||||
get() = true
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitErroneousIsInstancePredicate(this, data)
|
||||
}
|
||||
|
||||
class ConeIsNullPredicate(val arg: ConeValueParameterReference, val isNegated: Boolean) : ConeBooleanExpression {
|
||||
override val erroneous: Boolean
|
||||
get() = arg.erroneous
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitIsNullPredicate(this, data)
|
||||
|
||||
fun negated(): ConeIsNullPredicate =
|
||||
ConeIsNullPredicate(arg, isNegated.not())
|
||||
}
|
||||
}
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.contracts.description
|
||||
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
|
||||
class ConeUnresolvedEffect(val statement: FirStatement)
|
||||
@@ -5,12 +5,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.contracts.description
|
||||
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
|
||||
interface ConeContractDescriptionValue : ConeContractDescriptionElement {
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitValue(this, data)
|
||||
}
|
||||
|
||||
open class ConeConstantReference protected constructor(val name: String) : ConeContractDescriptionValue {
|
||||
override val erroneous: Boolean
|
||||
get() = false
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitConstantDescriptor(this, data)
|
||||
|
||||
@@ -31,6 +36,14 @@ class ConeBooleanConstantReference private constructor(name: String) : ConeConst
|
||||
}
|
||||
}
|
||||
|
||||
class ConeErroneousConstantReference(val diagnostic: ConeDiagnostic) : ConeConstantReference("ERROR") {
|
||||
override val erroneous: Boolean
|
||||
get() = true
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitErroneousConstantReference(this, data)
|
||||
}
|
||||
|
||||
/*
|
||||
* Index of value parameter of function
|
||||
* -1 means that it is reference to extension receiver
|
||||
@@ -40,6 +53,9 @@ open class ConeValueParameterReference(val parameterIndex: Int, val name: String
|
||||
assert(parameterIndex >= -1)
|
||||
}
|
||||
|
||||
override val erroneous: Boolean
|
||||
get() = false
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitValueParameterReference(this, data)
|
||||
}
|
||||
@@ -47,4 +63,12 @@ open class ConeValueParameterReference(val parameterIndex: Int, val name: String
|
||||
class ConeBooleanValueParameterReference(parameterIndex: Int, name: String) : ConeValueParameterReference(parameterIndex, name), ConeBooleanExpression {
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitBooleanValueParameterReference(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
class ConeErroneousValueParameterReference(val diagnostic: ConeDiagnostic) : ConeValueParameterReference(Int.MAX_VALUE, "ERROR") {
|
||||
override val erroneous: Boolean
|
||||
get() = true
|
||||
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitErroneousValueParameterReference(this, data)
|
||||
}
|
||||
|
||||
+2
-1
@@ -180,7 +180,8 @@ object FirTreeBuilder : AbstractFirTreeBuilder() {
|
||||
val intersectionTypeRef by element(TypeRef, typeRefWithNullability)
|
||||
val implicitTypeRef by element(TypeRef, typeRef)
|
||||
|
||||
val effectDeclaration by element(Contracts)
|
||||
val contractElementDeclaration by element(Contracts)
|
||||
val effectDeclaration by element(Contracts, contractElementDeclaration)
|
||||
|
||||
val contractDescription by element(Contracts)
|
||||
val legacyRawContractDescription by element(Contracts, contractDescription)
|
||||
|
||||
+2
@@ -562,6 +562,8 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
noImpl(argumentList)
|
||||
noImpl(annotationArgumentMapping)
|
||||
|
||||
impl(contractElementDeclaration)
|
||||
|
||||
val implementationsWithoutStatusAndTypeParameters = listOf(
|
||||
"FirAnonymousFunctionImpl",
|
||||
"FirValueParameterImpl",
|
||||
|
||||
+5
-1
@@ -732,6 +732,10 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
+field(varianceType)
|
||||
}
|
||||
|
||||
contractElementDeclaration.configure {
|
||||
+field("effect", coneContractElementType)
|
||||
}
|
||||
|
||||
effectDeclaration.configure {
|
||||
+field("effect", coneEffectDeclarationType)
|
||||
}
|
||||
@@ -742,7 +746,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
|
||||
resolvedContractDescription.configure {
|
||||
+fieldList("effects", effectDeclaration)
|
||||
+fieldList("unresolvedEffects", coneUnresolvedEffect)
|
||||
+fieldList("unresolvedEffects", contractElementDeclaration)
|
||||
}
|
||||
|
||||
legacyRawContractDescription.configure {
|
||||
|
||||
+1
-1
@@ -79,11 +79,11 @@ val emptyArgumentListType = type("fir.expressions", "FirEmptyArgumentList")
|
||||
val firScopeProviderType = type("fir.scopes", "FirScopeProvider")
|
||||
|
||||
val pureAbstractElementType = generatedType("FirPureAbstractElement")
|
||||
val coneContractElementType = type("fir.contracts.description", "ConeContractDescriptionElement")
|
||||
val coneEffectDeclarationType = type("fir.contracts.description", "ConeEffectDeclaration")
|
||||
val emptyContractDescriptionType = generatedType("contracts.impl", "FirEmptyContractDescription")
|
||||
val coneDiagnosticType = generatedType("diagnostics", "ConeDiagnostic")
|
||||
val coneStubDiagnosticType = generatedType("diagnostics", "ConeStubDiagnostic")
|
||||
val coneUnresolvedEffect = type("fir.contracts.description", "ConeUnresolvedEffect")
|
||||
|
||||
val dslBuilderAnnotationType = generatedType("builder", "FirBuilderDsl")
|
||||
val firImplementationDetailType = generatedType("FirImplementationDetail")
|
||||
|
||||
+2
-2
@@ -5,5 +5,5 @@
|
||||
import kotlin.contracts.*
|
||||
|
||||
fun emptyContract() {
|
||||
contract { }
|
||||
}
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>contract { }<!>
|
||||
}
|
||||
|
||||
+2
-2
@@ -25,9 +25,9 @@ fun whenInContract(x: Any?, boolean: Boolean) {
|
||||
|
||||
fun forInContract(x: Any?) {
|
||||
contract {
|
||||
for (i in 0..1) {
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>for (i in 0..1) {
|
||||
returns() implies (x is String)
|
||||
}
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import kotlin.contracts.*
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
inline fun case_1(block: () -> Unit) {
|
||||
contract { }
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>contract { }<!>
|
||||
return block()
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -11,24 +11,24 @@ object SampleObject {
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
inline fun case_1(invocationKind: InvocationKind, block: () -> Unit) {
|
||||
contract { callsInPlace(block, invocationKind) }
|
||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, invocationKind)<!> }
|
||||
return block()
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 2
|
||||
inline fun <T : InvocationKind> case_2(invocationKind: T, block: () -> Unit) {
|
||||
contract { callsInPlace(block, invocationKind) }
|
||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, invocationKind)<!> }
|
||||
return block()
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 3
|
||||
inline fun case_3(block: () -> Unit) {
|
||||
contract { callsInPlace(block, invocationKind) }
|
||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, invocationKind)<!> }
|
||||
return block()
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 4
|
||||
inline fun case_4(block: () -> Unit) {
|
||||
contract { callsInPlace(block, SampleObject.invocationKind) }
|
||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, SampleObject.invocationKind)<!> }
|
||||
return block()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user