[FIR] Implement checks for contract not allowed
^KT-55423 Fixed
This commit is contained in:
committed by
Space Team
parent
b2fbf8bed5
commit
f946ddeb40
+7
@@ -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,
|
||||
|
||||
+5
@@ -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
|
||||
}
|
||||
|
||||
+6
@@ -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,
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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<!>)<!>
|
||||
}<!>
|
||||
|
||||
+3
@@ -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)
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirAssignmentOperatorCallChecker,
|
||||
FirNamedVarargChecker,
|
||||
FirUnderscoredTypeArgumentSyntaxChecker,
|
||||
FirContractNotFirstStatementChecker,
|
||||
)
|
||||
|
||||
override val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker>
|
||||
|
||||
+37
-8
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+39
@@ -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
|
||||
}
|
||||
}
|
||||
+2
@@ -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
@@ -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")
|
||||
|
||||
+5
-3
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -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 {
|
||||
|
||||
+21
-11
@@ -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
|
||||
|
||||
+19
-5
@@ -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
|
||||
|
||||
+11
@@ -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)
|
||||
|
||||
+21
-20
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -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
|
||||
|
||||
+2
@@ -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
|
||||
|
||||
+5
@@ -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
|
||||
|
||||
+5
@@ -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
|
||||
|
||||
+4
@@ -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,
|
||||
|
||||
+13
@@ -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
|
||||
}
|
||||
|
||||
+13
@@ -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()
|
||||
}
|
||||
|
||||
+13
@@ -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()
|
||||
}
|
||||
|
||||
+4
@@ -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) {
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
Vendored
+15
-15
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+5
-5
@@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+19
-14
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+5
@@ -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) }
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Vendored
+11
-11
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -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
-5
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
-47
@@ -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
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
// !OPT_IN: kotlin.contracts.ExperimentalContracts
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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)<!>
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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()
|
||||
|
||||
+5
-5
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user