[FIR] Implement checks for contract not allowed

^KT-55423 Fixed
This commit is contained in:
Kirill Rakhman
2023-02-08 12:03:36 +01:00
committed by Space Team
parent b2fbf8bed5
commit f946ddeb40
50 changed files with 377 additions and 178 deletions
@@ -3678,6 +3678,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.CONTRACT_NOT_ALLOWED) { firDiagnostic ->
ContractNotAllowedImpl(
firDiagnostic.a,
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.NO_GET_METHOD) { firDiagnostic ->
NoGetMethodImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -2567,6 +2567,11 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val reason: String
}
abstract class ContractNotAllowed : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = ContractNotAllowed::class
abstract val reason: String
}
abstract class NoGetMethod : KtFirDiagnostic<KtArrayAccessExpression>() {
override val diagnosticClass get() = NoGetMethod::class
}
@@ -3096,6 +3096,12 @@ internal class ErrorInContractDescriptionImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.ErrorInContractDescription(), KtAbstractFirDiagnostic<KtElement>
internal class ContractNotAllowedImpl(
override val reason: String,
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.ContractNotAllowed(), KtAbstractFirDiagnostic<KtElement>
internal class NoGetMethodImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
@@ -107,6 +107,7 @@ internal object FirLazyBodiesCalculator {
constructor.apply {
replaceBody(newConstructor.body)
replaceContractDescription(newConstructor.contractDescription)
replaceDelegatedConstructor(newConstructor.delegatedConstructor)
replaceValueParameterDefaultValues(valueParameters, newConstructor.valueParameters)
}
@@ -10,7 +10,7 @@ inline fun <reified T> requreIsInstance(value: Any) contract <!UNSUPPORTED_FEATU
}
val Any?.myLength: Int?
get() contract <!UNSUPPORTED_FEATURE!>[
get() contract <!CONTRACT_NOT_ALLOWED, UNSUPPORTED_FEATURE!>[
<!ERROR_IN_CONTRACT_DESCRIPTION!>returnsNotNull() implies (this@length is String)<!>
]<!> = (this as? String)?.length
@@ -12,8 +12,8 @@ fun Any?.isNotNull(): Boolean {
@OptIn(ExperimentalContracts::class)
val Any?.isNotNull: Boolean
get() {
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(true) implies (this@isNotNull != null)
}
return this@isNotNull != null
}
}
@@ -7,13 +7,13 @@ interface A {
@OptIn(ExperimentalContracts::class)
var Any?.isNotNull: Boolean
get() {
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(true) implies (this@isNotNull != null)
}
return this != null
}
set(value) {
<!WRONG_IMPLIES_CONDITION!>contract {
<!WRONG_IMPLIES_CONDITION!><!CONTRACT_NOT_ALLOWED!>contract<!> {
returns() implies (this@isNotNull != null)
<!ERROR_IN_CONTRACT_DESCRIPTION!>require(<!SENSELESS_COMPARISON!>this != null<!>)<!>
}<!>
@@ -1272,6 +1272,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val ERROR_IN_CONTRACT_DESCRIPTION by error<KtElement>(PositioningStrategy.SELECTOR_BY_QUALIFIED) {
parameter<String>("reason")
}
val CONTRACT_NOT_ALLOWED by error<KtElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<String>("reason")
}
}
val CONVENTIONS by object : DiagnosticGroup("Conventions") {
@@ -668,6 +668,7 @@ object FirErrors {
// Function contracts
val ERROR_IN_CONTRACT_DESCRIPTION by error1<KtElement, String>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
val CONTRACT_NOT_ALLOWED by error1<KtElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
// Conventions
val NO_GET_METHOD by error0<KtArrayAccessExpression>(SourceElementPositioningStrategies.ARRAY_ACCESS)
@@ -64,6 +64,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirAssignmentOperatorCallChecker,
FirNamedVarargChecker,
FirUnderscoredTypeArgumentSyntaxChecker,
FirContractNotFirstStatementChecker,
)
override val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker>
@@ -6,27 +6,38 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.KtRealSourceElementKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
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.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.*
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"
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirContractDescriptionOwner ||
declaration.contractDescription !is FirResolvedContractDescription
) {
return
}
if (declaration !is FirContractDescriptionOwner) return
val contractDescription = declaration.contractDescription as? FirResolvedContractDescription ?: return
checkUnresolvedEffects(contractDescription, context, reporter)
checkContractNotAllowed(declaration, contractDescription, context, reporter)
}
private fun checkUnresolvedEffects(
contractDescription: FirResolvedContractDescription,
context: CheckerContext,
reporter: DiagnosticReporter
) {
// Any statements that [ConeEffectExtractor] cannot extract effects will be in `unresolvedEffects`.
for (unresolvedEffect in (declaration.contractDescription as FirResolvedContractDescription).unresolvedEffects) {
for (unresolvedEffect in contractDescription.unresolvedEffects) {
val statement = unresolvedEffect.statement
if (statement.source == null || statement.source!!.kind is KtFakeSourceElementKind) continue
@@ -35,4 +46,22 @@ object FirContractChecker : FirFunctionChecker() {
reporter.reportOn(statement.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, UNEXPECTED_CONSTRUCTION, context)
}
}
private fun checkContractNotAllowed(
declaration: FirFunction,
contractDescription: FirResolvedContractDescription,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val source = contractDescription.source
if (source?.kind !is KtRealSourceElementKind) return
fun contractNotAllowed(message: String) = reporter.reportOn(source, FirErrors.CONTRACT_NOT_ALLOWED, message, context)
if (declaration is FirPropertyAccessor || declaration is FirAnonymousFunction) contractNotAllowed("Contracts are only allowed for functions")
else if (declaration.isAbstract || declaration.isOpen || declaration.isOverride) contractNotAllowed("Contracts are not allowed for open or override functions")
else if (declaration.isOperator) contractNotAllowed("Contracts are not allowed for operator functions")
else if (declaration.symbol.callableId.isLocal || declaration.visibility == Visibilities.Local) contractNotAllowed("Contracts are not allowed for local functions")
}
}
@@ -0,0 +1,39 @@
/*
* 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.analysis.checkers.expression
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
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.declarations.FirFunction
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.name.StandardClassIds
object FirContractNotFirstStatementChecker : FirFunctionCallChecker() {
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
if (StandardClassIds.Callables.contract != expression.toResolvedCallableSymbol()?.callableId) return
val containingDeclaration = context.containingDeclarations.last()
if (!(containingDeclaration is FirFunction && expression.isCorrectlyPlacedIn(containingDeclaration))) {
val message = if (containingDeclaration is FirFunction && containingDeclaration.body is FirSingleExpressionBlock) {
"Contracts are only allowed in function body blocks"
} else {
"Contract should be the first statement"
}
reporter.reportOn(expression.source, FirErrors.CONTRACT_NOT_ALLOWED, message, context)
}
}
private fun FirFunctionCall.isCorrectlyPlacedIn(functionDeclaration: FirFunction): Boolean {
val firstStatement = functionDeclaration.body?.statements?.first()
return firstStatement is FirContractCallBlock && firstStatement.call == this
}
}
@@ -134,6 +134,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITHOUT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_DELEGATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_GETTER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONTRACT_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_GENERIC_UPPER_BOUND
@@ -1909,6 +1910,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
// Function contracts
map.put(ERROR_IN_CONTRACT_DESCRIPTION, "Error in contract description", TO_STRING)
map.put(CONTRACT_NOT_ALLOWED, "{0}", TO_STRING)
// Conventions
map.put(NO_GET_METHOD, "No get method providing array access")
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirImplementationDetail
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.FirConstructorBuilder
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
@@ -44,6 +46,7 @@ class FirJavaConstructor @FirImplementationDetail constructor(
) : FirConstructor() {
override val receiverParameter: FirReceiverParameter? get() = null
override var deprecationsProvider: DeprecationsProvider = UnresolvedDeprecationProvider
override val contractDescription: FirContractDescription get() = FirEmptyContractDescription
init {
symbol.bind(this)
@@ -100,6 +103,10 @@ class FirJavaConstructor @FirImplementationDetail constructor(
return this
}
override fun <D> transformContractDescription(transformer: FirTransformer<D>, data: D): FirConstructor {
return this
}
override fun <D> transformStatus(transformer: FirTransformer<D>, data: D): FirJavaConstructor {
status = status.transformSingle(transformer, data)
return this
@@ -152,6 +159,9 @@ class FirJavaConstructor @FirImplementationDetail constructor(
}
override fun replaceControlFlowGraphReference(newControlFlowGraphReference: FirControlFlowGraphReference?) {}
override fun replaceContractDescription(newContractDescription: FirContractDescription) {
error("Contract description cannot be replaced for FirJavaConstructor")
}
override fun replaceBody(newBody: FirBlock?) {
error("Body cannot be replaced for FirJavaConstructor")
@@ -1045,8 +1045,9 @@ class DeclarationsConverter(
annotations += modifiers.annotations
typeParameters += constructorTypeParametersFromConstructedClass(classWrapper.classBuilder.typeParameters)
valueParameters += firValueParameters.map { it.firValueParameter }
val (body, _) = convertFunctionBody(block, null, allowLegacyContractDescription = true)
val (body, contractDescription) = convertFunctionBody(block, null, allowLegacyContractDescription = true)
this.body = body
contractDescription?.let { this.contractDescription = it }
context.firFunctionTargets.removeLast()
this.contextReceivers.addAll(convertContextReceivers(secondaryConstructor.getParent()!!.getParent()!!))
}.also {
@@ -1736,14 +1737,15 @@ class DeclarationsConverter(
).map { it.firValueParameter }
}
val allowLegacyContractDescription = outerContractDescription == null && !isLocal
val allowLegacyContractDescription = outerContractDescription == null
val bodyWithContractDescription = convertFunctionBody(block, expression, allowLegacyContractDescription)
this.body = bodyWithContractDescription.first
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
contractDescription?.let {
// TODO: add error reporting for contracts on lambdas
if (this is FirSimpleFunctionBuilder) {
this.contractDescription = it
} else if (this is FirAnonymousFunctionBuilder) {
this.contractDescription = it
}
}
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusIm
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.expressions.impl.buildSingleExpressionBlock
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
@@ -201,6 +202,13 @@ class ExpressionsConverter(
body = if (block != null) {
declarationsConverter.withOffset(expressionSource.startOffset) {
declarationsConverter.convertBlockExpressionWithoutBuilding(block!!).apply {
statements.firstOrNull()?.let {
if (it.isContractBlockFirCheck()) {
this@buildAnonymousFunction.contractDescription = it.toLegacyRawContractDescription()
statements[0] = FirContractCallBlock(it)
}
}
if (statements.isEmpty()) {
statements.add(
buildReturnExpression {
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.references.builder.*
@@ -365,13 +366,13 @@ open class RawFirBuilder(
}
}
private fun KtDeclarationWithBody.buildFirBody(allowLegacyContractDescription: Boolean): Pair<FirBlock?, FirContractDescription?> =
private fun KtDeclarationWithBody.buildFirBody(): Pair<FirBlock?, FirContractDescription?> =
if (hasBody()) {
buildOrLazyBlock {
if (hasBlockBody()) {
val block = bodyBlockExpression?.accept(this@Visitor, Unit) as? FirBlock
val contractDescription = when {
allowLegacyContractDescription && !hasContractEffectList() -> block?.let(::processLegacyContractDescription)
!hasContractEffectList() -> block?.let(::processLegacyContractDescription)
else -> null
}
return@buildFirBody block to contractDescription
@@ -471,9 +472,9 @@ open class RawFirBuilder(
}
}
val outerContractDescription = this@toFirPropertyAccessor.obtainContractDescription()
val bodyWithContractDescription = this@toFirPropertyAccessor.buildFirBody(allowLegacyContractDescription = true)
this.body = bodyWithContractDescription.first
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
val (body, innerContractDescription) = this@toFirPropertyAccessor.buildFirBody()
this.body = body
val contractDescription = outerContractDescription ?: innerContractDescription
contractDescription?.let {
this.contractDescription = it
}
@@ -1484,13 +1485,14 @@ open class RawFirBuilder(
listOf()
withCapturedTypeParameters(true, functionSource, actualTypeParameters) {
val outerContractDescription = function.obtainContractDescription()
val bodyWithContractDescription = function.buildFirBody(!isLocalFunction)
this.body = bodyWithContractDescription.first
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
val (body, innerContractDescription) = function.buildFirBody()
this.body = body
val contractDescription = outerContractDescription ?: innerContractDescription
contractDescription?.let {
// TODO: add error reporting for contracts on lambdas
if (this is FirSimpleFunctionBuilder) {
this.contractDescription = it
} else if (this is FirAnonymousFunctionBuilder) {
this.contractDescription = it
}
}
}
@@ -1601,6 +1603,13 @@ open class RawFirBuilder(
FirSingleExpressionBlock(errorExpression.toReturn())
} else {
configureBlockWithoutBuilding(ktBody).apply {
statements.firstOrNull()?.let {
if (it.isContractBlockFirCheck()) {
this@buildAnonymousFunction.contractDescription = it.toLegacyRawContractDescription()
statements[0] = FirContractCallBlock(it)
}
}
if (statements.isEmpty()) {
statements.add(
buildReturnExpression {
@@ -1660,7 +1669,8 @@ open class RawFirBuilder(
extractValueParametersTo(this, symbol, ValueParameterDeclaration.FUNCTION)
val (body, _) = buildFirBody(allowLegacyContractDescription = true)
val (body, contractDescription) = buildFirBody()
contractDescription?.let { this.contractDescription = it }
this.body = body
this@RawFirBuilder.context.firFunctionTargets.removeLast()
}.also {
@@ -2757,7 +2767,7 @@ open class RawFirBuilder(
}
}
private fun buildErrorTopLevelDeclarationForDanglingModifierList(modifierList : KtModifierList) = buildDanglingModifierList {
private fun buildErrorTopLevelDeclarationForDanglingModifierList(modifierList: KtModifierList) = buildDanglingModifierList {
this.source = modifierList.toFirSourceElement(KtFakeSourceElementKind.DanglingModifierList)
moduleData = baseModuleData
origin = FirDeclarationOrigin.Source
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
import org.jetbrains.kotlin.fir.contracts.builder.buildLegacyRawContractDescription
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
@@ -43,6 +44,8 @@ import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
fun String.parseCharacter(): CharacterWithDiagnostic {
// Strip the quotes
@@ -495,18 +498,29 @@ fun <T> FirPropertyBuilder.generateAccessorsByDelegate(
fun processLegacyContractDescription(block: FirBlock): FirContractDescription? {
if (block.isContractPresentFirCheck()) {
val contractCall = block.replaceFirstStatement<FirFunctionCall> { FirContractCallBlock(it) }
return buildLegacyRawContractDescription {
source = contractCall.source
this.contractCall = contractCall
}
return contractCall.toLegacyRawContractDescription()
}
return null
}
fun FirFunctionCall.toLegacyRawContractDescription(): FirLegacyRawContractDescription {
return buildLegacyRawContractDescription {
this.source = this@toLegacyRawContractDescription.source
this.contractCall = this@toLegacyRawContractDescription
}
}
fun FirBlock.isContractPresentFirCheck(): Boolean {
val firstStatement = statements.firstOrNull() ?: return false
val contractCall = firstStatement as? FirFunctionCall ?: return false
return firstStatement.isContractBlockFirCheck()
}
@OptIn(ExperimentalContracts::class)
fun FirStatement.isContractBlockFirCheck(): Boolean {
contract { returns(true) implies (this@isContractBlockFirCheck is FirFunctionCall) }
val contractCall = this as? FirFunctionCall ?: return false
if (contractCall.calleeReference.name.asString() != "contract") return false
val receiver = contractCall.explicitReceiver as? FirQualifiedAccessExpression ?: return true
if (!contractCall.checkReceiver("contracts")) return false
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunctionCopy
import org.jetbrains.kotlin.fir.declarations.builder.buildContextReceiver
@@ -36,6 +37,7 @@ import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionT
import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor
import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolver
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.runContractResolveForFunction
import org.jetbrains.kotlin.fir.resolve.transformers.transformVarargTypeToArrayType
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
@@ -590,6 +592,10 @@ open class FirDeclarationsResolveTransformer(
// For class members everything should be already prepared
prepareSignatureForBodyResolve(simpleFunction)
simpleFunction.transformStatus(this, simpleFunction.resolveStatus().mode())
if (simpleFunction.contractDescription != FirEmptyContractDescription) {
simpleFunction.runContractResolveForFunction(session, scopeSession, context)
}
}
context.forFunctionBody(simpleFunction, components) {
withFullBodyResolve {
@@ -730,6 +736,11 @@ open class FirDeclarationsResolveTransformer(
anonymousFunction.transformReceiverParameter(transformer, ResolutionMode.ContextIndependent)
anonymousFunction.valueParameters.forEach { it.transformReturnTypeRef(transformer, ResolutionMode.ContextIndependent) }
}
if (anonymousFunction.contractDescription != FirEmptyContractDescription) {
anonymousFunction.runContractResolveForFunction(session, scopeSession, context)
}
return when (data) {
is ResolutionMode.ContextDependent, is ResolutionMode.ContextDependentDelegate -> {
context.storeContextForAnonymousFunction(anonymousFunction)
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.errorTypeFromPrototype
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
@@ -26,7 +25,6 @@ import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
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.BodyResolveContext
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformerDispatcher
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer
@@ -72,19 +70,8 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
simpleFunction: FirSimpleFunction,
data: ResolutionMode
): FirSimpleFunction {
if (!simpleFunction.hasContractToResolve) {
return simpleFunction
}
val containingDeclaration = context.containerIfAny
if (containingDeclaration != null && containingDeclaration !is FirClass) {
simpleFunction.replaceReturnTypeRef(
simpleFunction.returnTypeRef.errorTypeFromPrototype(
ConeContractDescriptionError("Local function can not be used in contract description")
)
)
return simpleFunction
}
@Suppress("UNCHECKED_CAST")
if (!simpleFunction.hasContractToResolve) return simpleFunction
return context.withSimpleFunction(simpleFunction, session) {
context.forFunctionBody(simpleFunction, components) {
transformContractDescriptionOwner(simpleFunction)
@@ -92,6 +79,15 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
}
}
override fun transformAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: ResolutionMode): FirAnonymousFunction {
if (!anonymousFunction.hasContractToResolve) return anonymousFunction
return context.forFunctionBody(anonymousFunction, components) {
transformContractDescriptionOwner(anonymousFunction)
}
}
override fun transformScript(script: FirScript, data: ResolutionMode): FirScript {
return script
}
@@ -282,7 +278,14 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
}
override fun transformConstructor(constructor: FirConstructor, data: ResolutionMode): FirConstructor {
return constructor
if (!constructor.hasContractToResolve) {
return constructor
}
return context.withConstructor(constructor) {
context.forConstructorBody(constructor, session) {
transformContractDescriptionOwner(constructor)
}
}
}
override fun transformEnumEntry(enumEntry: FirEnumEntry, data: ResolutionMode): FirEnumEntry {
@@ -302,15 +305,13 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
private val FirContractDescriptionOwner.valueParameters: List<FirValueParameter>
get() = when (this) {
is FirSimpleFunction -> valueParameters
is FirPropertyAccessor -> valueParameters
is FirFunction -> valueParameters
else -> error()
}
private val FirContractDescriptionOwner.body: FirBlock
get() = when (this) {
is FirSimpleFunction -> body!!
is FirPropertyAccessor -> body!!
is FirFunction -> body!!
else -> error()
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
@@ -52,3 +53,13 @@ fun <F : FirClassLikeDeclaration> F.runContractResolveForLocalClass(
return this.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
fun <F : FirFunction> F.runContractResolveForFunction(
session: FirSession,
scopeSession: ScopeSession,
outerBodyResolveContext: BodyResolveContext,
): F {
val transformer = FirContractResolveTransformer(session, scopeSession, outerBodyResolveContext)
return this.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
@@ -24,7 +25,7 @@ import org.jetbrains.kotlin.fir.visitors.*
* DO NOT MODIFY IT MANUALLY
*/
abstract class FirAnonymousFunction : FirFunction(), FirTypeParametersOwner {
abstract class FirAnonymousFunction : FirFunction(), FirTypeParametersOwner, FirContractDescriptionOwner {
abstract override val source: KtSourceElement?
abstract override val resolvePhase: FirResolvePhase
abstract override val annotations: List<FirAnnotation>
@@ -41,6 +42,7 @@ abstract class FirAnonymousFunction : FirFunction(), FirTypeParametersOwner {
abstract override val controlFlowGraphReference: FirControlFlowGraphReference?
abstract override val valueParameters: List<FirValueParameter>
abstract override val body: FirBlock?
abstract override val contractDescription: FirContractDescription
abstract override val symbol: FirAnonymousFunctionSymbol
abstract val label: FirLabel?
abstract val invocationKind: EventOccurrencesRange?
@@ -76,6 +78,8 @@ abstract class FirAnonymousFunction : FirFunction(), FirTypeParametersOwner {
abstract override fun replaceBody(newBody: FirBlock?)
abstract override fun replaceContractDescription(newContractDescription: FirContractDescription)
abstract fun replaceInvocationKind(newInvocationKind: EventOccurrencesRange?)
abstract fun replaceInlineStatus(newInlineStatus: InlineStatus)
@@ -94,5 +98,7 @@ abstract class FirAnonymousFunction : FirFunction(), FirTypeParametersOwner {
abstract override fun <D> transformBody(transformer: FirTransformer<D>, data: D): FirAnonymousFunction
abstract override fun <D> transformContractDescription(transformer: FirTransformer<D>, data: D): FirAnonymousFunction
abstract override fun <D> transformTypeParameters(transformer: FirTransformer<D>, data: D): FirAnonymousFunction
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.declarations
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
@@ -23,7 +24,7 @@ import org.jetbrains.kotlin.fir.visitors.*
* DO NOT MODIFY IT MANUALLY
*/
abstract class FirConstructor : FirFunction(), FirTypeParameterRefsOwner {
abstract class FirConstructor : FirFunction(), FirTypeParameterRefsOwner, FirContractDescriptionOwner {
abstract override val source: KtSourceElement?
abstract override val resolvePhase: FirResolvePhase
abstract override val moduleData: FirModuleData
@@ -39,6 +40,7 @@ abstract class FirConstructor : FirFunction(), FirTypeParameterRefsOwner {
abstract override val contextReceivers: List<FirContextReceiver>
abstract override val controlFlowGraphReference: FirControlFlowGraphReference?
abstract override val valueParameters: List<FirValueParameter>
abstract override val contractDescription: FirContractDescription
abstract override val annotations: List<FirAnnotation>
abstract override val symbol: FirConstructorSymbol
abstract val delegatedConstructor: FirDelegatedConstructorCall?
@@ -67,6 +69,8 @@ abstract class FirConstructor : FirFunction(), FirTypeParameterRefsOwner {
abstract override fun replaceValueParameters(newValueParameters: List<FirValueParameter>)
abstract override fun replaceContractDescription(newContractDescription: FirContractDescription)
abstract override fun replaceAnnotations(newAnnotations: List<FirAnnotation>)
abstract fun replaceDelegatedConstructor(newDelegatedConstructor: FirDelegatedConstructorCall?)
@@ -83,6 +87,8 @@ abstract class FirConstructor : FirFunction(), FirTypeParameterRefsOwner {
abstract override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirConstructor
abstract override fun <D> transformContractDescription(transformer: FirTransformer<D>, data: D): FirConstructor
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirConstructor
abstract fun <D> transformDelegatedConstructor(transformer: FirTransformer<D>, data: D): FirConstructor
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.fir.declarations.builder
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.declarations.DeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
@@ -55,6 +56,7 @@ interface FirAbstractConstructorBuilder : FirFunctionBuilder {
abstract val typeParameters: MutableList<FirTypeParameterRef>
abstract var receiverParameter: FirReceiverParameter?
abstract var controlFlowGraphReference: FirControlFlowGraphReference?
abstract var contractDescription: FirContractDescription
abstract var symbol: FirConstructorSymbol
abstract var delegatedConstructor: FirDelegatedConstructorCall?
override fun build(): FirConstructor
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.DeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
@@ -61,6 +63,7 @@ class FirAnonymousFunctionBuilder : FirFunctionBuilder, FirAnnotationContainerBu
var controlFlowGraphReference: FirControlFlowGraphReference? = null
override val valueParameters: MutableList<FirValueParameter> = mutableListOf()
override var body: FirBlock? = null
var contractDescription: FirContractDescription = FirEmptyContractDescription
lateinit var symbol: FirAnonymousFunctionSymbol
var label: FirLabel? = null
var invocationKind: EventOccurrencesRange? = null
@@ -86,6 +89,7 @@ class FirAnonymousFunctionBuilder : FirFunctionBuilder, FirAnnotationContainerBu
controlFlowGraphReference,
valueParameters,
body,
contractDescription,
symbol,
label,
invocationKind,
@@ -141,6 +145,7 @@ inline fun buildAnonymousFunctionCopy(original: FirAnonymousFunction, init: FirA
copyBuilder.controlFlowGraphReference = original.controlFlowGraphReference
copyBuilder.valueParameters.addAll(original.valueParameters)
copyBuilder.body = original.body
copyBuilder.contractDescription = original.contractDescription
copyBuilder.symbol = original.symbol
copyBuilder.label = original.label
copyBuilder.invocationKind = original.invocationKind
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.DeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
@@ -57,6 +59,7 @@ open class FirConstructorBuilder : FirAbstractConstructorBuilder, FirAnnotationC
override var dispatchReceiverType: ConeSimpleKotlinType? = null
override val contextReceivers: MutableList<FirContextReceiver> = mutableListOf()
override val valueParameters: MutableList<FirValueParameter> = mutableListOf()
override var contractDescription: FirContractDescription = FirEmptyContractDescription
override val annotations: MutableList<FirAnnotation> = mutableListOf()
override lateinit var symbol: FirConstructorSymbol
override var delegatedConstructor: FirDelegatedConstructorCall? = null
@@ -78,6 +81,7 @@ open class FirConstructorBuilder : FirAbstractConstructorBuilder, FirAnnotationC
dispatchReceiverType,
contextReceivers.toMutableOrEmpty(),
valueParameters,
contractDescription,
annotations.toMutableOrEmpty(),
symbol,
delegatedConstructor,
@@ -122,6 +126,7 @@ inline fun buildConstructorCopy(original: FirConstructor, init: FirConstructorBu
copyBuilder.dispatchReceiverType = original.dispatchReceiverType
copyBuilder.contextReceivers.addAll(original.contextReceivers)
copyBuilder.valueParameters.addAll(original.valueParameters)
copyBuilder.contractDescription = original.contractDescription
copyBuilder.annotations.addAll(original.annotations)
copyBuilder.symbol = original.symbol
copyBuilder.delegatedConstructor = original.delegatedConstructor
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.DeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
@@ -58,6 +60,7 @@ class FirPrimaryConstructorBuilder : FirAbstractConstructorBuilder, FirAnnotatio
override var dispatchReceiverType: ConeSimpleKotlinType? = null
override val contextReceivers: MutableList<FirContextReceiver> = mutableListOf()
override val valueParameters: MutableList<FirValueParameter> = mutableListOf()
override var contractDescription: FirContractDescription = FirEmptyContractDescription
override val annotations: MutableList<FirAnnotation> = mutableListOf()
override lateinit var symbol: FirConstructorSymbol
override var delegatedConstructor: FirDelegatedConstructorCall? = null
@@ -80,6 +83,7 @@ class FirPrimaryConstructorBuilder : FirAbstractConstructorBuilder, FirAnnotatio
dispatchReceiverType,
contextReceivers.toMutableOrEmpty(),
valueParameters,
contractDescription,
annotations.toMutableOrEmpty(),
symbol,
delegatedConstructor,
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.declarations.DeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
@@ -54,6 +55,7 @@ internal class FirAnonymousFunctionImpl(
override var controlFlowGraphReference: FirControlFlowGraphReference?,
override val valueParameters: MutableList<FirValueParameter>,
override var body: FirBlock?,
override var contractDescription: FirContractDescription,
override val symbol: FirAnonymousFunctionSymbol,
override var label: FirLabel?,
override var invocationKind: EventOccurrencesRange?,
@@ -80,6 +82,7 @@ internal class FirAnonymousFunctionImpl(
controlFlowGraphReference?.accept(visitor, data)
valueParameters.forEach { it.accept(visitor, data) }
body?.accept(visitor, data)
contractDescription.accept(visitor, data)
label?.accept(visitor, data)
typeParameters.forEach { it.accept(visitor, data) }
typeRef.accept(visitor, data)
@@ -94,6 +97,7 @@ internal class FirAnonymousFunctionImpl(
controlFlowGraphReference = controlFlowGraphReference?.transform(transformer, data)
transformValueParameters(transformer, data)
transformBody(transformer, data)
transformContractDescription(transformer, data)
label = label?.transform(transformer, data)
transformTypeParameters(transformer, data)
typeRef = typeRef.transform(transformer, data)
@@ -130,6 +134,11 @@ internal class FirAnonymousFunctionImpl(
return this
}
override fun <D> transformContractDescription(transformer: FirTransformer<D>, data: D): FirAnonymousFunctionImpl {
contractDescription = contractDescription.transform(transformer, data)
return this
}
override fun <D> transformTypeParameters(transformer: FirTransformer<D>, data: D): FirAnonymousFunctionImpl {
typeParameters.transformInplace(transformer, data)
return this
@@ -176,6 +185,10 @@ internal class FirAnonymousFunctionImpl(
body = newBody
}
override fun replaceContractDescription(newContractDescription: FirContractDescription) {
contractDescription = newContractDescription
}
override fun replaceInvocationKind(newInvocationKind: EventOccurrencesRange?) {
invocationKind = newInvocationKind
}
@@ -9,6 +9,7 @@ package org.jetbrains.kotlin.fir.declarations.impl
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.declarations.DeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
@@ -52,6 +53,7 @@ internal class FirConstructorImpl(
override val dispatchReceiverType: ConeSimpleKotlinType?,
override var contextReceivers: MutableOrEmptyList<FirContextReceiver>,
override val valueParameters: MutableList<FirValueParameter>,
override var contractDescription: FirContractDescription,
override var annotations: MutableOrEmptyList<FirAnnotation>,
override val symbol: FirConstructorSymbol,
override var delegatedConstructor: FirDelegatedConstructorCall?,
@@ -72,6 +74,7 @@ internal class FirConstructorImpl(
contextReceivers.forEach { it.accept(visitor, data) }
controlFlowGraphReference?.accept(visitor, data)
valueParameters.forEach { it.accept(visitor, data) }
contractDescription.accept(visitor, data)
annotations.forEach { it.accept(visitor, data) }
delegatedConstructor?.accept(visitor, data)
body?.accept(visitor, data)
@@ -85,6 +88,7 @@ internal class FirConstructorImpl(
contextReceivers.transformInplace(transformer, data)
controlFlowGraphReference = controlFlowGraphReference?.transform(transformer, data)
transformValueParameters(transformer, data)
transformContractDescription(transformer, data)
transformAnnotations(transformer, data)
transformDelegatedConstructor(transformer, data)
transformBody(transformer, data)
@@ -116,6 +120,11 @@ internal class FirConstructorImpl(
return this
}
override fun <D> transformContractDescription(transformer: FirTransformer<D>, data: D): FirConstructorImpl {
contractDescription = contractDescription.transform(transformer, data)
return this
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirConstructorImpl {
annotations.transformInplace(transformer, data)
return this
@@ -164,6 +173,10 @@ internal class FirConstructorImpl(
valueParameters.addAll(newValueParameters)
}
override fun replaceContractDescription(newContractDescription: FirContractDescription) {
contractDescription = newContractDescription
}
override fun replaceAnnotations(newAnnotations: List<FirAnnotation>) {
annotations = newAnnotations.toMutableOrEmpty()
}
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.fir.declarations.impl
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirImplementationDetail
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.declarations.DeprecationsProvider
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirContextReceiver
@@ -53,6 +54,7 @@ class FirPrimaryConstructor @FirImplementationDetail constructor(
override val dispatchReceiverType: ConeSimpleKotlinType?,
override var contextReceivers: MutableOrEmptyList<FirContextReceiver>,
override val valueParameters: MutableList<FirValueParameter>,
override var contractDescription: FirContractDescription,
override var annotations: MutableOrEmptyList<FirAnnotation>,
override val symbol: FirConstructorSymbol,
override var delegatedConstructor: FirDelegatedConstructorCall?,
@@ -73,6 +75,7 @@ class FirPrimaryConstructor @FirImplementationDetail constructor(
contextReceivers.forEach { it.accept(visitor, data) }
controlFlowGraphReference?.accept(visitor, data)
valueParameters.forEach { it.accept(visitor, data) }
contractDescription.accept(visitor, data)
annotations.forEach { it.accept(visitor, data) }
delegatedConstructor?.accept(visitor, data)
body?.accept(visitor, data)
@@ -86,6 +89,7 @@ class FirPrimaryConstructor @FirImplementationDetail constructor(
contextReceivers.transformInplace(transformer, data)
controlFlowGraphReference = controlFlowGraphReference?.transform(transformer, data)
transformValueParameters(transformer, data)
transformContractDescription(transformer, data)
transformAnnotations(transformer, data)
transformDelegatedConstructor(transformer, data)
transformBody(transformer, data)
@@ -117,6 +121,11 @@ class FirPrimaryConstructor @FirImplementationDetail constructor(
return this
}
override fun <D> transformContractDescription(transformer: FirTransformer<D>, data: D): FirPrimaryConstructor {
contractDescription = contractDescription.transform(transformer, data)
return this
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirPrimaryConstructor {
annotations.transformInplace(transformer, data)
return this
@@ -165,6 +174,10 @@ class FirPrimaryConstructor @FirImplementationDetail constructor(
valueParameters.addAll(newValueParameters)
}
override fun replaceContractDescription(newContractDescription: FirContractDescription) {
contractDescription = newContractDescription
}
override fun replaceAnnotations(newAnnotations: List<FirAnnotation>) {
annotations = newAnnotations.toMutableOrEmpty()
}
@@ -89,6 +89,8 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
parents += abstractConstructorBuilder
defaultNull("delegatedConstructor")
defaultNull("body")
default("contractDescription", "FirEmptyContractDescription")
useTypes(emptyContractDescriptionType)
}
}
@@ -266,7 +268,9 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
parents += functionBuilder
defaultNull("invocationKind", "label", "body", "controlFlowGraphReference")
default("inlineStatus", "InlineStatus.Unknown")
default("contractDescription", "FirEmptyContractDescription")
withCopy()
useTypes(emptyContractDescriptionType)
}
builder(propertyAccessor) {
@@ -60,12 +60,12 @@ object FirTreeBuilder : AbstractFirTreeBuilder() {
val simpleFunction by element(Declaration, function, contractDescriptionOwner, typeParametersOwner)
val propertyAccessor by element(Declaration, function, contractDescriptionOwner, typeParametersOwner)
val backingField by element(Declaration, variable, typeParametersOwner, statement)
val constructor by element(Declaration, function, typeParameterRefsOwner)
val constructor by element(Declaration, function, typeParameterRefsOwner, contractDescriptionOwner)
val file by element(Declaration, declaration)
val script by element(Declaration, declaration)
val packageDirective by element(Other)
val anonymousFunction by element(Declaration, function, typeParametersOwner)
val anonymousFunction by element(Declaration, function, typeParametersOwner, contractDescriptionOwner)
val anonymousFunctionExpression by element(Expression, expression)
val anonymousObject by element(Declaration, klass, controlFlowGraphOwner)
@@ -10,19 +10,19 @@ open class Class {
fun member(x: Boolean) {
contract { returns() implies (x) }
}
inline fun inlineMember(x: Boolean) {
contract { returns() implies (x) }
}
abstract fun abstractMember(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
open fun openMemeber(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
suspend fun suspendMember(x: Boolean) {
contract { returns() implies (x) }
}
@@ -44,43 +44,43 @@ suspend fun suspendTopLevel(x: Boolean) {
// Top-level operator
operator fun Boolean.plus(x: Boolean): Boolean {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
return x
}
val topLevelLambda: (Boolean) -> Unit = { x: Boolean ->
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
val topLevelAnonymousFunction = fun (x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
var topLevelPropertyAccessors: Int? = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>42<!>
get() {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
<!CONTRACT_NOT_ALLOWED!>contract<!> { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
return 42
}
set(value) {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
<!CONTRACT_NOT_ALLOWED!>contract<!> { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
}
// ============= Local =====================
fun test() {
fun localDeclaration(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
suspend fun suspendlocalDeclaration(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
val localAnonymousFunction = fun (x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
val localLambda: (Boolean) -> Unit = { x: Boolean ->
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
}
@@ -10,19 +10,19 @@ open class Class {
fun member(x: Boolean) {
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
inline fun inlineMember(x: Boolean) {
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
abstract fun abstractMember(x: Boolean) {
<!CONTRACT_NOT_ALLOWED, CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
open fun openMemeber(x: Boolean) {
<!CONTRACT_NOT_ALLOWED, CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
suspend fun suspendMember(x: Boolean) {
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
@@ -83,4 +83,4 @@ fun test() {
val localLambda: (Boolean) -> Unit = { x: Boolean ->
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
}
}
@@ -7,6 +7,11 @@ import kotlin.contracts.*
// ============= Class =====================
open class Class {
constructor(f: () -> Unit = {}) {
contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) }
f()
}
fun member(x: Boolean) {
contract { returns() implies (x) }
}
@@ -16,11 +21,11 @@ open class Class {
}
abstract fun abstractMember(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
open fun openMemeber(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
suspend fun suspendMember(x: Boolean) {
@@ -30,17 +35,17 @@ open class Class {
open class Inheritor : Class() {
override fun openMemeber(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
final override fun abstractMember(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
}
interface Interface {
fun implicitlyOpenMember(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
}
@@ -59,43 +64,43 @@ suspend fun suspendTopLevel(x: Boolean) {
// Top-level operator
operator fun Boolean.plus(x: Boolean): Boolean {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
return x
}
val topLevelLambda: (Boolean) -> Unit = { x: Boolean ->
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
val topLevelAnonymousFunction = fun (x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
var topLevelPropertyAccessors: Int? = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>42<!>
get() {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
<!CONTRACT_NOT_ALLOWED!>contract<!> { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
return 42
}
set(value) {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
<!CONTRACT_NOT_ALLOWED!>contract<!> { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_REFERENCE!>field<!> != null)<!> }
}
// ============= Local =====================
fun test() {
fun localDeclaration(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
suspend fun suspendlocalDeclaration(x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
val localAnonymousFunction = fun (x: Boolean) {
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
val localLambda: (Boolean) -> Unit = { x: Boolean ->
contract { returns() implies (x) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { returns() implies (x) }
}
}
@@ -7,6 +7,11 @@ import kotlin.contracts.*
// ============= Class =====================
open class Class {
constructor(f: () -> Unit = {}) {
contract { callsInPlace(f, InvocationKind.EXACTLY_ONCE) }
f()
}
fun member(x: Boolean) {
contract { returns() implies (x) }
}
@@ -16,7 +16,7 @@ public fun topLevel(/*0*/ x: kotlin.Boolean): kotlin.Unit
public operator fun kotlin.Boolean.plus(/*0*/ x: kotlin.Boolean): kotlin.Boolean
public open class Class {
public constructor Class()
public constructor Class(/*0*/ f: () -> kotlin.Unit = ...)
public abstract fun abstractMember(/*0*/ x: kotlin.Boolean): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -7,30 +7,30 @@ import kotlin.contracts.*
fun foo(y: Boolean) {
val x: Int = 42
contract {
<!CONTRACT_NOT_ALLOWED("Contract should be the first statement")!>contract<!> {
returns() implies y
}
}
inline fun case1(block: () -> Unit) {
val contracts = listOf(
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}, contract {
}, <!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}
)
block()
}
inline fun case_2(block: () -> Unit) = contract {
inline fun case_2(block: () -> Unit) = <!CONTRACT_NOT_ALLOWED("Contracts are only allowed in function body blocks")!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}
fun case_3(block: () -> Unit) {
class Class {
fun innerFun(block2: () -> Unit) {
contract {
<!CONTRACT_NOT_ALLOWED("Contracts are not allowed for local functions")!>contract<!> {
callsInPlace(block2, InvocationKind.EXACTLY_ONCE)
}
block2()
@@ -41,7 +41,7 @@ fun case_3(block: () -> Unit) {
inline fun case_4(number: Int?): Boolean {
val cond = number != null
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(false) implies (cond)
} as ContractBuilder
return number == null
@@ -49,8 +49,8 @@ inline fun case_4(number: Int?): Boolean {
inline fun case_5(cond: Boolean): Boolean {
run {
contract {
returns(true) implies (cond)
<!CONTRACT_NOT_ALLOWED!>contract<!> {
<!ERROR_IN_CONTRACT_DESCRIPTION!>returns(true) implies (cond)<!>
}
}
return true
@@ -59,7 +59,7 @@ inline fun case_5(cond: Boolean): Boolean {
inline fun case_6(cond: Boolean): Boolean {
run {
val x = 10
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(true) implies (cond)
}
}
@@ -68,8 +68,8 @@ inline fun case_6(cond: Boolean): Boolean {
fun case_7(cond: Boolean): Boolean {
fun innerFun() {
contract {
returns(true) implies (cond)
<!CONTRACT_NOT_ALLOWED!>contract<!> {
<!ERROR_IN_CONTRACT_DESCRIPTION!>returns(true) implies (cond)<!>
}
}
return true
@@ -4,13 +4,13 @@ import kotlin.contracts.*
class A {
var x: Int = 0
get() = f(x)
set(value) contract [returns() implies (value != null)] {
set(value) contract <!CONTRACT_NOT_ALLOWED!>[returns() implies (value != null)]<!> {
field = value + 1
}
var y: Double = 0.0
get() = g(y)
set(value) contract [returns() implies (value != null)] {
set(value) contract <!CONTRACT_NOT_ALLOWED!>[returns() implies (value != null)]<!> {
field = value * 2
}
@@ -6,14 +6,14 @@ import kotlin.contracts.*
// TESTCASE NUMBER: 1
inline fun case_1(block: () -> Unit) {
val value_1 = 1
contract { }
<!CONTRACT_NOT_ALLOWED!>contract<!> { }
return block()
}
// TESTCASE NUMBER: 2
inline fun case_2(block: () -> Unit) {
10 - 1
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}
return block()
@@ -22,7 +22,7 @@ inline fun case_2(block: () -> Unit) {
// TESTCASE NUMBER: 3
inline fun case_3(block: () -> Unit) {
throw Exception()
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.UNKNOWN)
}
return block()
@@ -34,7 +34,7 @@ inline fun case_3(block: () -> Unit) {
*/
inline fun case_4(block: () -> Unit) {
.0009
return contract {
return <!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}
}
@@ -45,7 +45,7 @@ inline fun case_4(block: () -> Unit) {
*/
fun case_5(value_1: Int?) {
println("!")
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(true) implies (value_1 != null)
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
}
@@ -56,7 +56,7 @@ fun case_5(value_1: Int?) {
*/
fun case_6(value_1: Int?) {
100 + 10
throw Exception(contract {
throw Exception(<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(true) implies (value_1 != null)
}.toString())
}
@@ -69,7 +69,7 @@ fun case_7(value_1: Int?) {
for (i in 0..10) {
println(i)
}
return contract {
return <!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(true) implies (value_1 != null)
}
}
@@ -80,7 +80,7 @@ fun case_7(value_1: Int?) {
*/
fun case_8(value_1: Int?) {
val f = 10 - 20
val g = contract {
val g = <!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(true) implies (value_1 != null)
}
}
@@ -91,7 +91,7 @@ fun case_8(value_1: Int?) {
*/
fun case_9(number: Int?): Boolean {
val value_1 = number != null
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns(false) implies (value_1)
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
return number == null
@@ -5,17 +5,17 @@ import kotlin.contracts.*
// TESTCASE NUMBER: 1
inline fun case_1(block: () -> Unit) {
return contract {
return <!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}
}
// TESTCASE NUMBER: 2
fun case_2() = contract { }
fun case_2() = <!CONTRACT_NOT_ALLOWED!>contract<!> { }
// TESTCASE NUMBER: 3
inline fun case_3(block: () -> Unit) {
val value_1 = contract {
val value_1 = <!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}
block()
@@ -39,14 +39,14 @@ inline fun case_5(block: () -> Unit) {
// TESTCASE NUMBER: 6
inline fun case_6(block: () -> Unit) {
throw Exception(contract {
throw Exception(<!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
}.toString())
}
// TESTCASE NUMBER: 7
inline fun case_7(block: () -> Unit) {
funWithAnyArg(contract {
funWithAnyArg(<!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
})
}
@@ -1,47 +0,0 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !OPT_IN: kotlin.contracts.ExperimentalContracts
import kotlin.contracts.*
// TESTCASE NUMBER: 1
fun case_1(value_1: Int?) {
println("!")
contract {
returns(true) implies (value_1 != null)
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
}
// TESTCASE NUMBER: 2
fun case_2(value_1: Int?) {
100 + 10
throw Exception(contract {
returns(true) implies (value_1 != null)
}.toString())
}
// TESTCASE NUMBER: 3
fun case_3(value_1: Int?) {
for (i in 0..10) {
println(i)
}
return contract {
returns(true) implies (value_1 != null)
}
}
// TESTCASE NUMBER: 4
fun case_4(value_1: Int?) {
val f = 10 - 20
val g = contract {
returns(true) implies (value_1 != null)
}
}
// TESTCASE NUMBER: 5
fun case_5(number: Int?): Boolean {
val value_1 = number != null
contract {
returns(false) implies (value_1)
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
return number == null
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !OPT_IN: kotlin.contracts.ExperimentalContracts
@@ -38,7 +38,7 @@ fun case_5(): Boolean? {
// TESTCASE NUMBER: 6
fun case_6(value_1: Boolean): Boolean? {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(null) implies <!ARGUMENT_TYPE_MISMATCH!>contract { returns(null) implies (!value_1) }<!><!> }
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(null) implies <!ARGUMENT_TYPE_MISMATCH!><!CONTRACT_NOT_ALLOWED!>contract<!> { returns(null) implies (!value_1) }<!><!> }
return null
}
@@ -36,7 +36,7 @@ class case_2(value_5: Boolean, val value_1: Boolean) {
init {
fun case_2_1(): Boolean {
contract { returns(false) implies (value_5) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(false) implies (value_5)<!> }
return !(value_5)
}
}
@@ -6,7 +6,7 @@ import kotlin.contracts.*
// TESTCASE NUMBER: 1
fun <T> T?.case_1() {
fun <K> K?.case_1_1(): Boolean {
contract { returns(true) implies (this@case_1 != null) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(true) implies (this@case_1 != null)<!> }
return this@case_1 != null
}
}
@@ -5,7 +5,7 @@ import kotlin.contracts.*
// TESTCASE NUMBER: 1
inline fun case_1(block: () -> Unit) = {
contract {
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
<!CONTRACT_NOT_ALLOWED!>contract<!> {
<!ERROR_IN_CONTRACT_DESCRIPTION!>callsInPlace(block, InvocationKind.EXACTLY_ONCE)<!>
}
}
@@ -6,7 +6,7 @@ import kotlin.contracts.*
// TESTCASE NUMBER: 1
fun case_1() {
val fun_1 = fun(block: () -> Unit) {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return block()
}
@@ -17,7 +17,7 @@ fun case_1() {
// TESTCASE NUMBER: 2
fun case_2() {
val lambda_1 = { block: () -> Unit ->
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
block()
}
@@ -43,7 +43,7 @@ class case_4 : ClassLevel3() {
fun <T>T.case_4_3_wrap() {
fun case_4_3_contract() {
contract { returns() implies (this@case_4_3_wrap is ClassLevel1) }
<!CONTRACT_NOT_ALLOWED!>contract<!> { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (this@case_4_3_wrap is ClassLevel1)<!> }
if (this@case_4_3_wrap !is ClassLevel1) throw Exception()
}
case_4_3_contract()
@@ -6,7 +6,7 @@ import kotlin.contracts.*
// TESTCASE NUMBER: 1
val Boolean.case_1: () -> Unit
get() {
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns() implies (this@case_1)
}
return {}
@@ -15,7 +15,7 @@ val Boolean.case_1: () -> Unit
// TESTCASE NUMBER: 2
val (() -> Unit).case_2: () -> Unit
get() {
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(this@case_2, InvocationKind.EXACTLY_ONCE)
}
return {}
@@ -27,7 +27,7 @@ var Boolean.case_3: () -> Unit
return {}
}
set(value) {
<!WRONG_INVOCATION_KIND!>contract {
<!WRONG_INVOCATION_KIND!><!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(value, InvocationKind.EXACTLY_ONCE)
}<!>
}
@@ -38,7 +38,7 @@ var (() -> Unit).case_4: () -> Unit
return {}
}
set(value) {
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
callsInPlace(this@case_4, InvocationKind.EXACTLY_ONCE)
}
}
@@ -46,7 +46,7 @@ var (() -> Unit).case_4: () -> Unit
// TESTCASE NUMBER: 5
val Boolean.case_5: () -> Unit
get() {
contract {
<!CONTRACT_NOT_ALLOWED!>contract<!> {
returns() implies (this@case_5)
}
@@ -17,6 +17,7 @@ object StandardClassIds {
val BASE_INTERNAL_IR_PACKAGE = BASE_INTERNAL_PACKAGE.child(Name.identifier("ir"))
val BASE_COROUTINES_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("coroutines"))
val BASE_ENUMS_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("enums"))
val BASE_CONTRACTS_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("contracts"))
val builtInsPackages = setOf(
BASE_KOTLIN_PACKAGE,
@@ -216,6 +217,8 @@ object StandardClassIds {
val clone = "clone".callableId(Cloneable)
val not = "not".callableId(Boolean)
val contract = "contract".callableId(BASE_CONTRACTS_PACKAGE)
}
object Java {