From 5a92eb2c67fa98bb2b2505531d7351c892d3328a Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 12 Apr 2023 17:31:16 +0300 Subject: [PATCH] [FIR] Properly track problems in contract description during effect extraction --- .../declaration/FirContractChecker.kt | 88 ++++++++++- .../FirContractDeserializer.kt | 4 +- .../contracts/ConeEffectExtractor.kt | 144 ++++++++++++------ ...actContractResolveTransformerDispatcher.kt | 16 +- .../resolve/diagnostics/ConeDiagnostics.kt | 84 +++++++++- .../FirContractElementDeclaration.kt | 28 ++++ .../fir/contracts/FirEffectDeclaration.kt | 5 +- .../FirResolvedContractDescription.kt | 3 +- .../FirContractElementDeclarationBuilder.kt | 43 ++++++ .../FirResolvedContractDescriptionBuilder.kt | 4 +- .../impl/FirContractElementDeclarationImpl.kt | 29 ++++ .../FirResolvedContractDescriptionImpl.kt | 6 +- .../kotlin/fir/visitors/FirDefaultVisitor.kt | 3 + .../fir/visitors/FirDefaultVisitorVoid.kt | 3 + .../kotlin/fir/visitors/FirTransformer.kt | 13 +- .../kotlin/fir/visitors/FirVisitor.kt | 3 + .../kotlin/fir/visitors/FirVisitorVoid.kt | 9 ++ .../kotlin/fir/contracts/ContractUtils.kt | 15 +- .../description/ConeContractDescription.kt | 2 + .../ConeContractDescriptionVisitor.kt | 18 ++- .../fir/contracts/description/ConeEffects.kt | 29 +++- .../ConeErroneousContractElement.kt | 19 +++ .../description/ConeLogicalCombinators.kt | 6 + .../contracts/description/ConePredicates.kt | 24 ++- .../description/ConeUnresolvedEffect.kt | 10 -- .../fir/contracts/description/ConeValues.kt | 26 +++- .../fir/tree/generator/FirTreeBuilder.kt | 3 +- .../generator/ImplementationConfigurator.kt | 2 + .../fir/tree/generator/NodeConfigurator.kt | 6 +- .../kotlin/fir/tree/generator/Types.kt | 2 +- .../contracts/dsl/errors/emptyContract.fir.kt | 4 +- .../illegalConstructionInContractBlock.fir.kt | 4 +- .../contractBuilder/common/neg/8.fir.kt | 2 +- .../effects/callsInPlace/neg/1.fir.kt | 8 +- 34 files changed, 563 insertions(+), 102 deletions(-) create mode 100644 compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirContractElementDeclaration.kt create mode 100644 compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirContractElementDeclarationBuilder.kt create mode 100644 compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirContractElementDeclarationImpl.kt create mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeErroneousContractElement.kt delete mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeUnresolvedEffect.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirContractChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirContractChecker.kt index 176fa8689c4..0f1a3086246 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirContractChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirContractChecker.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration -import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtRealSourceElementKind import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.diagnostics.DiagnosticReporter @@ -13,15 +12,16 @@ import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription +import org.jetbrains.kotlin.fir.contracts.description.* import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor import org.jetbrains.kotlin.fir.declarations.utils.* +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic object FirContractChecker : FirFunctionChecker() { - // TODO: The message should vary. Migrate this to [ConeEffectExtractor] when creating fine-grained errors. - private const val UNEXPECTED_CONSTRUCTION = "unexpected construction in contract description" + private val EMPTY_CONTRACT_MESSAGE = "Empty contract block is not allowed" override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { if (declaration !is FirContractDescriptionOwner) return @@ -29,6 +29,9 @@ object FirContractChecker : FirFunctionChecker() { checkUnresolvedEffects(contractDescription, context, reporter) checkContractNotAllowed(declaration, contractDescription, context, reporter) + if (contractDescription.effects.isEmpty() && contractDescription.unresolvedEffects.isEmpty()) { + reporter.reportOn(contractDescription.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, EMPTY_CONTRACT_MESSAGE, context) + } } private fun checkUnresolvedEffects( @@ -38,12 +41,11 @@ object FirContractChecker : FirFunctionChecker() { ) { // Any statements that [ConeEffectExtractor] cannot extract effects will be in `unresolvedEffects`. for (unresolvedEffect in contractDescription.unresolvedEffects) { - val statement = unresolvedEffect.statement - if (statement.source == null || statement.source!!.kind is KtFakeSourceElementKind) continue + val diagnostic = unresolvedEffect.effect.accept(DiagnosticExtractor, null) ?: continue // TODO: report on fine-grained locations, e.g., ... implies unresolved => report on unresolved, not the entire statement. // but, sometimes, it's just reported on `contract`... - reporter.reportOn(statement.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, UNEXPECTED_CONSTRUCTION, context) + reporter.reportOn(unresolvedEffect.source, FirErrors.ERROR_IN_CONTRACT_DESCRIPTION, diagnostic.reason, context) } } @@ -64,4 +66,78 @@ object FirContractChecker : FirFunctionChecker() { else if (declaration.symbol.callableId.isLocal || declaration.visibility == Visibilities.Local) contractNotAllowed("Contracts are not allowed for local functions") } + private object DiagnosticExtractor : ConeContractDescriptionVisitor() { + override fun visitContractDescriptionElement( + contractDescriptionElement: ConeContractDescriptionElement, + data: Nothing? + ): ConeDiagnostic? { + return null + } + + override fun visitConditionalEffectDeclaration( + conditionalEffect: ConeConditionalEffectDeclaration, + data: Nothing? + ): ConeDiagnostic? { + return conditionalEffect.effect.accept(this, null) ?: conditionalEffect.condition.accept(this, null) + } + + override fun visitReturnsEffectDeclaration(returnsEffect: ConeReturnsEffectDeclaration, data: Nothing?): ConeDiagnostic? { + return returnsEffect.value.accept(this, null) + } + + override fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: Nothing?): ConeDiagnostic? { + return callsEffect.valueParameterReference.accept(this, data) + } + + override fun visitErroneousCallsEffectDeclaration( + callsEffect: ConeErroneousCallsEffectDeclaration, + data: Nothing? + ): ConeDiagnostic { + return callsEffect.diagnostic + } + + override fun visitLogicalBinaryOperationContractExpression( + binaryLogicExpression: ConeBinaryLogicExpression, + data: Nothing? + ): ConeDiagnostic? { + return binaryLogicExpression.left.accept(this, null) ?: binaryLogicExpression.right.accept(this, null) + } + + override fun visitLogicalNot(logicalNot: ConeLogicalNot, data: Nothing?): ConeDiagnostic? { + return logicalNot.arg.accept(this, null) + } + + override fun visitIsInstancePredicate(isInstancePredicate: ConeIsInstancePredicate, data: Nothing?): ConeDiagnostic? { + return isInstancePredicate.arg.accept(this, data) + } + + override fun visitErroneousIsInstancePredicate( + isInstancePredicate: ConeErroneousIsInstancePredicate, + data: Nothing? + ): ConeDiagnostic { + return isInstancePredicate.diagnostic + } + + override fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: Nothing?): ConeDiagnostic? { + return isNullPredicate.arg.accept(this, data) + } + + override fun visitErroneousConstantReference( + erroneousConstantReference: ConeErroneousConstantReference, + data: Nothing? + ): ConeDiagnostic { + return erroneousConstantReference.diagnostic + } + + override fun visitErroneousValueParameterReference( + valueParameterReference: ConeErroneousValueParameterReference, + data: Nothing? + ): ConeDiagnostic { + return valueParameterReference.diagnostic + } + + override fun visitErroneousElement(element: ConeErroneousContractElement, data: Nothing?): ConeDiagnostic { + return element.diagnostic + } + } } diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt index 848e980485c..9356d74b88a 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription import org.jetbrains.kotlin.fir.contracts.description.* -import org.jetbrains.kotlin.fir.contracts.toFirEffectDeclaration +import org.jetbrains.kotlin.fir.contracts.toFirElement import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.expressions.LogicOperationKind @@ -24,7 +24,7 @@ class FirContractDeserializer(private val c: FirDeserializationContext) { fun loadContract(proto: ProtoBuf.Contract, owner: FirContractDescriptionOwner): FirContractDescription? { val effects = proto.effectList.map { loadPossiblyConditionalEffect(it, owner) ?: return null } return buildResolvedContractDescription { - this.effects += effects.map { it.toFirEffectDeclaration() } + this.effects += effects.map { it.toFirElement() } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt index d95a5098ca1..a9d9817b96f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt @@ -11,39 +11,49 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.contracts.description.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.references.FirNamedReference +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeContractDescriptionError +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.getContainingClass import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor +import org.jetbrains.kotlin.name.CallableId +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.ConstantValueKind +import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled class ConeEffectExtractor( private val session: FirSession, private val owner: FirContractDescriptionOwner, private val valueParameters: List -) : FirDefaultVisitor() { +) : FirDefaultVisitor() { companion object { private val BOOLEAN_AND = FirContractsDslNames.id("kotlin", "Boolean", "and") private val BOOLEAN_OR = FirContractsDslNames.id("kotlin", "Boolean", "or") private val BOOLEAN_NOT = FirContractsDslNames.id("kotlin", "Boolean", "not") } - override fun visitElement(element: FirElement, data: Nothing?): ConeContractDescriptionElement? { - return null + private fun ConeContractDescriptionError.asElement(): ConeErroneousContractElement { + return ConeErroneousContractElement(this) } - override fun visitReturnExpression(returnExpression: FirReturnExpression, data: Nothing?): ConeContractDescriptionElement? { + override fun visitElement(element: FirElement, data: Nothing?): ConeContractDescriptionElement { + return ConeContractDescriptionError.IllegalElement(element).asElement() + } + + override fun visitReturnExpression(returnExpression: FirReturnExpression, data: Nothing?): ConeContractDescriptionElement { return returnExpression.result.accept(this, data) } - override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?): ConeContractDescriptionElement? { - val resolvedId = functionCall.toResolvedCallableSymbol()?.callableId ?: return null + override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?): ConeContractDescriptionElement { + val resolvedId = functionCall.toResolvedCallableSymbol()?.callableId + ?: return ConeContractDescriptionError.UnresolvedCall(functionCall.calleeReference.name).asElement() + return when (resolvedId) { FirContractsDslNames.IMPLIES -> { - val effect = functionCall.explicitReceiver?.accept(this, null) as? ConeEffectDeclaration - ?: return null - val condition = functionCall.argument.accept(this, null) as? ConeBooleanExpression - ?: return null + val effect = functionCall.explicitReceiver?.asContractElement() as? ConeEffectDeclaration ?: noReceiver(resolvedId) + val condition = functionCall.argument.asContractElement() as? ConeBooleanExpression ?: noArgument(resolvedId) ConeConditionalEffectDeclaration(effect, condition) } @@ -52,8 +62,10 @@ class ConeEffectExtractor( val value = if (argument == null) { ConeConstantReference.WILDCARD } else { - argument.accept(this, null) as? ConeConstantReference - ?: return null + when (val value = argument.asContractElement()) { + is ConeConstantReference -> value + else -> ConeErroneousConstantReference(ConeContractDescriptionError.NotAConstant(value)) + } } ConeReturnsEffectDeclaration(value) } @@ -63,63 +75,80 @@ class ConeEffectExtractor( } FirContractsDslNames.CALLS_IN_PLACE -> { - val reference = functionCall.arguments[0].accept(this, null) as? ConeValueParameterReference - ?: return null - val kind = functionCall.arguments.getOrNull(1)?.parseInvocationKind() ?: EventOccurrencesRange.UNKNOWN - ConeCallsEffectDeclaration(reference, kind) + val reference = functionCall.arguments[0].asContractValueExpression() + when (val argument = functionCall.arguments.getOrNull(1)) { + null -> ConeCallsEffectDeclaration(reference, EventOccurrencesRange.UNKNOWN) + else -> when (val kind = argument.parseInvocationKind()) { + null -> ConeErroneousCallsEffectDeclaration(reference, ConeContractDescriptionError.UnresolvedInvocationKind(argument)) + else -> ConeCallsEffectDeclaration(reference, kind) + } + } } BOOLEAN_AND, BOOLEAN_OR -> { - val left = functionCall.explicitReceiver?.accept(this, null) as? ConeBooleanExpression ?: return null - val right = functionCall.argument.accept(this, null) as? ConeBooleanExpression ?: return null + val left = functionCall.explicitReceiver?.asContractBooleanExpression() ?: noReceiver(resolvedId) + val right = functionCall.arguments.firstOrNull()?.asContractBooleanExpression() ?: noArgument(resolvedId) val kind = when (resolvedId) { BOOLEAN_AND -> LogicOperationKind.AND BOOLEAN_OR -> LogicOperationKind.OR - else -> throw IllegalStateException() + else -> shouldNotBeCalled() } ConeBinaryLogicExpression(left, right, kind) } BOOLEAN_NOT -> { - val arg = functionCall.explicitReceiver?.accept(this, null) as? ConeBooleanExpression ?: return null + val arg = functionCall.explicitReceiver?.asContractBooleanExpression() ?: noReceiver(resolvedId) ConeLogicalNot(arg) } - else -> null + + else -> ConeContractDescriptionError.NotContractDsl(resolvedId).asElement() } } override fun visitBinaryLogicExpression( binaryLogicExpression: FirBinaryLogicExpression, data: Nothing? - ): ConeContractDescriptionElement? { - val left = binaryLogicExpression.leftOperand.accept(this, null) as? ConeBooleanExpression ?: return null - val right = binaryLogicExpression.rightOperand.accept(this, null) as? ConeBooleanExpression ?: return null + ): ConeContractDescriptionElement { + val left = binaryLogicExpression.leftOperand.asContractBooleanExpression() + val right = binaryLogicExpression.rightOperand.asContractBooleanExpression() return ConeBinaryLogicExpression(left, right, binaryLogicExpression.kind) } - override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: Nothing?): ConeContractDescriptionElement? { - val isNegated = when (equalityOperatorCall.operation) { + override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: Nothing?): ConeContractDescriptionElement { + val isNegated = when (val operation = equalityOperatorCall.operation) { FirOperation.EQ -> false FirOperation.NOT_EQ -> true - else -> return null + else -> return ConeContractDescriptionError.IllegalEqualityOperator(operation).asElement() } - val const = equalityOperatorCall.arguments[1] as? FirConstExpression<*> ?: return null - if (const.kind != ConstantValueKind.Null) return null - val arg = equalityOperatorCall.arguments[0].accept(this, null) as? ConeValueParameterReference ?: return null + + val argument = equalityOperatorCall.arguments[1] + val const = argument as? FirConstExpression<*> ?: return ConeContractDescriptionError.NotAConstant(argument).asElement() + if (const.kind != ConstantValueKind.Null) return ConeContractDescriptionError.IllegalConst(const, onlyNullAllowed = true).asElement() + + val arg = equalityOperatorCall.arguments[0].asContractValueExpression() return ConeIsNullPredicate(arg, isNegated) } - override fun visitSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: Nothing?): ConeContractDescriptionElement? { + override fun visitSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: Nothing?): ConeContractDescriptionElement { return smartCastExpression.originalExpression.accept(this, data) } override fun visitQualifiedAccessExpression( qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing? - ): ConeContractDescriptionElement? { - val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return null - val parameter = symbol.fir as? FirValueParameter ?: return null - val index = valueParameters.indexOf(parameter).takeUnless { it < 0 } ?: return null + ): ConeContractDescriptionElement { + val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() + ?: run { + val name = (qualifiedAccessExpression.calleeReference as? FirNamedReference)?.name ?: Name.special("unresolved") + return ConeContractDescriptionError.UnresolvedCall(name).asElement() + } + val parameter = symbol.fir as? FirValueParameter + ?: return ConeErroneousValueParameterReference( + ConeContractDescriptionError.IllegalParameter(symbol, "$symbol is not a value parameter") + ) + val index = valueParameters.indexOf(parameter).takeUnless { it < 0 } ?: return ConeErroneousValueParameterReference( + ConeContractDescriptionError.IllegalParameter(symbol, "Value paramter $symbol is not found in parameters of outer function") + ) val type = parameter.returnTypeRef.coneType val name = parameter.name.asString() @@ -129,7 +158,7 @@ class ConeEffectExtractor( override fun visitPropertyAccessExpression( propertyAccessExpression: FirPropertyAccessExpression, data: Nothing? - ): ConeContractDescriptionElement? { + ): ConeContractDescriptionElement { return visitQualifiedAccessExpression(propertyAccessExpression, data) } @@ -152,8 +181,9 @@ class ConeEffectExtractor( override fun visitThisReceiverExpression( thisReceiverExpression: FirThisReceiverExpression, data: Nothing? - ): ConeContractDescriptionElement? { - val declaration = thisReceiverExpression.calleeReference.boundSymbol?.fir ?: return null + ): ConeContractDescriptionElement { + val declaration = thisReceiverExpression.calleeReference.boundSymbol?.fir + ?: return ConeContractDescriptionError.UnresolvedThis(thisReceiverExpression).asElement() val callableOwner = owner as? FirCallableDeclaration val ownerHasReceiver = callableOwner?.receiverParameter != null val ownerIsMemberOfDeclaration = callableOwner?.getContainingClass(session) == declaration @@ -161,24 +191,24 @@ class ConeEffectExtractor( val type = thisReceiverExpression.typeRef.coneType toValueParameterReference(type, -1, "this") } else { - null + ConeContractDescriptionError.IllegalThis(thisReceiverExpression).asElement() } } - override fun visitConstExpression(constExpression: FirConstExpression, data: Nothing?): ConeContractDescriptionElement? { + override fun visitConstExpression(constExpression: FirConstExpression, data: Nothing?): ConeContractDescriptionElement { return when (constExpression.kind) { ConstantValueKind.Null -> ConeConstantReference.NULL ConstantValueKind.Boolean -> when (constExpression.value as Boolean) { true -> ConeBooleanConstantReference.TRUE false -> ConeBooleanConstantReference.FALSE } - else -> null + else -> ConeContractDescriptionError.IllegalConst(constExpression, onlyNullAllowed = false).asElement() } } - override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: Nothing?): ConeContractDescriptionElement? { - val arg = typeOperatorCall.argument.accept(this, data) as? ConeValueParameterReference ?: return null - val type = typeOperatorCall.conversionTypeRef.coneType + override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: Nothing?): ConeContractDescriptionElement { + val arg = typeOperatorCall.argument.asContractValueExpression() + val type = typeOperatorCall.conversionTypeRef.coneType.fullyExpandedType(session) val isNegated = typeOperatorCall.operation == FirOperation.NOT_IS return ConeIsInstancePredicate(arg, type, isNegated) } @@ -194,4 +224,30 @@ class ConeEffectExtractor( else -> null } } + + private fun noReceiver(callableId: CallableId): ConeErroneousContractElement { + return ConeContractDescriptionError.NoReceiver(callableId.callableName).asElement() + } + + private fun noArgument(callableId: CallableId): ConeErroneousContractElement { + return ConeContractDescriptionError.NoArgument(callableId.callableName).asElement() + } + + private fun FirElement.asContractElement(): ConeContractDescriptionElement { + return accept(this@ConeEffectExtractor, null) + } + + private fun FirExpression.asContractBooleanExpression(): ConeBooleanExpression { + return when (val element = asContractElement()) { + is ConeBooleanExpression -> element + else -> ConeContractDescriptionError.NotABooleanExpression(element).asElement() + } + } + + private fun FirExpression.asContractValueExpression(): ConeValueParameterReference { + return when (val element = asContractElement()) { + is ConeValueParameterReference -> element + else -> ConeErroneousValueParameterReference(ConeContractDescriptionError.NotAParameterReference(element)) + } + } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt index 58864c97531..8d98af3956b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt @@ -5,15 +5,15 @@ package org.jetbrains.kotlin.fir.resolve.transformers.contracts +import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription import org.jetbrains.kotlin.fir.contracts.FirRawContractDescription import org.jetbrains.kotlin.fir.contracts.builder.buildLegacyRawContractDescription import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration -import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription -import org.jetbrains.kotlin.fir.contracts.toFirEffectDeclaration +import org.jetbrains.kotlin.fir.contracts.toFirElement import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter @@ -179,11 +179,13 @@ abstract class FirAbstractContractResolveTransformerDispatcher( val resolvedContractDescription = buildResolvedContractDescription { val effectExtractor = ConeEffectExtractor(session, owner, valueParameters) for (statement in lambdaBody.statements) { - val effect = statement.accept(effectExtractor, null) as? ConeEffectDeclaration - if (effect == null) { - unresolvedEffects += ConeUnresolvedEffect(statement) - } else { - effects += effect.toFirEffectDeclaration(statement.source) + if (statement.source?.kind is KtFakeSourceElementKind.ImplicitReturn) continue + when (val effect = statement.accept(effectExtractor, null)) { + is ConeEffectDeclaration -> when (effect.erroneous) { + false -> effects += effect.toFirElement(statement.source) + true -> unresolvedEffects += effect.toFirElement(statement.source) + } + else -> unresolvedEffects += effect.toFirElement(statement.source) } } this.source = contractDescription.source diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt index e40f01603ec..42cc24e8b7d 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt @@ -7,9 +7,14 @@ package org.jetbrains.kotlin.fir.resolve.diagnostics import kotlinx.collections.immutable.ImmutableList import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnosticWithSource +import org.jetbrains.kotlin.fir.expressions.FirConstExpression +import org.jetbrains.kotlin.fir.expressions.FirOperation +import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.calls.AbstractCandidate import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -17,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirQualifierPart import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability @@ -138,7 +144,83 @@ object ConeVariableExpectedError : ConeDiagnostic { override val reason: String get() = "Variable expected" } -class ConeContractDescriptionError(override val reason: String) : ConeDiagnostic +sealed class ConeContractDescriptionError : ConeDiagnostic { + class IllegalElement(val element: FirElement) : ConeContractDescriptionError() { + override val reason: String + get() = "Illegal element in contract description" + } + + class UnresolvedCall(val name: Name) : ConeContractDescriptionError() { + override val reason: String + get() = "Unresolved call in contract description: ${name.asString()}" + } + + class NoReceiver(val name: Name) : ConeContractDescriptionError() { + override val reason: String + get() = "No receiver for call ${name.asString()} found" + } + + class NoArgument(val name: Name) : ConeContractDescriptionError() { + override val reason: String + get() = "No argument for call ${name.asString()} found" + } + + class NotAConstant(val element: Any) : ConeContractDescriptionError() { + override val reason: String + get() = "$element is not a constant reference" + } + + class IllegalConst( + val element: FirConstExpression<*>, + val onlyNullAllowed: Boolean + ) : ConeContractDescriptionError() { + override val reason: String + get() = buildString { + append(element.render()) + append("is not a null") + if (!onlyNullAllowed) { + append(", true or false") + } + } + } + + class NotAParameterReference(val element: ConeContractDescriptionElement) : ConeContractDescriptionError() { + override val reason: String + get() = "$element is not a parameter or receiver reference" + } + + class IllegalParameter(val symbol: FirCallableSymbol<*>, override val reason: String) : ConeContractDescriptionError() + + class UnresolvedThis(val expression: FirThisReceiverExpression) : ConeContractDescriptionError() { + override val reason: String + get() = "Can't resolve this reference" + } + + class IllegalThis(val expression: FirThisReceiverExpression) : ConeContractDescriptionError() { + override val reason: String + get() = "Only this reference to extension receiver of a function is allowed" + } + + class UnresolvedInvocationKind(val element: FirElement) : ConeContractDescriptionError() { + override val reason: String + get() = "${element.render()} is not a valid invocation kind" + } + + class NotABooleanExpression(val element: ConeContractDescriptionElement) : ConeContractDescriptionError() { + override val reason: String + get() = "$element is not a boolean expression" + } + + class NotContractDsl(val callableId: CallableId) : ConeContractDescriptionError() { + override val reason: String + get() = "$callableId is not a part of contracts DSL" + } + + class IllegalEqualityOperator(val operation: FirOperation) : ConeContractDescriptionError() { + override val reason: String + get() = "$operation operator call is illegal in contract description" + } +} class ConeIllegalAnnotationError(val name: Name) : ConeDiagnostic { override val reason: String get() = "Not a legal annotation: $name" diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirContractElementDeclaration.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirContractElementDeclaration.kt new file mode 100644 index 00000000000..d2bae69fa31 --- /dev/null +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirContractElementDeclaration.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.contracts + +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirPureAbstractElement +import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement +import org.jetbrains.kotlin.fir.visitors.* + +/* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + +abstract class FirContractElementDeclaration : FirPureAbstractElement(), FirElement { + abstract override val source: KtSourceElement? + abstract val effect: ConeContractDescriptionElement + + override fun accept(visitor: FirVisitor, data: D): R = visitor.visitContractElementDeclaration(this, data) + + @Suppress("UNCHECKED_CAST") + override fun transform(transformer: FirTransformer, data: D): E = + transformer.transformContractElementDeclaration(this, data) as E +} diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirEffectDeclaration.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirEffectDeclaration.kt index 6d50928823d..7aa74176798 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirEffectDeclaration.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirEffectDeclaration.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.contracts import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirPureAbstractElement import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration import org.jetbrains.kotlin.fir.visitors.* @@ -16,9 +15,9 @@ import org.jetbrains.kotlin.fir.visitors.* * DO NOT MODIFY IT MANUALLY */ -abstract class FirEffectDeclaration : FirPureAbstractElement(), FirElement { +abstract class FirEffectDeclaration : FirContractElementDeclaration() { abstract override val source: KtSourceElement? - abstract val effect: ConeEffectDeclaration + abstract override val effect: ConeEffectDeclaration override fun accept(visitor: FirVisitor, data: D): R = visitor.visitEffectDeclaration(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt index 8d980642bee..2e7a6bfa547 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.contracts import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect import org.jetbrains.kotlin.fir.visitors.* /* @@ -18,7 +17,7 @@ import org.jetbrains.kotlin.fir.visitors.* abstract class FirResolvedContractDescription : FirContractDescription() { abstract override val source: KtSourceElement? abstract val effects: List - abstract val unresolvedEffects: List + abstract val unresolvedEffects: List override fun accept(visitor: FirVisitor, data: D): R = visitor.visitResolvedContractDescription(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirContractElementDeclarationBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirContractElementDeclarationBuilder.kt new file mode 100644 index 00000000000..d748307c598 --- /dev/null +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirContractElementDeclarationBuilder.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("DuplicatedCode") + +package org.jetbrains.kotlin.fir.contracts.builder + +import kotlin.contracts.* +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fir.builder.FirBuilderDsl +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration +import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement +import org.jetbrains.kotlin.fir.contracts.impl.FirContractElementDeclarationImpl +import org.jetbrains.kotlin.fir.visitors.* + +/* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + +@FirBuilderDsl +class FirContractElementDeclarationBuilder { + var source: KtSourceElement? = null + lateinit var effect: ConeContractDescriptionElement + + fun build(): FirContractElementDeclaration { + return FirContractElementDeclarationImpl( + source, + effect, + ) + } + +} + +@OptIn(ExperimentalContracts::class) +inline fun buildContractElementDeclaration(init: FirContractElementDeclarationBuilder.() -> Unit): FirContractElementDeclaration { + contract { + callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE) + } + return FirContractElementDeclarationBuilder().apply(init).build() +} diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt index 8a7e04a4ef0..fc4b46d9dab 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt @@ -10,9 +10,9 @@ package org.jetbrains.kotlin.fir.contracts.builder import kotlin.contracts.* import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.builder.FirBuilderDsl +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription -import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect import org.jetbrains.kotlin.fir.contracts.impl.FirResolvedContractDescriptionImpl import org.jetbrains.kotlin.fir.visitors.* @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.fir.visitors.* class FirResolvedContractDescriptionBuilder { var source: KtSourceElement? = null val effects: MutableList = mutableListOf() - val unresolvedEffects: MutableList = mutableListOf() + val unresolvedEffects: MutableList = mutableListOf() fun build(): FirResolvedContractDescription { return FirResolvedContractDescriptionImpl( diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirContractElementDeclarationImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirContractElementDeclarationImpl.kt new file mode 100644 index 00000000000..d8fc82aa8fe --- /dev/null +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirContractElementDeclarationImpl.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("DuplicatedCode") + +package org.jetbrains.kotlin.fir.contracts.impl + +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration +import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement +import org.jetbrains.kotlin.fir.visitors.* + +/* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + +internal class FirContractElementDeclarationImpl( + override val source: KtSourceElement?, + override val effect: ConeContractDescriptionElement, +) : FirContractElementDeclaration() { + override fun acceptChildren(visitor: FirVisitor, data: D) {} + + override fun transformChildren(transformer: FirTransformer, data: D): FirContractElementDeclarationImpl { + return this + } +} diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt index 3d92b090a45..918f0ff7f50 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt @@ -8,9 +8,9 @@ package org.jetbrains.kotlin.fir.contracts.impl import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription -import org.jetbrains.kotlin.fir.contracts.description.ConeUnresolvedEffect import org.jetbrains.kotlin.fir.visitors.* /* @@ -21,14 +21,16 @@ import org.jetbrains.kotlin.fir.visitors.* internal class FirResolvedContractDescriptionImpl( override val source: KtSourceElement?, override val effects: MutableList, - override val unresolvedEffects: MutableList, + override val unresolvedEffects: MutableList, ) : FirResolvedContractDescription() { override fun acceptChildren(visitor: FirVisitor, data: D) { effects.forEach { it.accept(visitor, data) } + unresolvedEffects.forEach { it.accept(visitor, data) } } override fun transformChildren(transformer: FirTransformer, data: D): FirResolvedContractDescriptionImpl { effects.transformInplace(transformer, data) + unresolvedEffects.transformInplace(transformer, data) return this } } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt index ed0e994d019..f1f7fa8d6a1 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitor.kt @@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription @@ -314,6 +315,8 @@ abstract class FirDefaultVisitor : FirVisitor() { override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: D): R = visitTypeRef(implicitTypeRef, data) + override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): R = visitContractElementDeclaration(effectDeclaration, data) + override fun visitLegacyRawContractDescription(legacyRawContractDescription: FirLegacyRawContractDescription, data: D): R = visitContractDescription(legacyRawContractDescription, data) override fun visitRawContractDescription(rawContractDescription: FirRawContractDescription, data: D): R = visitContractDescription(rawContractDescription, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt index 8e49efc8ccf..215d987d6c5 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirDefaultVisitorVoid.kt @@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription @@ -314,6 +315,8 @@ abstract class FirDefaultVisitorVoid : FirVisitorVoid() { override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef) = visitTypeRef(implicitTypeRef) + override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration) = visitContractElementDeclaration(effectDeclaration) + override fun visitLegacyRawContractDescription(legacyRawContractDescription: FirLegacyRawContractDescription) = visitContractDescription(legacyRawContractDescription) override fun visitRawContractDescription(rawContractDescription: FirRawContractDescription) = visitContractDescription(rawContractDescription) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt index baf15987389..8bd4e9bf562 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt @@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription @@ -731,7 +732,11 @@ abstract class FirTransformer : FirVisitor() { return transformElement(implicitTypeRef, data) } - open fun transformEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirEffectDeclaration { + open fun transformContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: D): FirContractElementDeclaration { + return transformElement(contractElementDeclaration, data) + } + + open fun transformEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirContractElementDeclaration { return transformElement(effectDeclaration, data) } @@ -1323,7 +1328,11 @@ abstract class FirTransformer : FirVisitor() { return transformImplicitTypeRef(implicitTypeRef, data) } - final override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirEffectDeclaration { + final override fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: D): FirContractElementDeclaration { + return transformContractElementDeclaration(contractElementDeclaration, data) + } + + final override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): FirContractElementDeclaration { return transformEffectDeclaration(effectDeclaration, data) } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt index 2a6930425ad..0b89adcd31e 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt @@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription @@ -446,6 +447,8 @@ abstract class FirVisitor { open fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: D): R = visitElement(implicitTypeRef, data) + open fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: D): R = visitElement(contractElementDeclaration, data) + open fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: D): R = visitElement(effectDeclaration, data) open fun visitContractDescription(contractDescription: FirContractDescription, data: D): R = visitElement(contractDescription, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt index 4dfa8b8aea3..96b5253b745 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt @@ -148,6 +148,7 @@ import org.jetbrains.kotlin.fir.types.FirDynamicTypeRef import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef import org.jetbrains.kotlin.fir.types.FirIntersectionTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription @@ -730,6 +731,10 @@ abstract class FirVisitorVoid : FirVisitor() { visitElement(implicitTypeRef) } + open fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration) { + visitElement(contractElementDeclaration) + } + open fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration) { visitElement(effectDeclaration) } @@ -1322,6 +1327,10 @@ abstract class FirVisitorVoid : FirVisitor() { visitImplicitTypeRef(implicitTypeRef) } + final override fun visitContractElementDeclaration(contractElementDeclaration: FirContractElementDeclaration, data: Nothing?) { + visitContractElementDeclaration(contractElementDeclaration) + } + final override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration, data: Nothing?) { visitEffectDeclaration(effectDeclaration) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/ContractUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/ContractUtils.kt index b9cd2f87776..61377c05563 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/ContractUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/ContractUtils.kt @@ -6,16 +6,27 @@ package org.jetbrains.kotlin.fir.contracts import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fir.contracts.builder.buildContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.builder.buildEffectDeclaration +import org.jetbrains.kotlin.fir.contracts.description.ConeContractDescriptionElement import org.jetbrains.kotlin.fir.contracts.description.ConeEffectDeclaration val FirContractDescription.effects: List? get() = (this as? FirResolvedContractDescription)?.effects -fun ConeEffectDeclaration.toFirEffectDeclaration(source: KtSourceElement? = null): FirEffectDeclaration = +fun ConeEffectDeclaration.toFirElement(source: KtSourceElement? = null): FirEffectDeclaration = buildEffectDeclaration { if (source != null) { this.source = source } - effect = this@toFirEffectDeclaration + effect = this@toFirElement + } + + +fun ConeContractDescriptionElement.toFirElement(source: KtSourceElement? = null): FirContractElementDeclaration = + buildContractElementDeclaration { + if (source != null) { + this.source = source + } + effect = this@toFirElement } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescription.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescription.kt index 7769571aa34..8039baa25f7 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescription.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescription.kt @@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.contracts.description interface ConeContractDescriptionElement { fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R + + val erroneous: Boolean } abstract class ConeEffectDeclaration : ConeContractDescriptionElement { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescriptionVisitor.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescriptionVisitor.kt index a750448afbd..3cf27f4e0f8 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescriptionVisitor.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeContractDescriptionVisitor.kt @@ -23,6 +23,9 @@ abstract class ConeContractDescriptionVisitor { open fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: D): R = visitEffectDeclaration(callsEffect, data) + open fun visitErroneousCallsEffectDeclaration(callsEffect: ConeErroneousCallsEffectDeclaration, data: D): R = + visitCallsEffectDeclaration(callsEffect, data) + // Expressions open fun visitBooleanExpression(booleanExpression: ConeBooleanExpression, data: D): R = visitContractDescriptionElement(booleanExpression, data) @@ -35,6 +38,9 @@ abstract class ConeContractDescriptionVisitor { open fun visitIsInstancePredicate(isInstancePredicate: ConeIsInstancePredicate, data: D): R = visitBooleanExpression(isInstancePredicate, data) + open fun visitErroneousIsInstancePredicate(isInstancePredicate: ConeErroneousIsInstancePredicate, data: D): R = + visitIsInstancePredicate(isInstancePredicate, data) + open fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: D): R = visitBooleanExpression(isNullPredicate, data) // Values @@ -45,9 +51,19 @@ abstract class ConeContractDescriptionVisitor { open fun visitBooleanConstantDescriptor(booleanConstantDescriptor: ConeBooleanConstantReference, data: D): R = visitConstantDescriptor(booleanConstantDescriptor, data) + open fun visitErroneousConstantReference(erroneousConstantReference: ConeErroneousConstantReference, data: D): R = + visitConstantDescriptor(erroneousConstantReference, data) + open fun visitValueParameterReference(valueParameterReference: ConeValueParameterReference, data: D): R = visitValue(valueParameterReference, data) open fun visitBooleanValueParameterReference(booleanValueParameterReference: ConeBooleanValueParameterReference, data: D): R = visitValueParameterReference(booleanValueParameterReference, data) -} \ No newline at end of file + + open fun visitErroneousValueParameterReference(valueParameterReference: ConeErroneousValueParameterReference, data: D): R = + visitValueParameterReference(valueParameterReference, data) + + // Error + open fun visitErroneousElement(element: ConeErroneousContractElement, data: D): R = + visitContractDescriptionElement(element, data) +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeEffects.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeEffects.kt index 69d6173c075..41317c93ab9 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeEffects.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeEffects.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.contracts.description import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic /** * Effect with condition attached to it. @@ -22,6 +23,9 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange * - if [condition] is true, we *can't* reason that [effect] will be observed. */ class ConeConditionalEffectDeclaration(val effect: ConeEffectDeclaration, val condition: ConeBooleanExpression) : ConeEffectDeclaration() { + override val erroneous: Boolean + get() = effect.erroneous || condition.erroneous + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitConditionalEffectDeclaration(this, data) } @@ -31,9 +35,11 @@ class ConeConditionalEffectDeclaration(val effect: ConeEffectDeclaration, val co * Effect which specifies that subroutine returns some particular value */ class ConeReturnsEffectDeclaration(val value: ConeConstantReference) : ConeEffectDeclaration() { + override val erroneous: Boolean + get() = value.erroneous + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitReturnsEffectDeclaration(this, data) - } @@ -41,7 +47,24 @@ class ConeReturnsEffectDeclaration(val value: ConeConstantReference) : ConeEffec * Effect which specifies, that during execution of subroutine, callable [valueParameterReference] will be invoked * [kind] amount of times, and will never be invoked after subroutine call is finished. */ -class ConeCallsEffectDeclaration(val valueParameterReference: ConeValueParameterReference, val kind: EventOccurrencesRange) : ConeEffectDeclaration() { +open class ConeCallsEffectDeclaration( + val valueParameterReference: ConeValueParameterReference, + val kind: EventOccurrencesRange +) : ConeEffectDeclaration() { + override val erroneous: Boolean + get() = valueParameterReference.erroneous + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitCallsEffectDeclaration(this, data) -} \ No newline at end of file +} + +class ConeErroneousCallsEffectDeclaration( + valueParameterReference: ConeValueParameterReference, + val diagnostic: ConeDiagnostic +) : ConeCallsEffectDeclaration(valueParameterReference, EventOccurrencesRange.UNKNOWN) { + override val erroneous: Boolean + get() = true + + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = + contractDescriptionVisitor.visitErroneousCallsEffectDeclaration(this, data) +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeErroneousContractElement.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeErroneousContractElement.kt new file mode 100644 index 00000000000..f207f588a62 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeErroneousContractElement.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.contracts.description + +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic + +class ConeErroneousContractElement( + val diagnostic: ConeDiagnostic +) : ConeEffectDeclaration(), ConeBooleanExpression, ConeContractDescriptionValue { + override val erroneous: Boolean + get() = true + + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R { + return contractDescriptionVisitor.visitErroneousElement(this, data) + } +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeLogicalCombinators.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeLogicalCombinators.kt index 24b9defb411..17ff4cd86a2 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeLogicalCombinators.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeLogicalCombinators.kt @@ -8,12 +8,18 @@ package org.jetbrains.kotlin.fir.contracts.description import org.jetbrains.kotlin.fir.expressions.LogicOperationKind class ConeBinaryLogicExpression(val left: ConeBooleanExpression, val right: ConeBooleanExpression, val kind: LogicOperationKind) : ConeBooleanExpression { + override val erroneous: Boolean + get() = left.erroneous || right.erroneous + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R { return contractDescriptionVisitor.visitLogicalBinaryOperationContractExpression(this, data) } } class ConeLogicalNot(val arg: ConeBooleanExpression) : ConeBooleanExpression { + override val erroneous: Boolean + get() = arg.erroneous + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitLogicalNot(this, data) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConePredicates.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConePredicates.kt index f334afa3d49..c3875109d3b 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConePredicates.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConePredicates.kt @@ -5,9 +5,13 @@ package org.jetbrains.kotlin.fir.contracts.description +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.types.ConeKotlinType -class ConeIsInstancePredicate(val arg: ConeValueParameterReference, val type: ConeKotlinType, val isNegated: Boolean) : ConeBooleanExpression { +open class ConeIsInstancePredicate(val arg: ConeValueParameterReference, val type: ConeKotlinType, val isNegated: Boolean) : ConeBooleanExpression { + override val erroneous: Boolean + get() = arg.erroneous + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitIsInstancePredicate(this, data) @@ -15,10 +19,26 @@ class ConeIsInstancePredicate(val arg: ConeValueParameterReference, val type: Co ConeIsInstancePredicate(arg, type, isNegated.not()) } +class ConeErroneousIsInstancePredicate( + arg: ConeValueParameterReference, + type: ConeKotlinType, + isNegated: Boolean, + val diagnostic: ConeDiagnostic +) : ConeIsInstancePredicate(arg, type, isNegated) { + override val erroneous: Boolean + get() = true + + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = + contractDescriptionVisitor.visitErroneousIsInstancePredicate(this, data) +} + class ConeIsNullPredicate(val arg: ConeValueParameterReference, val isNegated: Boolean) : ConeBooleanExpression { + override val erroneous: Boolean + get() = arg.erroneous + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitIsNullPredicate(this, data) fun negated(): ConeIsNullPredicate = ConeIsNullPredicate(arg, isNegated.not()) -} \ No newline at end of file +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeUnresolvedEffect.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeUnresolvedEffect.kt deleted file mode 100644 index 14a037a0d2e..00000000000 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeUnresolvedEffect.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.fir.contracts.description - -import org.jetbrains.kotlin.fir.expressions.FirStatement - -class ConeUnresolvedEffect(val statement: FirStatement) \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt index 555332db0a0..b2876ebf66f 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/contracts/description/ConeValues.kt @@ -5,12 +5,17 @@ package org.jetbrains.kotlin.fir.contracts.description +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic + interface ConeContractDescriptionValue : ConeContractDescriptionElement { override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitValue(this, data) } open class ConeConstantReference protected constructor(val name: String) : ConeContractDescriptionValue { + override val erroneous: Boolean + get() = false + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitConstantDescriptor(this, data) @@ -31,6 +36,14 @@ class ConeBooleanConstantReference private constructor(name: String) : ConeConst } } +class ConeErroneousConstantReference(val diagnostic: ConeDiagnostic) : ConeConstantReference("ERROR") { + override val erroneous: Boolean + get() = true + + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = + contractDescriptionVisitor.visitErroneousConstantReference(this, data) +} + /* * Index of value parameter of function * -1 means that it is reference to extension receiver @@ -40,6 +53,9 @@ open class ConeValueParameterReference(val parameterIndex: Int, val name: String assert(parameterIndex >= -1) } + override val erroneous: Boolean + get() = false + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitValueParameterReference(this, data) } @@ -47,4 +63,12 @@ open class ConeValueParameterReference(val parameterIndex: Int, val name: String class ConeBooleanValueParameterReference(parameterIndex: Int, name: String) : ConeValueParameterReference(parameterIndex, name), ConeBooleanExpression { override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = contractDescriptionVisitor.visitBooleanValueParameterReference(this, data) -} \ No newline at end of file +} + +class ConeErroneousValueParameterReference(val diagnostic: ConeDiagnostic) : ConeValueParameterReference(Int.MAX_VALUE, "ERROR") { + override val erroneous: Boolean + get() = true + + override fun accept(contractDescriptionVisitor: ConeContractDescriptionVisitor, data: D): R = + contractDescriptionVisitor.visitErroneousValueParameterReference(this, data) +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt index acc903087f5..55b013b831e 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt @@ -180,7 +180,8 @@ object FirTreeBuilder : AbstractFirTreeBuilder() { val intersectionTypeRef by element(TypeRef, typeRefWithNullability) val implicitTypeRef by element(TypeRef, typeRef) - val effectDeclaration by element(Contracts) + val contractElementDeclaration by element(Contracts) + val effectDeclaration by element(Contracts, contractElementDeclaration) val contractDescription by element(Contracts) val legacyRawContractDescription by element(Contracts, contractDescription) diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt index c3ddf3472d9..b1637497821 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt @@ -562,6 +562,8 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() noImpl(argumentList) noImpl(annotationArgumentMapping) + impl(contractElementDeclaration) + val implementationsWithoutStatusAndTypeParameters = listOf( "FirAnonymousFunctionImpl", "FirValueParameterImpl", diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index 189731f4e08..d3d382e7567 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -732,6 +732,10 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild +field(varianceType) } + contractElementDeclaration.configure { + +field("effect", coneContractElementType) + } + effectDeclaration.configure { +field("effect", coneEffectDeclarationType) } @@ -742,7 +746,7 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild resolvedContractDescription.configure { +fieldList("effects", effectDeclaration) - +fieldList("unresolvedEffects", coneUnresolvedEffect) + +fieldList("unresolvedEffects", contractElementDeclaration) } legacyRawContractDescription.configure { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt index b2101dfdd13..f21d4051a80 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt @@ -79,11 +79,11 @@ val emptyArgumentListType = type("fir.expressions", "FirEmptyArgumentList") val firScopeProviderType = type("fir.scopes", "FirScopeProvider") val pureAbstractElementType = generatedType("FirPureAbstractElement") +val coneContractElementType = type("fir.contracts.description", "ConeContractDescriptionElement") val coneEffectDeclarationType = type("fir.contracts.description", "ConeEffectDeclaration") val emptyContractDescriptionType = generatedType("contracts.impl", "FirEmptyContractDescription") val coneDiagnosticType = generatedType("diagnostics", "ConeDiagnostic") val coneStubDiagnosticType = generatedType("diagnostics", "ConeStubDiagnostic") -val coneUnresolvedEffect = type("fir.contracts.description", "ConeUnresolvedEffect") val dslBuilderAnnotationType = generatedType("builder", "FirBuilderDsl") val firImplementationDetailType = generatedType("FirImplementationDetail") diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/emptyContract.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/emptyContract.fir.kt index 569b76f3df4..2fcdedab5e7 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/emptyContract.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/emptyContract.fir.kt @@ -5,5 +5,5 @@ import kotlin.contracts.* fun emptyContract() { - contract { } -} \ No newline at end of file + contract { } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/illegalConstructionInContractBlock.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/illegalConstructionInContractBlock.fir.kt index 0074c9de75a..3d144aab7bf 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/illegalConstructionInContractBlock.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/illegalConstructionInContractBlock.fir.kt @@ -25,9 +25,9 @@ fun whenInContract(x: Any?, boolean: Boolean) { fun forInContract(x: Any?) { contract { - for (i in 0..1) { + for (i in 0..1) { returns() implies (x is String) - } + } } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/8.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/8.fir.kt index d43e7a3937f..6dca0c96728 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/8.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/8.fir.kt @@ -5,7 +5,7 @@ import kotlin.contracts.* // TESTCASE NUMBER: 1 inline fun case_1(block: () -> Unit) { - contract { } + contract { } return block() } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/effects/callsInPlace/neg/1.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/effects/callsInPlace/neg/1.fir.kt index 35ae5d1f018..1dea6936ddc 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/effects/callsInPlace/neg/1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/effects/callsInPlace/neg/1.fir.kt @@ -11,24 +11,24 @@ object SampleObject { // TESTCASE NUMBER: 1 inline fun case_1(invocationKind: InvocationKind, block: () -> Unit) { - contract { callsInPlace(block, invocationKind) } + contract { callsInPlace(block, invocationKind) } return block() } // TESTCASE NUMBER: 2 inline fun case_2(invocationKind: T, block: () -> Unit) { - contract { callsInPlace(block, invocationKind) } + contract { callsInPlace(block, invocationKind) } return block() } // TESTCASE NUMBER: 3 inline fun case_3(block: () -> Unit) { - contract { callsInPlace(block, invocationKind) } + contract { callsInPlace(block, invocationKind) } return block() } // TESTCASE NUMBER: 4 inline fun case_4(block: () -> Unit) { - contract { callsInPlace(block, SampleObject.invocationKind) } + contract { callsInPlace(block, SampleObject.invocationKind) } return block() }