[cls] write contracts information to cls stubs
^ KTIJ-24665 this information would be used to create resolved FirElements from stubs, so no ProtoBuf would be kept in memory
This commit is contained in:
+15
-12
@@ -12,10 +12,13 @@ import org.jetbrains.kotlin.analysis.api.contracts.description.booleans.*
|
|||||||
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
|
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFunctionSymbol
|
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFunctionSymbol
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.KtParameterSymbol
|
import org.jetbrains.kotlin.analysis.api.symbols.KtParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
|
||||||
internal fun ConeEffectDeclaration.coneEffectDeclarationToAnalysisApi(
|
internal fun KtEffectDeclaration<ConeKotlinType, ConeDiagnostic>.coneEffectDeclarationToAnalysisApi(
|
||||||
builder: KtSymbolByFirBuilder,
|
builder: KtSymbolByFirBuilder,
|
||||||
firFunctionSymbol: KtFirFunctionSymbol
|
firFunctionSymbol: KtFirFunctionSymbol
|
||||||
): KtContractEffectDeclaration =
|
): KtContractEffectDeclaration =
|
||||||
@@ -24,7 +27,7 @@ internal fun ConeEffectDeclaration.coneEffectDeclarationToAnalysisApi(
|
|||||||
private class ConeContractDescriptionElementToAnalysisApi(
|
private class ConeContractDescriptionElementToAnalysisApi(
|
||||||
private val builder: KtSymbolByFirBuilder,
|
private val builder: KtSymbolByFirBuilder,
|
||||||
private val firFunctionSymbol: KtFirFunctionSymbol
|
private val firFunctionSymbol: KtFirFunctionSymbol
|
||||||
) : ConeContractDescriptionVisitor<Any, Unit>() {
|
) : KtContractDescriptionVisitor<Any, Unit, ConeKotlinType, ConeDiagnostic>() {
|
||||||
|
|
||||||
override fun visitConditionalEffectDeclaration(
|
override fun visitConditionalEffectDeclaration(
|
||||||
conditionalEffect: ConeConditionalEffectDeclaration,
|
conditionalEffect: ConeConditionalEffectDeclaration,
|
||||||
@@ -39,15 +42,15 @@ private class ConeContractDescriptionElementToAnalysisApi(
|
|||||||
data: Unit
|
data: Unit
|
||||||
): KtContractReturnsContractEffectDeclaration =
|
): KtContractReturnsContractEffectDeclaration =
|
||||||
when (val value = returnsEffect.value) {
|
when (val value = returnsEffect.value) {
|
||||||
ConeConstantReference.NULL ->
|
ConeContractConstantValues.NULL ->
|
||||||
KtContractReturnsSpecificValueEffectDeclaration(KtContractConstantValue(KtContractConstantType.NULL, builder.token))
|
KtContractReturnsSpecificValueEffectDeclaration(KtContractConstantValue(KtContractConstantType.NULL, builder.token))
|
||||||
ConeConstantReference.NOT_NULL -> KtContractReturnsNotNullEffectDeclaration(builder.token)
|
ConeContractConstantValues.NOT_NULL -> KtContractReturnsNotNullEffectDeclaration(builder.token)
|
||||||
ConeConstantReference.WILDCARD -> KtContractReturnsSuccessfullyEffectDeclaration(builder.token)
|
ConeContractConstantValues.WILDCARD -> KtContractReturnsSuccessfullyEffectDeclaration(builder.token)
|
||||||
is ConeBooleanConstantReference -> KtContractReturnsSpecificValueEffectDeclaration(
|
is KtBooleanConstantReference -> KtContractReturnsSpecificValueEffectDeclaration(
|
||||||
KtContractConstantValue(
|
KtContractConstantValue(
|
||||||
when (value) {
|
when (value) {
|
||||||
ConeBooleanConstantReference.TRUE -> KtContractConstantType.TRUE
|
ConeContractConstantValues.TRUE -> KtContractConstantType.TRUE
|
||||||
ConeBooleanConstantReference.FALSE -> KtContractConstantType.FALSE
|
ConeContractConstantValues.FALSE -> KtContractConstantType.FALSE
|
||||||
else -> error("Can't convert $value to the Analysis API")
|
else -> error("Can't convert $value to the Analysis API")
|
||||||
},
|
},
|
||||||
builder.token
|
builder.token
|
||||||
@@ -56,7 +59,7 @@ private class ConeContractDescriptionElementToAnalysisApi(
|
|||||||
else -> error("Can't convert $returnsEffect to the Analysis API")
|
else -> error("Can't convert $returnsEffect to the Analysis API")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: Unit): KtContractCallsInPlaceContractEffectDeclaration =
|
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<ConeKotlinType, ConeDiagnostic>, data: Unit): KtContractCallsInPlaceContractEffectDeclaration =
|
||||||
KtContractCallsInPlaceContractEffectDeclaration(
|
KtContractCallsInPlaceContractEffectDeclaration(
|
||||||
callsEffect.valueParameterReference.accept(),
|
callsEffect.valueParameterReference.accept(),
|
||||||
callsEffect.kind
|
callsEffect.kind
|
||||||
@@ -92,8 +95,8 @@ private class ConeContractDescriptionElementToAnalysisApi(
|
|||||||
data: Unit
|
data: Unit
|
||||||
): KtContractBooleanConstantExpression =
|
): KtContractBooleanConstantExpression =
|
||||||
when (booleanConstantDescriptor) {
|
when (booleanConstantDescriptor) {
|
||||||
ConeBooleanConstantReference.TRUE -> KtContractBooleanConstantExpression(true, builder.token)
|
ConeContractConstantValues.TRUE -> KtContractBooleanConstantExpression(true, builder.token)
|
||||||
ConeBooleanConstantReference.FALSE -> KtContractBooleanConstantExpression(false, builder.token)
|
ConeContractConstantValues.FALSE -> KtContractBooleanConstantExpression(false, builder.token)
|
||||||
else -> error("Can't convert $booleanConstantDescriptor to Analysis API")
|
else -> error("Can't convert $booleanConstantDescriptor to Analysis API")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+77
@@ -0,0 +1,77 @@
|
|||||||
|
// JVM_FILE_NAME: ContractsKt
|
||||||
|
|
||||||
|
@file:OptIn(ExperimentalContracts::class)
|
||||||
|
package test
|
||||||
|
|
||||||
|
import kotlin.contracts.*
|
||||||
|
|
||||||
|
fun myRequire(x: Boolean) {
|
||||||
|
contract {
|
||||||
|
returns() implies x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> call_InPlace(block: () -> R): R {
|
||||||
|
contract {
|
||||||
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
return block()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isNull(obj: Any?): Boolean {
|
||||||
|
contract {
|
||||||
|
returns(true) implies (obj != null)
|
||||||
|
}
|
||||||
|
return obj != null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isNotNull(foo: Any?): Any? {
|
||||||
|
contract {
|
||||||
|
returnsNotNull() implies (foo != null)
|
||||||
|
}
|
||||||
|
return foo
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isString(foo: Any?): String? {
|
||||||
|
contract {
|
||||||
|
returnsNotNull() implies (foo is String)
|
||||||
|
}
|
||||||
|
return foo as? String
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isNotString(foo: Any?): String? {
|
||||||
|
contract {
|
||||||
|
returnsNotNull() implies (foo !is String)
|
||||||
|
}
|
||||||
|
return if (foo is String) null else "not a string"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String?.asSafe(): String? {
|
||||||
|
contract {
|
||||||
|
returnsNotNull() implies (this@asSafe != null)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isStringCheck(x: Any?): Any? {
|
||||||
|
contract {
|
||||||
|
returns(true) implies (x is Comparable<*> || x is CharSequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
return x is String
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isStringOrNumber(x: Any?): Any? {
|
||||||
|
contract {
|
||||||
|
returns(true) implies (x is Comparable<*> && (x is CharSequence || x is Number))
|
||||||
|
}
|
||||||
|
|
||||||
|
return x is String || x is Int
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Number> T?.test0(): Boolean {
|
||||||
|
contract {
|
||||||
|
returns(true) implies (this@test0 is T)
|
||||||
|
}
|
||||||
|
return this is T
|
||||||
|
}
|
||||||
Vendored
+173
@@ -0,0 +1,173 @@
|
|||||||
|
PsiJetFileStubImpl[package=test]
|
||||||
|
KotlinStub$PACKAGE_DIRECTIVE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=test]
|
||||||
|
KotlinStub$IMPORT_LIST
|
||||||
|
KotlinStub$FUN[fqName=test.call_InPlace, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=true, isExtension=false, isTopLevel=true, mayHaveContract=true, name=call_InPlace]
|
||||||
|
effect:CallsInPlace(param(0), EXACTLY_ONCE)
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$TYPE_PARAMETER_LIST
|
||||||
|
KotlinStub$TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=R]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=block]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$FUNCTION_TYPE
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=R]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=R]
|
||||||
|
KotlinStub$FUN[fqName=test.isNotNull, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=true, name=isNotNull]
|
||||||
|
effect:Returns(NOT_NULL) -> param(0) != null
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=foo]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$FUN[fqName=test.isNotString, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=true, name=isNotString]
|
||||||
|
effect:Returns(NOT_NULL) -> param(0) !is KotlinClassTypeBean(classId=kotlin/String, arguments=[], nullable=false)
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=foo]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=String]
|
||||||
|
KotlinStub$FUN[fqName=test.isNull, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=true, name=isNull]
|
||||||
|
effect:Returns(TRUE) -> param(0) != null
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=obj]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Boolean]
|
||||||
|
KotlinStub$FUN[fqName=test.isString, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=true, name=isString]
|
||||||
|
effect:Returns(NOT_NULL) -> param(0) is KotlinClassTypeBean(classId=kotlin/String, arguments=[], nullable=false)
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=foo]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=String]
|
||||||
|
KotlinStub$FUN[fqName=test.isStringCheck, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=true, name=isStringCheck]
|
||||||
|
effect:Returns(TRUE) -> param(0) is KotlinClassTypeBean(classId=kotlin/Comparable, arguments=[KotlinTypeArgumentBean(projectionKind=STAR, type=null)], nullable=false) || param(0) is KotlinClassTypeBean(classId=kotlin/CharSequence, arguments=[], nullable=false)
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=x]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$FUN[fqName=test.isStringOrNumber, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=true, name=isStringOrNumber]
|
||||||
|
effect:Returns(TRUE) -> param(0) is KotlinClassTypeBean(classId=kotlin/Comparable, arguments=[KotlinTypeArgumentBean(projectionKind=STAR, type=null)], nullable=false) && param(0) is KotlinClassTypeBean(classId=kotlin/CharSequence, arguments=[], nullable=false) || param(0) is KotlinClassTypeBean(classId=kotlin/Number, arguments=[], nullable=false)
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=x]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Any]
|
||||||
|
KotlinStub$FUN[fqName=test.myRequire, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=true, mayHaveContract=true, name=myRequire]
|
||||||
|
effect:Returns(WILDCARD) -> param(0)
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=x]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Boolean]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Unit]
|
||||||
|
KotlinStub$FUN[fqName=test.asSafe, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=true, isTopLevel=true, mayHaveContract=true, name=asSafe]
|
||||||
|
effect:Returns(NOT_NULL) -> param(-1) != null
|
||||||
|
KotlinStub$MODIFIER_LIST[public]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=String]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=String]
|
||||||
|
KotlinStub$FUN[fqName=test.test0, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=true, isExtension=true, isTopLevel=true, mayHaveContract=true, name=test0]
|
||||||
|
effect:Returns(TRUE) -> param(-1) is KotlinTypeParameterTypeBean(typeParameterName=T, nullable=false, definitelyNotNull=false)
|
||||||
|
KotlinStub$MODIFIER_LIST[public inline]
|
||||||
|
KotlinStub$TYPE_PARAMETER_LIST
|
||||||
|
KotlinStub$TYPE_PARAMETER[fqName=null, isInVariance=false, isOutVariance=false, name=T]
|
||||||
|
KotlinStub$MODIFIER_LIST[reified]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Number]
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$NULLABLE_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=T]
|
||||||
|
KotlinStub$VALUE_PARAMETER_LIST
|
||||||
|
KotlinStub$TYPE_REFERENCE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$USER_TYPE
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=kotlin]
|
||||||
|
KotlinStub$REFERENCE_EXPRESSION[referencedName=Boolean]
|
||||||
+66
-5
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.decompiler.stub.files
|
|||||||
import com.intellij.psi.stubs.StubElement
|
import com.intellij.psi.stubs.StubElement
|
||||||
import com.intellij.util.indexing.FileContentImpl
|
import com.intellij.util.indexing.FileContentImpl
|
||||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinClsStubBuilder
|
import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinClsStubBuilder
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
import org.jetbrains.kotlin.psi.KtProjectionKind
|
import org.jetbrains.kotlin.psi.KtProjectionKind
|
||||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
@@ -25,11 +26,22 @@ abstract class AbstractAdditionalStubInfoTest : AbstractDecompiledClassTest() {
|
|||||||
|
|
||||||
private fun extractAdditionInfo(stub: StubElement<*>, builder: StringBuilder, level: Int) {
|
private fun extractAdditionInfo(stub: StubElement<*>, builder: StringBuilder, level: Int) {
|
||||||
builder.append(stub.toString())
|
builder.append(stub.toString())
|
||||||
if (stub is KotlinUserTypeStubImpl) {
|
when (stub) {
|
||||||
val upperBound = stub.upperBound
|
is KotlinUserTypeStubImpl -> {
|
||||||
if (upperBound != null) {
|
val upperBound = stub.upperBound
|
||||||
builder.append(" ft: ")
|
if (upperBound != null) {
|
||||||
appendFlexibleTypeInfo(builder, upperBound)
|
builder.append(" ft: ")
|
||||||
|
appendFlexibleTypeInfo(builder, upperBound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KotlinFunctionStubImpl -> {
|
||||||
|
val contract = stub.contract
|
||||||
|
if (contract != null) {
|
||||||
|
for (element in contract) {
|
||||||
|
builder.append("\n" + " ".repeat(level)).append("effect:")
|
||||||
|
element.accept(KotlinContractRenderer(builder), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (child in stub.childrenStubs) {
|
for (child in stub.childrenStubs) {
|
||||||
@@ -77,4 +89,53 @@ abstract class AbstractAdditionalStubInfoTest : AbstractDecompiledClassTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinContractRenderer(private val buffer: StringBuilder) : KtContractDescriptionVisitor<Unit, Nothing?, KotlinTypeBean, Nothing?>() {
|
||||||
|
override fun visitConditionalEffectDeclaration(conditionalEffect: KtConditionalEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
conditionalEffect.effect.accept(this, data)
|
||||||
|
buffer.append(" -> ")
|
||||||
|
conditionalEffect.condition.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturnsEffectDeclaration(returnsEffect: KtReturnsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append("Returns(")
|
||||||
|
returnsEffect.value.accept(this, data)
|
||||||
|
buffer.append(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append("CallsInPlace(")
|
||||||
|
callsEffect.valueParameterReference.accept(this, data)
|
||||||
|
buffer.append(", ${callsEffect.kind})")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: KtBinaryLogicExpression<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
binaryLogicExpression.left.accept(this, data)
|
||||||
|
buffer.append(" ${binaryLogicExpression.kind.token} ")
|
||||||
|
binaryLogicExpression.right.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLogicalNot(logicalNot: KtLogicalNot<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
logicalNot.arg.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsInstancePredicate(isInstancePredicate: KtIsInstancePredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
isInstancePredicate.arg.accept(this, data)
|
||||||
|
buffer.append(" ${if (isInstancePredicate.isNegated) "!" else ""}is ${isInstancePredicate.type}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsNullPredicate(isNullPredicate: KtIsNullPredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
isNullPredicate.arg.accept(this, data)
|
||||||
|
buffer.append(" ${if (isNullPredicate.isNegated) "!=" else "=="} null")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstantDescriptor(constantReference: KtConstantReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append(constantReference.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitValueParameterReference(valueParameterReference: KtValueParameterReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
buffer.append("param(").append(valueParameterReference.parameterIndex).append(")")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+6
@@ -30,6 +30,12 @@ public class AdditionalStubInfoTestGenerated extends AbstractAdditionalStubInfoT
|
|||||||
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/AnnotatedFlexibleTypes/");
|
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/AnnotatedFlexibleTypes/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("Contracts")
|
||||||
|
public void testContracts() throws Exception {
|
||||||
|
runTest("analysis/decompiled/decompiler-to-file-stubs/testData/additionalClsStubInfo/Contracts/");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("OuterClassesWithFlexibleArgs")
|
@TestMetadata("OuterClassesWithFlexibleArgs")
|
||||||
public void testOuterClassesWithFlexibleArgs() throws Exception {
|
public void testOuterClassesWithFlexibleArgs() throws Exception {
|
||||||
|
|||||||
+6
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.resolve.DataClassResolver
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
|
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.getName
|
import org.jetbrains.kotlin.serialization.deserialization.getName
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
|
|
||||||
fun createPackageDeclarationsStubs(
|
fun createPackageDeclarationsStubs(
|
||||||
parentStub: StubElement<out PsiElement>,
|
parentStub: StubElement<out PsiElement>,
|
||||||
@@ -173,6 +174,7 @@ private class FunctionClsStubBuilder(
|
|||||||
// Note that arguments passed to stubs here and elsewhere are based on what stabs would be generated based on decompiled code
|
// Note that arguments passed to stubs here and elsewhere are based on what stabs would be generated based on decompiled code
|
||||||
// As functions are never decompiled to fun f() = 1 form, hasBlockBody is always true
|
// As functions are never decompiled to fun f() = 1 form, hasBlockBody is always true
|
||||||
// This info is anyway irrelevant for the purposes these stubs are used
|
// This info is anyway irrelevant for the purposes these stubs are used
|
||||||
|
val hasContract = functionProto.hasContract()
|
||||||
return KotlinFunctionStubImpl(
|
return KotlinFunctionStubImpl(
|
||||||
parent,
|
parent,
|
||||||
callableName.ref(),
|
callableName.ref(),
|
||||||
@@ -182,7 +184,10 @@ private class FunctionClsStubBuilder(
|
|||||||
hasBlockBody = true,
|
hasBlockBody = true,
|
||||||
hasBody = Flags.MODALITY.get(functionProto.flags) != Modality.ABSTRACT,
|
hasBody = Flags.MODALITY.get(functionProto.flags) != Modality.ABSTRACT,
|
||||||
hasTypeParameterListBeforeFunctionName = functionProto.typeParameterList.isNotEmpty(),
|
hasTypeParameterListBeforeFunctionName = functionProto.typeParameterList.isNotEmpty(),
|
||||||
mayHaveContract = functionProto.hasContract()
|
mayHaveContract = hasContract,
|
||||||
|
runIf(hasContract) {
|
||||||
|
ClsContractBuilder(c, typeStubBuilder).loadContract(functionProto)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.analysis.decompiler.stub
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtBooleanValueParameterReference
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtConstantReference
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtEffectDeclaration
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtValueParameterReference
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.isInstanceType
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.impl.KotlinContractEffectType.Companion.IGNORE_REFERENCE_PARAMETER_NAME
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoBufContractDeserializer
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
|
|
||||||
|
class ClsContractBuilder(private val c: ClsStubBuilderContext, private val typeStubBuilder: TypeClsStubBuilder) :
|
||||||
|
ProtoBufContractDeserializer<KotlinTypeBean, Nothing?, ProtoBuf.Function>() {
|
||||||
|
|
||||||
|
fun loadContract(proto: ProtoBuf.Function): List<KtEffectDeclaration<KotlinTypeBean, Nothing?>>? {
|
||||||
|
return proto.contract.effectList.map { loadPossiblyConditionalEffect(it, proto) ?: return null }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun extractVariable(valueParameterIndex: Int, owner: ProtoBuf.Function): KtValueParameterReference<KotlinTypeBean, Nothing?> {
|
||||||
|
val type = if (valueParameterIndex < 0) {
|
||||||
|
owner.receiverType
|
||||||
|
} else owner.valueParameterList[valueParameterIndex].type
|
||||||
|
return if (type.hasClassName() && c.nameResolver.getClassId(type.className) == StandardClassIds.Boolean) {
|
||||||
|
KtBooleanValueParameterReference(valueParameterIndex, name = IGNORE_REFERENCE_PARAMETER_NAME)
|
||||||
|
} else KtValueParameterReference(valueParameterIndex, name = IGNORE_REFERENCE_PARAMETER_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun extractType(proto: ProtoBuf.Expression): KotlinTypeBean? {
|
||||||
|
return typeStubBuilder.createKotlinTypeBean(proto.isInstanceType(c.typeTable))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadConstant(value: ProtoBuf.Expression.ConstantValue): KtConstantReference<KotlinTypeBean, Nothing?> {
|
||||||
|
return when (value) {
|
||||||
|
ProtoBuf.Expression.ConstantValue.TRUE -> KotlinContractConstantValues.TRUE
|
||||||
|
ProtoBuf.Expression.ConstantValue.FALSE -> KotlinContractConstantValues.FALSE
|
||||||
|
ProtoBuf.Expression.ConstantValue.NULL -> KotlinContractConstantValues.NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNotNull(): KtConstantReference<KotlinTypeBean, Nothing?> {
|
||||||
|
return KotlinContractConstantValues.NOT_NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getWildcard(): KtConstantReference<KotlinTypeBean, Nothing?> {
|
||||||
|
return KotlinContractConstantValues.WILDCARD
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -150,7 +150,7 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKotlinTypeBean(
|
fun createKotlinTypeBean(
|
||||||
type: Type?
|
type: Type?
|
||||||
): KotlinTypeBean? {
|
): KotlinTypeBean? {
|
||||||
if (type == null) return null
|
if (type == null) return null
|
||||||
|
|||||||
+8
-6
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtRealSourceElementKind
|
import org.jetbrains.kotlin.KtRealSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
|
||||||
object FirContractChecker : FirFunctionChecker() {
|
object FirContractChecker : FirFunctionChecker() {
|
||||||
private val EMPTY_CONTRACT_MESSAGE = "Empty contract block is not allowed"
|
private val EMPTY_CONTRACT_MESSAGE = "Empty contract block is not allowed"
|
||||||
@@ -66,7 +68,7 @@ object FirContractChecker : FirFunctionChecker() {
|
|||||||
else if (declaration.symbol.callableId.isLocal || declaration.visibility == Visibilities.Local) contractNotAllowed("Contracts are not allowed for local functions")
|
else if (declaration.symbol.callableId.isLocal || declaration.visibility == Visibilities.Local) contractNotAllowed("Contracts are not allowed for local functions")
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DiagnosticExtractor : ConeContractDescriptionVisitor<ConeDiagnostic?, Nothing?>() {
|
private object DiagnosticExtractor : KtContractDescriptionVisitor<ConeDiagnostic?, Nothing?, ConeKotlinType, ConeDiagnostic>() {
|
||||||
override fun visitContractDescriptionElement(
|
override fun visitContractDescriptionElement(
|
||||||
contractDescriptionElement: ConeContractDescriptionElement,
|
contractDescriptionElement: ConeContractDescriptionElement,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
@@ -90,7 +92,7 @@ object FirContractChecker : FirFunctionChecker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitErroneousCallsEffectDeclaration(
|
override fun visitErroneousCallsEffectDeclaration(
|
||||||
callsEffect: ConeErroneousCallsEffectDeclaration,
|
callsEffect: KtErroneousCallsEffectDeclaration<ConeKotlinType, ConeDiagnostic>,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
): ConeDiagnostic {
|
): ConeDiagnostic {
|
||||||
return callsEffect.diagnostic
|
return callsEffect.diagnostic
|
||||||
@@ -112,7 +114,7 @@ object FirContractChecker : FirFunctionChecker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitErroneousIsInstancePredicate(
|
override fun visitErroneousIsInstancePredicate(
|
||||||
isInstancePredicate: ConeErroneousIsInstancePredicate,
|
isInstancePredicate: KtErroneousIsInstancePredicate<ConeKotlinType, ConeDiagnostic>,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
): ConeDiagnostic {
|
): ConeDiagnostic {
|
||||||
return isInstancePredicate.diagnostic
|
return isInstancePredicate.diagnostic
|
||||||
@@ -123,20 +125,20 @@ object FirContractChecker : FirFunctionChecker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitErroneousConstantReference(
|
override fun visitErroneousConstantReference(
|
||||||
erroneousConstantReference: ConeErroneousConstantReference,
|
erroneousConstantReference: KtErroneousConstantReference<ConeKotlinType, ConeDiagnostic>,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
): ConeDiagnostic {
|
): ConeDiagnostic {
|
||||||
return erroneousConstantReference.diagnostic
|
return erroneousConstantReference.diagnostic
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitErroneousValueParameterReference(
|
override fun visitErroneousValueParameterReference(
|
||||||
valueParameterReference: ConeErroneousValueParameterReference,
|
valueParameterReference: KtErroneousValueParameterReference<ConeKotlinType, ConeDiagnostic>,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
): ConeDiagnostic {
|
): ConeDiagnostic {
|
||||||
return valueParameterReference.diagnostic
|
return valueParameterReference.diagnostic
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitErroneousElement(element: ConeErroneousContractElement, data: Nothing?): ConeDiagnostic {
|
override fun visitErroneousElement(element: KtErroneousContractElement<ConeKotlinType, ConeDiagnostic>, data: Nothing?): ConeDiagnostic {
|
||||||
return element.diagnostic
|
return element.diagnostic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-179
@@ -5,22 +5,24 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.deserialization
|
package org.jetbrains.kotlin.fir.deserialization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
import org.jetbrains.kotlin.contracts.description.KtBooleanValueParameterReference
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtConstantReference
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtValueParameterReference
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription
|
import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.contracts.toFirElement
|
import org.jetbrains.kotlin.fir.contracts.toFirElement
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.isBoolean
|
import org.jetbrains.kotlin.fir.types.isBoolean
|
||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.isInstanceType
|
import org.jetbrains.kotlin.metadata.deserialization.isInstanceType
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoBufContractDeserializer
|
||||||
|
|
||||||
class FirContractDeserializer(private val c: FirDeserializationContext) {
|
class FirContractDeserializer(private val c: FirDeserializationContext) :
|
||||||
|
ProtoBufContractDeserializer<ConeKotlinType, ConeDiagnostic, FirContractDescriptionOwner>() {
|
||||||
fun loadContract(proto: ProtoBuf.Contract, owner: FirContractDescriptionOwner): FirContractDescription? {
|
fun loadContract(proto: ProtoBuf.Contract, owner: FirContractDescriptionOwner): FirContractDescription? {
|
||||||
val effects = proto.effectList.map { loadPossiblyConditionalEffect(it, owner) ?: return null }
|
val effects = proto.effectList.map { loadPossiblyConditionalEffect(it, owner) ?: return null }
|
||||||
return buildResolvedContractDescription {
|
return buildResolvedContractDescription {
|
||||||
@@ -28,105 +30,16 @@ class FirContractDeserializer(private val c: FirDeserializationContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadPossiblyConditionalEffect(
|
override fun extractType(proto: ProtoBuf.Expression): ConeKotlinType? {
|
||||||
proto: ProtoBuf.Effect,
|
return c.typeDeserializer.type(proto.isInstanceType(c.typeTable) ?: return null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun extractVariable(
|
||||||
|
valueParameterIndex: Int,
|
||||||
owner: FirContractDescriptionOwner
|
owner: FirContractDescriptionOwner
|
||||||
): ConeEffectDeclaration? {
|
): KtValueParameterReference<ConeKotlinType, ConeDiagnostic>? {
|
||||||
if (proto.hasConclusionOfConditionalEffect()) {
|
|
||||||
val conclusion = loadExpression(proto.conclusionOfConditionalEffect, owner) ?: return null
|
|
||||||
val effect = loadSimpleEffect(proto, owner) ?: return null
|
|
||||||
return ConeConditionalEffectDeclaration(effect, conclusion)
|
|
||||||
}
|
|
||||||
return loadSimpleEffect(proto, owner)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadSimpleEffect(proto: ProtoBuf.Effect, owner: FirContractDescriptionOwner): ConeEffectDeclaration? {
|
|
||||||
val type: ProtoBuf.Effect.EffectType = if (proto.hasEffectType()) proto.effectType else return null
|
|
||||||
return when(type) {
|
|
||||||
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> {
|
|
||||||
val argument = proto.effectConstructorArgumentList.firstOrNull()
|
|
||||||
val returnValue = if (argument == null) {
|
|
||||||
ConeConstantReference.WILDCARD
|
|
||||||
} else {
|
|
||||||
loadExpression(argument, owner) as? ConeConstantReference ?: return null
|
|
||||||
}
|
|
||||||
ConeReturnsEffectDeclaration(returnValue)
|
|
||||||
}
|
|
||||||
ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL -> {
|
|
||||||
ConeReturnsEffectDeclaration(ConeConstantReference.NOT_NULL)
|
|
||||||
}
|
|
||||||
ProtoBuf.Effect.EffectType.CALLS -> {
|
|
||||||
val argument = proto.effectConstructorArgumentList.firstOrNull() ?: return null
|
|
||||||
val callable = extractVariable(argument, owner) ?: return null
|
|
||||||
val invocationKind = if (proto.hasKind())
|
|
||||||
proto.kind.toDescriptorInvocationKind() ?: return null
|
|
||||||
else
|
|
||||||
EventOccurrencesRange.UNKNOWN
|
|
||||||
ConeCallsEffectDeclaration(callable, invocationKind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadExpression(proto: ProtoBuf.Expression, owner: FirContractDescriptionOwner): ConeBooleanExpression? {
|
|
||||||
val primitiveType = getPrimitiveType(proto)
|
|
||||||
val primitiveExpression = extractPrimitiveExpression(proto, primitiveType, owner)
|
|
||||||
|
|
||||||
val complexType = getComplexType(proto)
|
|
||||||
val childs: MutableList<ConeBooleanExpression> = mutableListOf()
|
|
||||||
childs.addIfNotNull(primitiveExpression)
|
|
||||||
|
|
||||||
return when (complexType) {
|
|
||||||
ComplexExpressionType.AND_SEQUENCE -> {
|
|
||||||
proto.andArgumentList.mapTo(childs) { loadExpression(it, owner) ?: return null }
|
|
||||||
childs.reduce { acc, booleanExpression -> ConeBinaryLogicExpression(acc, booleanExpression, LogicOperationKind.AND) }
|
|
||||||
}
|
|
||||||
|
|
||||||
ComplexExpressionType.OR_SEQUENCE -> {
|
|
||||||
proto.orArgumentList.mapTo(childs) { loadExpression(it, owner) ?: return null }
|
|
||||||
childs.reduce { acc, booleanExpression -> ConeBinaryLogicExpression(acc, booleanExpression, LogicOperationKind.OR) }
|
|
||||||
}
|
|
||||||
|
|
||||||
null -> primitiveExpression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractPrimitiveExpression(proto: ProtoBuf.Expression, primitiveType: PrimitiveExpressionType?, owner: FirContractDescriptionOwner): ConeBooleanExpression? {
|
|
||||||
val isInverted = Flags.IS_NEGATED.get(proto.flags)
|
|
||||||
|
|
||||||
return when (primitiveType) {
|
|
||||||
PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE, PrimitiveExpressionType.RECEIVER_REFERENCE -> {
|
|
||||||
(extractVariable(proto, owner) as? ConeBooleanValueParameterReference?)?.invertIfNecessary(isInverted)
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimitiveExpressionType.CONSTANT ->
|
|
||||||
(loadConstant(proto.constantValue) as? ConeBooleanConstantReference)?.invertIfNecessary(isInverted)
|
|
||||||
|
|
||||||
PrimitiveExpressionType.INSTANCE_CHECK -> {
|
|
||||||
val variable = extractVariable(proto, owner) ?: return null
|
|
||||||
val type = extractType(proto) ?: return null
|
|
||||||
ConeIsInstancePredicate(variable, type, isInverted)
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimitiveExpressionType.NULLABILITY_CHECK -> {
|
|
||||||
val variable = extractVariable(proto, owner) ?: return null
|
|
||||||
ConeIsNullPredicate(variable, isInverted)
|
|
||||||
}
|
|
||||||
|
|
||||||
null -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ConeBooleanExpression.invertIfNecessary(shouldInvert: Boolean): ConeBooleanExpression =
|
|
||||||
if (shouldInvert) ConeLogicalNot(this) else this
|
|
||||||
|
|
||||||
private fun extractVariable(proto: ProtoBuf.Expression, owner: FirContractDescriptionOwner): ConeValueParameterReference? {
|
|
||||||
if (!proto.hasValueParameterReference()) return null
|
|
||||||
|
|
||||||
val ownerFunction = owner as FirSimpleFunction
|
|
||||||
|
|
||||||
val valueParameterIndex = proto.valueParameterReference - 1
|
|
||||||
|
|
||||||
val name: String
|
val name: String
|
||||||
|
val ownerFunction = owner as FirSimpleFunction
|
||||||
val typeRef = if (valueParameterIndex < 0) {
|
val typeRef = if (valueParameterIndex < 0) {
|
||||||
name = "this"
|
name = "this"
|
||||||
ownerFunction.receiverParameter?.typeRef
|
ownerFunction.receiverParameter?.typeRef
|
||||||
@@ -137,90 +50,24 @@ class FirContractDeserializer(private val c: FirDeserializationContext) {
|
|||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
return if (!typeRef.isBoolean)
|
return if (!typeRef.isBoolean)
|
||||||
ConeValueParameterReference(valueParameterIndex, name)
|
KtValueParameterReference(valueParameterIndex, name)
|
||||||
else
|
else
|
||||||
ConeBooleanValueParameterReference(valueParameterIndex, name)
|
KtBooleanValueParameterReference(valueParameterIndex, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): EventOccurrencesRange? = when (this) {
|
override fun loadConstant(value: ProtoBuf.Expression.ConstantValue): KtConstantReference<ConeKotlinType, ConeDiagnostic> {
|
||||||
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> EventOccurrencesRange.AT_MOST_ONCE
|
return when (value) {
|
||||||
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> EventOccurrencesRange.EXACTLY_ONCE
|
ProtoBuf.Expression.ConstantValue.TRUE -> ConeContractConstantValues.TRUE
|
||||||
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> EventOccurrencesRange.AT_LEAST_ONCE
|
ProtoBuf.Expression.ConstantValue.FALSE -> ConeContractConstantValues.FALSE
|
||||||
}
|
ProtoBuf.Expression.ConstantValue.NULL -> ConeContractConstantValues.NULL
|
||||||
|
|
||||||
private fun extractType(proto: ProtoBuf.Expression): ConeKotlinType? {
|
|
||||||
return c.typeDeserializer.type(proto.isInstanceType(c.typeTable) ?: return null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadConstant(value: ProtoBuf.Expression.ConstantValue): ConeConstantReference? = when (value) {
|
|
||||||
ProtoBuf.Expression.ConstantValue.TRUE -> ConeBooleanConstantReference.TRUE
|
|
||||||
ProtoBuf.Expression.ConstantValue.FALSE -> ConeBooleanConstantReference.FALSE
|
|
||||||
ProtoBuf.Expression.ConstantValue.NULL -> ConeConstantReference.NULL
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun getComplexType(proto: ProtoBuf.Expression): ComplexExpressionType? {
|
|
||||||
val isOrSequence = proto.orArgumentCount != 0
|
|
||||||
val isAndSequence = proto.andArgumentCount != 0
|
|
||||||
return when {
|
|
||||||
isOrSequence && isAndSequence -> null
|
|
||||||
isOrSequence -> ComplexExpressionType.OR_SEQUENCE
|
|
||||||
isAndSequence -> ComplexExpressionType.AND_SEQUENCE
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPrimitiveType(proto: ProtoBuf.Expression): PrimitiveExpressionType? {
|
override fun getNotNull(): KtConstantReference<ConeKotlinType, ConeDiagnostic> {
|
||||||
// Expected to be one element, but can be empty (unknown expression) or contain several elements (invalid data)
|
return ConeContractConstantValues.NOT_NULL
|
||||||
val expressionTypes: MutableList<PrimitiveExpressionType> = mutableListOf()
|
|
||||||
|
|
||||||
// Check for predicates
|
|
||||||
when {
|
|
||||||
proto.hasValueParameterReference() && proto.hasType() ->
|
|
||||||
expressionTypes.add(PrimitiveExpressionType.INSTANCE_CHECK)
|
|
||||||
|
|
||||||
proto.hasValueParameterReference() && Flags.IS_NULL_CHECK_PREDICATE.get(proto.flags) ->
|
|
||||||
expressionTypes.add(PrimitiveExpressionType.NULLABILITY_CHECK)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If message contains correct predicate, then predicate's type overrides type of value,
|
|
||||||
// even is message has one
|
|
||||||
if (expressionTypes.isNotEmpty()) {
|
|
||||||
return expressionTypes.singleOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, check if it is a value
|
|
||||||
when {
|
|
||||||
proto.hasValueParameterReference() && proto.valueParameterReference > 0 ->
|
|
||||||
expressionTypes.add(PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE)
|
|
||||||
|
|
||||||
proto.hasValueParameterReference() && proto.valueParameterReference == 0 ->
|
|
||||||
expressionTypes.add(PrimitiveExpressionType.RECEIVER_REFERENCE)
|
|
||||||
|
|
||||||
proto.hasConstantValue() -> expressionTypes.add(PrimitiveExpressionType.CONSTANT)
|
|
||||||
}
|
|
||||||
|
|
||||||
return expressionTypes.singleOrNull()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ProtoBuf.Expression.hasType(): Boolean = this.hasIsInstanceType() || this.hasIsInstanceTypeId()
|
override fun getWildcard(): KtConstantReference<ConeKotlinType, ConeDiagnostic> {
|
||||||
|
return ConeContractConstantValues.WILDCARD
|
||||||
// Arguments of expressions with such types are never other expressions
|
|
||||||
private enum class PrimitiveExpressionType {
|
|
||||||
VALUE_PARAMETER_REFERENCE,
|
|
||||||
RECEIVER_REFERENCE,
|
|
||||||
CONSTANT,
|
|
||||||
INSTANCE_CHECK,
|
|
||||||
NULLABILITY_CHECK
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expressions with such type can take other expressions as arguments.
|
|
||||||
// Additionally, for performance reasons, "complex expression" and "primitive expression"
|
|
||||||
// can co-exist in the one and the same message. If "primitive expression" is present
|
|
||||||
// in the current message, it is treated as the first argument of "complex expression".
|
|
||||||
private enum class ComplexExpressionType {
|
|
||||||
AND_SEQUENCE,
|
|
||||||
OR_SEQUENCE
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-9
@@ -6,12 +6,15 @@
|
|||||||
package org.jetbrains.kotlin.fir.serialization
|
package org.jetbrains.kotlin.fir.serialization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtContractDescriptionVisitor
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.contracts.effects
|
import org.jetbrains.kotlin.fir.contracts.effects
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
|
|
||||||
@@ -57,9 +60,9 @@ class FirContractSerializer {
|
|||||||
|
|
||||||
is ConeReturnsEffectDeclaration -> {
|
is ConeReturnsEffectDeclaration -> {
|
||||||
when (effectDeclaration.value) {
|
when (effectDeclaration.value) {
|
||||||
ConeConstantReference.NOT_NULL ->
|
ConeContractConstantValues.NOT_NULL ->
|
||||||
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL
|
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL
|
||||||
ConeConstantReference.WILDCARD ->
|
ConeContractConstantValues.WILDCARD ->
|
||||||
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
||||||
else -> {
|
else -> {
|
||||||
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
||||||
@@ -89,7 +92,7 @@ class FirContractSerializer {
|
|||||||
contractDescriptionElement: ConeContractDescriptionElement,
|
contractDescriptionElement: ConeContractDescriptionElement,
|
||||||
contractDescription: FirContractDescription
|
contractDescription: FirContractDescription
|
||||||
): ProtoBuf.Expression.Builder {
|
): ProtoBuf.Expression.Builder {
|
||||||
return contractDescriptionElement.accept(object : ConeContractDescriptionVisitor<ProtoBuf.Expression.Builder, Unit>() {
|
return contractDescriptionElement.accept(object : KtContractDescriptionVisitor<ProtoBuf.Expression.Builder, Unit, ConeKotlinType, ConeDiagnostic>() {
|
||||||
override fun visitLogicalBinaryOperationContractExpression(
|
override fun visitLogicalBinaryOperationContractExpression(
|
||||||
binaryLogicExpression: ConeBinaryLogicExpression,
|
binaryLogicExpression: ConeBinaryLogicExpression,
|
||||||
data: Unit
|
data: Unit
|
||||||
@@ -201,14 +204,14 @@ class FirContractSerializer {
|
|||||||
|
|
||||||
private fun constantValueProtobufEnum(constantReference: ConeConstantReference): ProtoBuf.Expression.ConstantValue? =
|
private fun constantValueProtobufEnum(constantReference: ConeConstantReference): ProtoBuf.Expression.ConstantValue? =
|
||||||
when (constantReference) {
|
when (constantReference) {
|
||||||
ConeBooleanConstantReference.TRUE -> ProtoBuf.Expression.ConstantValue.TRUE
|
ConeContractConstantValues.TRUE -> ProtoBuf.Expression.ConstantValue.TRUE
|
||||||
ConeBooleanConstantReference.FALSE -> ProtoBuf.Expression.ConstantValue.FALSE
|
ConeContractConstantValues.FALSE -> ProtoBuf.Expression.ConstantValue.FALSE
|
||||||
ConeConstantReference.NULL -> ProtoBuf.Expression.ConstantValue.NULL
|
ConeContractConstantValues.NULL -> ProtoBuf.Expression.ConstantValue.NULL
|
||||||
ConeConstantReference.NOT_NULL -> throw IllegalStateException(
|
ConeContractConstantValues.NOT_NULL -> throw IllegalStateException(
|
||||||
"Internal error during serialization of function contract: NOT_NULL constant isn't denotable in protobuf format. " +
|
"Internal error during serialization of function contract: NOT_NULL constant isn't denotable in protobuf format. " +
|
||||||
"Its serialization should be handled at higher level"
|
"Its serialization should be handled at higher level"
|
||||||
)
|
)
|
||||||
ConeConstantReference.WILDCARD -> null
|
ConeContractConstantValues.WILDCARD -> null
|
||||||
else -> throw IllegalArgumentException("Unknown constant: $constantReference")
|
else -> throw IllegalArgumentException("Unknown constant: $constantReference")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
|
|||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.KtPsiSourceElement
|
import org.jetbrains.kotlin.KtPsiSourceElement
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
|||||||
+1
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.builder
|
|||||||
import com.intellij.psi.tree.IElementType
|
import com.intellij.psi.tree.IElementType
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.contracts.description.canBeRevisited
|
import org.jetbrains.kotlin.contracts.description.canBeRevisited
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
|
|||||||
+1
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.dfa.cfg
|
package org.jetbrains.kotlin.fir.resolve.dfa.cfg
|
||||||
|
|
||||||
import org.jetbrains.kotlin.contracts.description.*
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
|
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
|
||||||
|
|||||||
+2
-2
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.transformers
|
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||||
@@ -12,7 +13,6 @@ import org.jetbrains.kotlin.fir.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind.OR
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
||||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
@@ -182,7 +182,7 @@ private sealed class WhenExhaustivenessChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression, data: D) {
|
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression, data: D) {
|
||||||
if (binaryLogicExpression.kind == OR) {
|
if (binaryLogicExpression.kind == LogicOperationKind.OR) {
|
||||||
binaryLogicExpression.acceptChildren(this, data)
|
binaryLogicExpression.acceptChildren(this, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-17
@@ -5,11 +5,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
|
package org.jetbrains.kotlin.fir.resolve.transformers.contracts
|
||||||
|
|
||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeContractDescriptionError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeContractDescriptionError
|
||||||
@@ -37,8 +39,8 @@ class ConeEffectExtractor(
|
|||||||
private val BOOLEAN_NOT = FirContractsDslNames.id("kotlin", "Boolean", "not")
|
private val BOOLEAN_NOT = FirContractsDslNames.id("kotlin", "Boolean", "not")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConeContractDescriptionError.asElement(): ConeErroneousContractElement {
|
private fun ConeContractDescriptionError.asElement(): KtErroneousContractElement<ConeKotlinType, ConeDiagnostic> {
|
||||||
return ConeErroneousContractElement(this)
|
return KtErroneousContractElement(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitElement(element: FirElement, data: Nothing?): ConeContractDescriptionElement {
|
override fun visitElement(element: FirElement, data: Nothing?): ConeContractDescriptionElement {
|
||||||
@@ -63,18 +65,19 @@ class ConeEffectExtractor(
|
|||||||
FirContractsDslNames.RETURNS -> {
|
FirContractsDslNames.RETURNS -> {
|
||||||
val argument = functionCall.arguments.firstOrNull()
|
val argument = functionCall.arguments.firstOrNull()
|
||||||
val value = if (argument == null) {
|
val value = if (argument == null) {
|
||||||
ConeConstantReference.WILDCARD
|
ConeContractConstantValues.WILDCARD
|
||||||
} else {
|
} else {
|
||||||
when (val value = argument.asContractElement()) {
|
when (val value = argument.asContractElement()) {
|
||||||
is ConeConstantReference -> value
|
is ConeConstantReference -> value
|
||||||
else -> ConeErroneousConstantReference(ConeContractDescriptionError.NotAConstant(value))
|
else -> KtErroneousConstantReference(ConeContractDescriptionError.NotAConstant(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConeReturnsEffectDeclaration(value)
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
KtReturnsEffectDeclaration(value as ConeConstantReference)
|
||||||
}
|
}
|
||||||
|
|
||||||
FirContractsDslNames.RETURNS_NOT_NULL -> {
|
FirContractsDslNames.RETURNS_NOT_NULL -> {
|
||||||
ConeReturnsEffectDeclaration(ConeConstantReference.NOT_NULL)
|
ConeReturnsEffectDeclaration(ConeContractConstantValues.NOT_NULL)
|
||||||
}
|
}
|
||||||
|
|
||||||
FirContractsDslNames.CALLS_IN_PLACE -> {
|
FirContractsDslNames.CALLS_IN_PLACE -> {
|
||||||
@@ -82,7 +85,7 @@ class ConeEffectExtractor(
|
|||||||
when (val argument = functionCall.arguments.getOrNull(1)) {
|
when (val argument = functionCall.arguments.getOrNull(1)) {
|
||||||
null -> ConeCallsEffectDeclaration(reference, EventOccurrencesRange.UNKNOWN)
|
null -> ConeCallsEffectDeclaration(reference, EventOccurrencesRange.UNKNOWN)
|
||||||
else -> when (val kind = argument.parseInvocationKind()) {
|
else -> when (val kind = argument.parseInvocationKind()) {
|
||||||
null -> ConeErroneousCallsEffectDeclaration(reference, ConeContractDescriptionError.UnresolvedInvocationKind(argument))
|
null -> KtErroneousCallsEffectDeclaration(reference, ConeContractDescriptionError.UnresolvedInvocationKind(argument))
|
||||||
else -> ConeCallsEffectDeclaration(reference, kind)
|
else -> ConeCallsEffectDeclaration(reference, kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,10 +149,10 @@ class ConeEffectExtractor(
|
|||||||
return ConeContractDescriptionError.UnresolvedCall(name).asElement()
|
return ConeContractDescriptionError.UnresolvedCall(name).asElement()
|
||||||
}
|
}
|
||||||
val parameter = symbol.fir as? FirValueParameter
|
val parameter = symbol.fir as? FirValueParameter
|
||||||
?: return ConeErroneousValueParameterReference(
|
?: return KtErroneousValueParameterReference(
|
||||||
ConeContractDescriptionError.IllegalParameter(symbol, "$symbol is not a value parameter")
|
ConeContractDescriptionError.IllegalParameter(symbol, "$symbol is not a value parameter")
|
||||||
)
|
)
|
||||||
val index = valueParameters.indexOf(parameter).takeUnless { it < 0 } ?: return ConeErroneousValueParameterReference(
|
val index = valueParameters.indexOf(parameter).takeUnless { it < 0 } ?: return KtErroneousValueParameterReference(
|
||||||
ConeContractDescriptionError.IllegalParameter(symbol, "Value paramter $symbol is not found in parameters of outer function")
|
ConeContractDescriptionError.IllegalParameter(symbol, "Value paramter $symbol is not found in parameters of outer function")
|
||||||
)
|
)
|
||||||
val type = parameter.returnTypeRef.coneType
|
val type = parameter.returnTypeRef.coneType
|
||||||
@@ -200,10 +203,10 @@ class ConeEffectExtractor(
|
|||||||
|
|
||||||
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Nothing?): ConeContractDescriptionElement {
|
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Nothing?): ConeContractDescriptionElement {
|
||||||
return when (constExpression.kind) {
|
return when (constExpression.kind) {
|
||||||
ConstantValueKind.Null -> ConeConstantReference.NULL
|
ConstantValueKind.Null -> ConeContractConstantValues.NULL
|
||||||
ConstantValueKind.Boolean -> when (constExpression.value as Boolean) {
|
ConstantValueKind.Boolean -> when (constExpression.value as Boolean) {
|
||||||
true -> ConeBooleanConstantReference.TRUE
|
true -> ConeContractConstantValues.TRUE
|
||||||
false -> ConeBooleanConstantReference.FALSE
|
false -> ConeContractConstantValues.FALSE
|
||||||
}
|
}
|
||||||
else -> ConeContractDescriptionError.IllegalConst(constExpression, onlyNullAllowed = false).asElement()
|
else -> ConeContractDescriptionError.IllegalConst(constExpression, onlyNullAllowed = false).asElement()
|
||||||
}
|
}
|
||||||
@@ -224,7 +227,7 @@ class ConeEffectExtractor(
|
|||||||
}
|
}
|
||||||
return when (diagnostic) {
|
return when (diagnostic) {
|
||||||
null -> ConeIsInstancePredicate(arg, type, isNegated)
|
null -> ConeIsInstancePredicate(arg, type, isNegated)
|
||||||
else -> ConeErroneousIsInstancePredicate(arg, type, isNegated, diagnostic)
|
else -> KtErroneousIsInstancePredicate(arg, type, isNegated, diagnostic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,11 +243,11 @@ class ConeEffectExtractor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun noReceiver(callableId: CallableId): ConeErroneousContractElement {
|
private fun noReceiver(callableId: CallableId): KtErroneousContractElement<ConeKotlinType, ConeDiagnostic> {
|
||||||
return ConeContractDescriptionError.NoReceiver(callableId.callableName).asElement()
|
return ConeContractDescriptionError.NoReceiver(callableId.callableName).asElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun noArgument(callableId: CallableId): ConeErroneousContractElement {
|
private fun noArgument(callableId: CallableId): KtErroneousContractElement<ConeKotlinType, ConeDiagnostic> {
|
||||||
return ConeContractDescriptionError.NoArgument(callableId.callableName).asElement()
|
return ConeContractDescriptionError.NoArgument(callableId.callableName).asElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +265,7 @@ class ConeEffectExtractor(
|
|||||||
private fun FirExpression.asContractValueExpression(): ConeValueParameterReference {
|
private fun FirExpression.asContractValueExpression(): ConeValueParameterReference {
|
||||||
return when (val element = asContractElement()) {
|
return when (val element = asContractElement()) {
|
||||||
is ConeValueParameterReference -> element
|
is ConeValueParameterReference -> element
|
||||||
else -> ConeErroneousValueParameterReference(ConeContractDescriptionError.NotAParameterReference(element))
|
else -> KtErroneousValueParameterReference(ConeContractDescriptionError.NotAParameterReference(element))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,17 +5,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.canBeNull
|
||||||
|
import org.jetbrains.kotlin.fir.types.isAny
|
||||||
|
import org.jetbrains.kotlin.fir.types.isMarkedNullable
|
||||||
|
import org.jetbrains.kotlin.fir.types.isNullableNothing
|
||||||
|
|
||||||
fun ConeConstantReference.toOperation(): Operation? = when (this) {
|
fun ConeConstantReference.toOperation(): Operation? = when (this) {
|
||||||
ConeConstantReference.WILDCARD -> null
|
ConeContractConstantValues.WILDCARD -> null
|
||||||
ConeConstantReference.NULL -> Operation.EqNull
|
ConeContractConstantValues.NULL -> Operation.EqNull
|
||||||
ConeConstantReference.NOT_NULL -> Operation.NotEqNull
|
ConeContractConstantValues.NOT_NULL -> Operation.NotEqNull
|
||||||
ConeBooleanConstantReference.TRUE -> Operation.EqTrue
|
ConeContractConstantValues.TRUE -> Operation.EqTrue
|
||||||
ConeBooleanConstantReference.FALSE -> Operation.EqFalse
|
ConeContractConstantValues.FALSE -> Operation.EqFalse
|
||||||
else -> throw IllegalArgumentException("$this can not be transformed to Operation")
|
else -> throw IllegalArgumentException("$this can not be transformed to Operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ fun LogicSystem.approveContractStatement(
|
|||||||
|
|
||||||
fun ConeBooleanExpression.visit(inverted: Boolean): TypeStatements? = when (this) {
|
fun ConeBooleanExpression.visit(inverted: Boolean): TypeStatements? = when (this) {
|
||||||
is ConeBooleanConstantReference ->
|
is ConeBooleanConstantReference ->
|
||||||
if (inverted == (this == ConeBooleanConstantReference.TRUE)) null else mapOf()
|
if (inverted == (this == ConeContractConstantValues.TRUE)) null else mapOf()
|
||||||
is ConeLogicalNot -> arg.visit(inverted = !inverted)
|
is ConeLogicalNot -> arg.visit(inverted = !inverted)
|
||||||
is ConeIsInstancePredicate ->
|
is ConeIsInstancePredicate ->
|
||||||
arguments.getOrNull(arg.parameterIndex + 1)?.let {
|
arguments.getOrNull(arg.parameterIndex + 1)?.let {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":compiler:frontend.common"))
|
api(project(":compiler:frontend.common"))
|
||||||
|
api(project(":core:compiler.common"))
|
||||||
api(project(":compiler:fir:cones"))
|
api(project(":compiler:fir:cones"))
|
||||||
|
|
||||||
// Necessary only to store bound PsiElement inside FirElement
|
// Necessary only to store bound PsiElement inside FirElement
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.expressions
|
package org.jetbrains.kotlin.fir.expressions
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.fir.visitors.*
|
import org.jetbrains.kotlin.fir.visitors.*
|
||||||
|
|||||||
+1
-1
@@ -9,13 +9,13 @@ package org.jetbrains.kotlin.fir.expressions.builder
|
|||||||
|
|
||||||
import kotlin.contracts.*
|
import kotlin.contracts.*
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
|
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
|
||||||
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
||||||
import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
|
import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.FirExpressionBuilder
|
import org.jetbrains.kotlin.fir.expressions.builder.FirExpressionBuilder
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirBinaryLogicExpressionImpl
|
import org.jetbrains.kotlin.fir.expressions.impl.FirBinaryLogicExpressionImpl
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
|||||||
+1
-1
@@ -8,10 +8,10 @@
|
|||||||
package org.jetbrains.kotlin.fir.expressions.impl
|
package org.jetbrains.kotlin.fir.expressions.impl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource
|
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource
|
||||||
import org.jetbrains.kotlin.fir.visitors.*
|
import org.jetbrains.kotlin.fir.visitors.*
|
||||||
|
|||||||
-22
@@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 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
|
|
||||||
|
|
||||||
interface ConeContractDescriptionElement {
|
|
||||||
fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R
|
|
||||||
|
|
||||||
val erroneous: Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class ConeEffectDeclaration : ConeContractDescriptionElement {
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitEffectDeclaration(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ConeBooleanExpression : ConeContractDescriptionElement {
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitBooleanExpression(this, data)
|
|
||||||
}
|
|
||||||
-69
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 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
|
|
||||||
|
|
||||||
|
|
||||||
abstract class ConeContractDescriptionVisitor<out R, in D> {
|
|
||||||
open fun visitContractDescriptionElement(contractDescriptionElement: ConeContractDescriptionElement, data: D): R {
|
|
||||||
throw IllegalStateException("Top of hierarchy reached, no overloads were found for element: $contractDescriptionElement")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Effects
|
|
||||||
open fun visitEffectDeclaration(effectDeclaration: ConeEffectDeclaration, data: D): R = visitContractDescriptionElement(effectDeclaration, data)
|
|
||||||
|
|
||||||
open fun visitConditionalEffectDeclaration(conditionalEffect: ConeConditionalEffectDeclaration, data: D): R =
|
|
||||||
visitEffectDeclaration(conditionalEffect, data)
|
|
||||||
|
|
||||||
open fun visitReturnsEffectDeclaration(returnsEffect: ConeReturnsEffectDeclaration, data: D): R =
|
|
||||||
visitEffectDeclaration(returnsEffect, data)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
open fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: ConeBinaryLogicExpression, data: D): R =
|
|
||||||
visitBooleanExpression(binaryLogicExpression, data)
|
|
||||||
|
|
||||||
open fun visitLogicalNot(logicalNot: ConeLogicalNot, data: D): R = visitBooleanExpression(logicalNot, data)
|
|
||||||
|
|
||||||
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
|
|
||||||
open fun visitValue(value: ConeContractDescriptionValue, data: D): R = visitContractDescriptionElement(value, data)
|
|
||||||
|
|
||||||
open fun visitConstantDescriptor(constantReference: ConeConstantReference, data: D): R = visitValue(constantReference, data)
|
|
||||||
|
|
||||||
open fun visitBooleanConstantDescriptor(booleanConstantDescriptor: ConeBooleanConstantReference, data: D): R =
|
|
||||||
visitConstantDescriptor(booleanConstantDescriptor, data)
|
|
||||||
|
|
||||||
open fun visitErroneousConstantReference(erroneousConstantReference: ConeErroneousConstantReference, data: D): R =
|
|
||||||
visitConstantDescriptor(erroneousConstantReference, data)
|
|
||||||
|
|
||||||
open fun visitValueParameterReference(valueParameterReference: ConeValueParameterReference, data: D): R =
|
|
||||||
visitValue(valueParameterReference, data)
|
|
||||||
|
|
||||||
open fun visitBooleanValueParameterReference(booleanValueParameterReference: ConeBooleanValueParameterReference, data: D): R =
|
|
||||||
visitValueParameterReference(booleanValueParameterReference, data)
|
|
||||||
|
|
||||||
open fun visitErroneousValueParameterReference(valueParameterReference: ConeErroneousValueParameterReference, data: D): R =
|
|
||||||
visitValueParameterReference(valueParameterReference, data)
|
|
||||||
|
|
||||||
// Error
|
|
||||||
open fun visitErroneousElement(element: ConeErroneousContractElement, data: D): R =
|
|
||||||
visitContractDescriptionElement(element, data)
|
|
||||||
}
|
|
||||||
+18
-15
@@ -5,14 +5,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.contracts.description
|
package org.jetbrains.kotlin.fir.contracts.description
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.contracts.*
|
import org.jetbrains.kotlin.fir.contracts.*
|
||||||
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
|
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.renderer.FirRendererComponents
|
import org.jetbrains.kotlin.fir.renderer.FirRendererComponents
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.renderForDebugging
|
import org.jetbrains.kotlin.fir.types.renderForDebugging
|
||||||
|
|
||||||
class ConeContractRenderer : ConeContractDescriptionVisitor<Unit, Nothing?>() {
|
class ConeContractRenderer : KtContractDescriptionVisitor<Unit, Nothing?, ConeKotlinType, ConeDiagnostic>() {
|
||||||
|
|
||||||
internal lateinit var components: FirRendererComponents
|
internal lateinit var components: FirRendererComponents
|
||||||
private val printer get() = components.printer
|
private val printer get() = components.printer
|
||||||
@@ -74,54 +77,54 @@ class ConeContractRenderer : ConeContractDescriptionVisitor<Unit, Nothing?>() {
|
|||||||
printer.println(">")
|
printer.println(">")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConditionalEffectDeclaration(conditionalEffect: ConeConditionalEffectDeclaration, data: Nothing?) {
|
override fun visitConditionalEffectDeclaration(conditionalEffect: KtConditionalEffectDeclaration<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
conditionalEffect.effect.accept(this, data)
|
conditionalEffect.effect.accept(this, data)
|
||||||
printer.print(" -> ")
|
printer.print(" -> ")
|
||||||
conditionalEffect.condition.accept(this, data)
|
conditionalEffect.condition.accept(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReturnsEffectDeclaration(returnsEffect: ConeReturnsEffectDeclaration, data: Nothing?) {
|
override fun visitReturnsEffectDeclaration(returnsEffect: KtReturnsEffectDeclaration<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
printer.print("Returns(")
|
printer.print("Returns(")
|
||||||
returnsEffect.value.accept(this, data)
|
returnsEffect.value.accept(this, data)
|
||||||
printer.print(")")
|
printer.print(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: Nothing?) {
|
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
printer.print("CallsInPlace(")
|
printer.print("CallsInPlace(")
|
||||||
callsEffect.valueParameterReference.accept(this, data)
|
callsEffect.valueParameterReference.accept(this, data)
|
||||||
printer.print(", ${callsEffect.kind})")
|
printer.print(", ${callsEffect.kind})")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: ConeBinaryLogicExpression, data: Nothing?) {
|
override fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: KtBinaryLogicExpression<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
inBracketsIfNecessary(binaryLogicExpression, binaryLogicExpression.left) { binaryLogicExpression.left.accept(this, data) }
|
inBracketsIfNecessary(binaryLogicExpression, binaryLogicExpression.left) { binaryLogicExpression.left.accept(this, data) }
|
||||||
printer.print(" ${binaryLogicExpression.kind.token} ")
|
printer.print(" ${binaryLogicExpression.kind.token} ")
|
||||||
inBracketsIfNecessary(binaryLogicExpression, binaryLogicExpression.right) { binaryLogicExpression.right.accept(this, data) }
|
inBracketsIfNecessary(binaryLogicExpression, binaryLogicExpression.right) { binaryLogicExpression.right.accept(this, data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLogicalNot(logicalNot: ConeLogicalNot, data: Nothing?) {
|
override fun visitLogicalNot(logicalNot: KtLogicalNot<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
inBracketsIfNecessary(logicalNot, logicalNot.arg) { printer.print("!") }
|
inBracketsIfNecessary(logicalNot, logicalNot.arg) { printer.print("!") }
|
||||||
logicalNot.arg.accept(this, data)
|
logicalNot.arg.accept(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitIsInstancePredicate(isInstancePredicate: ConeIsInstancePredicate, data: Nothing?) {
|
override fun visitIsInstancePredicate(isInstancePredicate: KtIsInstancePredicate<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
isInstancePredicate.arg.accept(this, data)
|
isInstancePredicate.arg.accept(this, data)
|
||||||
printer.print(" ${if (isInstancePredicate.isNegated) "!" else ""}is ${isInstancePredicate.type.renderForDebugging()}")
|
printer.print(" ${if (isInstancePredicate.isNegated) "!" else ""}is ${isInstancePredicate.type.renderForDebugging()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: Nothing?) {
|
override fun visitIsNullPredicate(isNullPredicate: KtIsNullPredicate<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
isNullPredicate.arg.accept(this, data)
|
isNullPredicate.arg.accept(this, data)
|
||||||
printer.print(" ${if (isNullPredicate.isNegated) "!=" else "=="} null")
|
printer.print(" ${if (isNullPredicate.isNegated) "!=" else "=="} null")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstantDescriptor(constantReference: ConeConstantReference, data: Nothing?) {
|
override fun visitConstantDescriptor(constantReference: KtConstantReference<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
printer.print(constantReference.name)
|
printer.print(constantReference.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitValueParameterReference(valueParameterReference: ConeValueParameterReference, data: Nothing?) {
|
override fun visitValueParameterReference(valueParameterReference: KtValueParameterReference<ConeKotlinType, ConeDiagnostic>, data: Nothing?) {
|
||||||
printer.print(valueParameterReference.name)
|
printer.print(valueParameterReference.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inBracketsIfNecessary(parent: ConeContractDescriptionElement, child: ConeContractDescriptionElement, block: () -> Unit) {
|
private fun inBracketsIfNecessary(parent: KtContractDescriptionElement<ConeKotlinType, ConeDiagnostic>, child: KtContractDescriptionElement<ConeKotlinType, ConeDiagnostic>, block: () -> Unit) {
|
||||||
if (needsBrackets(parent, child)) {
|
if (needsBrackets(parent, child)) {
|
||||||
printer.print("(")
|
printer.print("(")
|
||||||
block()
|
block()
|
||||||
@@ -131,12 +134,12 @@ class ConeContractRenderer : ConeContractDescriptionVisitor<Unit, Nothing?>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConeContractDescriptionElement.isAtom(): Boolean =
|
private fun KtContractDescriptionElement<ConeKotlinType, ConeDiagnostic>.isAtom(): Boolean =
|
||||||
this is ConeValueParameterReference || this is ConeConstantReference || this is ConeIsNullPredicate || this is ConeIsInstancePredicate
|
this is KtValueParameterReference || this is KtConstantReference || this is KtIsNullPredicate || this is KtIsInstancePredicate
|
||||||
|
|
||||||
private fun needsBrackets(parent: ConeContractDescriptionElement, child: ConeContractDescriptionElement): Boolean {
|
private fun needsBrackets(parent: KtContractDescriptionElement<ConeKotlinType, ConeDiagnostic>, child: KtContractDescriptionElement<ConeKotlinType, ConeDiagnostic>): Boolean {
|
||||||
if (child.isAtom()) return false
|
if (child.isAtom()) return false
|
||||||
if (parent is ConeLogicalNot) return true
|
if (parent is KtLogicalNot) return true
|
||||||
return parent::class != child::class
|
return parent::class != child::class
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-19
@@ -1,19 +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.diagnostics.ConeDiagnostic
|
|
||||||
|
|
||||||
class ConeErroneousContractElement(
|
|
||||||
val diagnostic: ConeDiagnostic
|
|
||||||
) : ConeEffectDeclaration(), ConeBooleanExpression, ConeContractDescriptionValue {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R {
|
|
||||||
return contractDescriptionVisitor.visitErroneousElement(this, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-25
@@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 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.LogicOperationKind
|
|
||||||
|
|
||||||
class ConeBinaryLogicExpression(val left: ConeBooleanExpression, val right: ConeBooleanExpression, val kind: LogicOperationKind) : ConeBooleanExpression {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = left.erroneous || right.erroneous
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R {
|
|
||||||
return contractDescriptionVisitor.visitLogicalBinaryOperationContractExpression(this, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConeLogicalNot(val arg: ConeBooleanExpression) : ConeBooleanExpression {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = arg.erroneous
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitLogicalNot(this, data)
|
|
||||||
}
|
|
||||||
-44
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 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
|
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|
||||||
|
|
||||||
open class ConeIsInstancePredicate(val arg: ConeValueParameterReference, val type: ConeKotlinType, val isNegated: Boolean) : ConeBooleanExpression {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = arg.erroneous
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitIsInstancePredicate(this, data)
|
|
||||||
|
|
||||||
fun negated(): ConeIsInstancePredicate =
|
|
||||||
ConeIsInstancePredicate(arg, type, isNegated.not())
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConeErroneousIsInstancePredicate(
|
|
||||||
arg: ConeValueParameterReference,
|
|
||||||
type: ConeKotlinType,
|
|
||||||
isNegated: Boolean,
|
|
||||||
val diagnostic: ConeDiagnostic
|
|
||||||
) : ConeIsInstancePredicate(arg, type, isNegated) {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitErroneousIsInstancePredicate(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConeIsNullPredicate(val arg: ConeValueParameterReference, val isNegated: Boolean) : ConeBooleanExpression {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = arg.erroneous
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitIsNullPredicate(this, data)
|
|
||||||
|
|
||||||
fun negated(): ConeIsNullPredicate =
|
|
||||||
ConeIsNullPredicate(arg, isNegated.not())
|
|
||||||
}
|
|
||||||
+23
-64
@@ -1,74 +1,33 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* 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
|
package org.jetbrains.kotlin.fir.contracts.description
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
|
||||||
interface ConeContractDescriptionValue : ConeContractDescriptionElement {
|
object ConeContractConstantValues {
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
val NULL = KtConstantReference<ConeKotlinType, ConeDiagnostic>("NULL")
|
||||||
contractDescriptionVisitor.visitValue(this, data)
|
val WILDCARD = KtConstantReference<ConeKotlinType, ConeDiagnostic>("WILDCARD")
|
||||||
|
val NOT_NULL = KtConstantReference<ConeKotlinType, ConeDiagnostic>("NOT_NULL")
|
||||||
|
val TRUE = KtBooleanConstantReference<ConeKotlinType, ConeDiagnostic>("TRUE")
|
||||||
|
val FALSE = KtBooleanConstantReference<ConeKotlinType, ConeDiagnostic>("FALSE")
|
||||||
}
|
}
|
||||||
|
|
||||||
open class ConeConstantReference protected constructor(val name: String) : ConeContractDescriptionValue {
|
typealias ConeEffectDeclaration = KtEffectDeclaration<ConeKotlinType, ConeDiagnostic>
|
||||||
override val erroneous: Boolean
|
typealias ConeContractDescriptionElement = KtContractDescriptionElement<ConeKotlinType, ConeDiagnostic>
|
||||||
get() = false
|
typealias ConeCallsEffectDeclaration = KtCallsEffectDeclaration<ConeKotlinType, ConeDiagnostic>
|
||||||
|
typealias ConeConditionalEffectDeclaration = KtConditionalEffectDeclaration<ConeKotlinType, ConeDiagnostic>
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
typealias ConeReturnsEffectDeclaration = KtReturnsEffectDeclaration<ConeKotlinType, ConeDiagnostic>
|
||||||
contractDescriptionVisitor.visitConstantDescriptor(this, data)
|
typealias ConeConstantReference = KtConstantReference<ConeKotlinType, ConeDiagnostic>
|
||||||
|
typealias ConeIsNullPredicate = KtIsNullPredicate<ConeKotlinType, ConeDiagnostic>
|
||||||
companion object {
|
typealias ConeIsInstancePredicate = KtIsInstancePredicate<ConeKotlinType, ConeDiagnostic>
|
||||||
val NULL = ConeConstantReference("NULL")
|
typealias ConeLogicalNot = KtLogicalNot<ConeKotlinType, ConeDiagnostic>
|
||||||
val WILDCARD = ConeConstantReference("WILDCARD")
|
typealias ConeBooleanExpression = KtBooleanExpression<ConeKotlinType, ConeDiagnostic>
|
||||||
val NOT_NULL = ConeConstantReference("NOT_NULL")
|
typealias ConeBinaryLogicExpression = KtBinaryLogicExpression<ConeKotlinType, ConeDiagnostic>
|
||||||
}
|
typealias ConeBooleanConstantReference = KtBooleanConstantReference<ConeKotlinType, ConeDiagnostic>
|
||||||
}
|
typealias ConeValueParameterReference = KtValueParameterReference<ConeKotlinType, ConeDiagnostic>
|
||||||
|
typealias ConeBooleanValueParameterReference = KtBooleanValueParameterReference<ConeKotlinType, ConeDiagnostic>
|
||||||
class ConeBooleanConstantReference private constructor(name: String) : ConeConstantReference(name), ConeBooleanExpression {
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitBooleanConstantDescriptor(this, data)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val TRUE = ConeBooleanConstantReference("TRUE")
|
|
||||||
val FALSE = ConeBooleanConstantReference("FALSE")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConeErroneousConstantReference(val diagnostic: ConeDiagnostic) : ConeConstantReference("ERROR") {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitErroneousConstantReference(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Index of value parameter of function
|
|
||||||
* -1 means that it is reference to extension receiver
|
|
||||||
*/
|
|
||||||
open class ConeValueParameterReference(val parameterIndex: Int, val name: String) : ConeContractDescriptionValue {
|
|
||||||
init {
|
|
||||||
assert(parameterIndex >= -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitValueParameterReference(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConeBooleanValueParameterReference(parameterIndex: Int, name: String) : ConeValueParameterReference(parameterIndex, name), ConeBooleanExpression {
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitBooleanValueParameterReference(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConeErroneousValueParameterReference(val diagnostic: ConeDiagnostic) : ConeValueParameterReference(Int.MAX_VALUE, "ERROR") {
|
|
||||||
override val erroneous: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
|
||||||
contractDescriptionVisitor.visitErroneousValueParameterReference(this, data)
|
|
||||||
}
|
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ val smartcastStabilityType = type(SmartcastStability::class)
|
|||||||
val fqNameType = type(FqName::class)
|
val fqNameType = type(FqName::class)
|
||||||
val classIdType = type(ClassId::class)
|
val classIdType = type(ClassId::class)
|
||||||
val annotationUseSiteTargetType = type(AnnotationUseSiteTarget::class)
|
val annotationUseSiteTargetType = type(AnnotationUseSiteTarget::class)
|
||||||
val operationKindType = type("fir.expressions", "LogicOperationKind")
|
val operationKindType = type("contracts.description", "LogicOperationKind")
|
||||||
val coneKotlinTypeType = type(ConeKotlinType::class)
|
val coneKotlinTypeType = type(ConeKotlinType::class)
|
||||||
val coneSimpleKotlinTypeType = type(ConeSimpleKotlinType::class)
|
val coneSimpleKotlinTypeType = type(ConeSimpleKotlinType::class)
|
||||||
val coneClassLikeTypeType = type(ConeClassLikeType::class)
|
val coneClassLikeTypeType = type(ConeClassLikeType::class)
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ object KotlinStubVersions {
|
|||||||
// Though only kotlin declarations (no code in the bodies) are stubbed, please do increase this version
|
// Though only kotlin declarations (no code in the bodies) are stubbed, please do increase this version
|
||||||
// if you are not 100% sure it can be avoided.
|
// if you are not 100% sure it can be avoided.
|
||||||
// Increasing this version will lead to reindexing of all kotlin source files on the first IDE startup with the new version.
|
// Increasing this version will lead to reindexing of all kotlin source files on the first IDE startup with the new version.
|
||||||
const val SOURCE_STUB_VERSION = 149
|
const val SOURCE_STUB_VERSION = 150
|
||||||
|
|
||||||
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
|
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
|
||||||
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
|
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
|
||||||
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
|
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
|
||||||
private const val BINARY_STUB_VERSION = 85
|
private const val BINARY_STUB_VERSION = 86
|
||||||
|
|
||||||
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
|
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
|
||||||
// Increasing this version will lead to reindexing of all classfiles.
|
// Increasing this version will lead to reindexing of all classfiles.
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ public class KtFunctionElementType extends KtStubElementType<KotlinFunctionStub,
|
|||||||
return new KotlinFunctionStubImpl(
|
return new KotlinFunctionStubImpl(
|
||||||
(StubElement<?>) parentStub, StringRef.fromString(psi.getName()), isTopLevel, fqName,
|
(StubElement<?>) parentStub, StringRef.fromString(psi.getName()), isTopLevel, fqName,
|
||||||
isExtension, hasBlockBody, hasBody, psi.hasTypeParameterListBeforeFunctionName(),
|
isExtension, hasBlockBody, hasBody, psi.hasTypeParameterListBeforeFunctionName(),
|
||||||
psi.mayHaveContract()
|
psi.mayHaveContract(),
|
||||||
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +68,11 @@ public class KtFunctionElementType extends KtStubElementType<KotlinFunctionStub,
|
|||||||
dataStream.writeBoolean(stub.hasBlockBody());
|
dataStream.writeBoolean(stub.hasBlockBody());
|
||||||
dataStream.writeBoolean(stub.hasBody());
|
dataStream.writeBoolean(stub.hasBody());
|
||||||
dataStream.writeBoolean(stub.hasTypeParameterListBeforeFunctionName());
|
dataStream.writeBoolean(stub.hasTypeParameterListBeforeFunctionName());
|
||||||
dataStream.writeBoolean(stub.mayHaveContract());
|
boolean haveContract = stub.mayHaveContract();
|
||||||
|
dataStream.writeBoolean(haveContract);
|
||||||
|
if (haveContract && stub instanceof KotlinFunctionStubImpl) {
|
||||||
|
((KotlinFunctionStubImpl) stub).serializeContract(dataStream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -84,10 +89,9 @@ public class KtFunctionElementType extends KtStubElementType<KotlinFunctionStub,
|
|||||||
boolean hasBody = dataStream.readBoolean();
|
boolean hasBody = dataStream.readBoolean();
|
||||||
boolean hasTypeParameterListBeforeFunctionName = dataStream.readBoolean();
|
boolean hasTypeParameterListBeforeFunctionName = dataStream.readBoolean();
|
||||||
boolean mayHaveContract = dataStream.readBoolean();
|
boolean mayHaveContract = dataStream.readBoolean();
|
||||||
|
|
||||||
return new KotlinFunctionStubImpl(
|
return new KotlinFunctionStubImpl(
|
||||||
(StubElement<?>) parentStub, name, isTopLevel, fqName, isExtension, hasBlockBody, hasBody,
|
(StubElement<?>) parentStub, name, isTopLevel, fqName, isExtension, hasBlockBody, hasBody,
|
||||||
hasTypeParameterListBeforeFunctionName, mayHaveContract
|
hasTypeParameterListBeforeFunctionName, mayHaveContract, mayHaveContract ? KotlinFunctionStubImpl.Companion.deserializeContract(dataStream) : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class KtUserTypeElementType extends KtStubElementType<KotlinUserTypeStub,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void serializeType(@NotNull StubOutputStream dataStream, @Nullable KotlinTypeBean type) throws IOException {
|
public static void serializeType(@NotNull StubOutputStream dataStream, @Nullable KotlinTypeBean type) throws IOException {
|
||||||
dataStream.writeInt(KotlinTypeBeanKind.fromBean(type).ordinal());
|
dataStream.writeInt(KotlinTypeBeanKind.fromBean(type).ordinal());
|
||||||
if (type instanceof KotlinClassTypeBean) {
|
if (type instanceof KotlinClassTypeBean) {
|
||||||
StubUtils.serializeClassId(dataStream, ((KotlinClassTypeBean) type).getClassId());
|
StubUtils.serializeClassId(dataStream, ((KotlinClassTypeBean) type).getClassId());
|
||||||
@@ -94,7 +94,7 @@ public class KtUserTypeElementType extends KtStubElementType<KotlinUserTypeStub,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static KotlinTypeBean deserializeType(@NotNull StubInputStream dataStream) throws IOException {
|
public static KotlinTypeBean deserializeType(@NotNull StubInputStream dataStream) throws IOException {
|
||||||
KotlinTypeBeanKind typeKind = KotlinTypeBeanKind.values()[dataStream.readInt()];
|
KotlinTypeBeanKind typeKind = KotlinTypeBeanKind.values()[dataStream.readInt()];
|
||||||
switch (typeKind) {
|
switch (typeKind) {
|
||||||
case CLASS: {
|
case CLASS: {
|
||||||
|
|||||||
+154
-1
@@ -7,12 +7,165 @@ package org.jetbrains.kotlin.psi.stubs.impl
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.stubs.StubElement
|
import com.intellij.psi.stubs.StubElement
|
||||||
|
import com.intellij.psi.stubs.StubInputStream
|
||||||
|
import com.intellij.psi.stubs.StubOutputStream
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
import org.jetbrains.kotlin.psi.KtContractEffect
|
import org.jetbrains.kotlin.psi.KtContractEffect
|
||||||
import org.jetbrains.kotlin.psi.stubs.KotlinContractEffectStub
|
import org.jetbrains.kotlin.psi.stubs.KotlinContractEffectStub
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtContractEffectElementType
|
import org.jetbrains.kotlin.psi.stubs.elements.KtContractEffectElementType
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.elements.KtUserTypeElementType.deserializeType
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.elements.KtUserTypeElementType.serializeType
|
||||||
|
|
||||||
class KotlinContractEffectStubImpl(
|
class KotlinContractEffectStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
elementType: KtContractEffectElementType
|
elementType: KtContractEffectElementType
|
||||||
) : KotlinPlaceHolderStubImpl<KtContractEffect>(parent, elementType), KotlinContractEffectStub {
|
) : KotlinPlaceHolderStubImpl<KtContractEffect>(parent, elementType), KotlinContractEffectStub
|
||||||
|
|
||||||
|
enum class KotlinContractEffectType {
|
||||||
|
CALLS {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtCallsEffectDeclaration<KotlinTypeBean, Nothing?> {
|
||||||
|
val declaration = PARAMETER_REFERENCE.deserialize(dataStream)
|
||||||
|
val range = EventOccurrencesRange.values()[dataStream.readInt()]
|
||||||
|
return KtCallsEffectDeclaration(declaration as KtValueParameterReference, range)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RETURNS {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
|
||||||
|
return KtReturnsEffectDeclaration(CONSTANT.deserialize(dataStream) as KtConstantReference)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CONDITIONAL {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
|
||||||
|
val descriptionElement = values()[dataStream.readInt()].deserialize(dataStream)
|
||||||
|
val condition = values()[dataStream.readInt()].deserialize(dataStream)
|
||||||
|
return KtConditionalEffectDeclaration(
|
||||||
|
descriptionElement as KtEffectDeclaration,
|
||||||
|
condition as KtBooleanExpression
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IS_NULL {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
|
||||||
|
return KtIsNullPredicate(
|
||||||
|
PARAMETER_REFERENCE.deserialize(dataStream) as KtValueParameterReference,
|
||||||
|
dataStream.readBoolean()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IS_INSTANCE {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
|
||||||
|
return KtIsInstancePredicate(
|
||||||
|
PARAMETER_REFERENCE.deserialize(dataStream) as KtValueParameterReference,
|
||||||
|
deserializeType(dataStream)!!,
|
||||||
|
dataStream.readBoolean()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NOT {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
|
||||||
|
return KtLogicalNot(values()[dataStream.readInt()].deserialize(dataStream) as KtBooleanExpression)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BOOLEAN_LOGIC {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
|
||||||
|
val kind = if (dataStream.readBoolean()) LogicOperationKind.AND else LogicOperationKind.OR
|
||||||
|
val left = values()[dataStream.readInt()].deserialize(dataStream) as KtBooleanExpression
|
||||||
|
val right = values()[dataStream.readInt()].deserialize(dataStream) as KtBooleanExpression
|
||||||
|
return KtBinaryLogicExpression(left, right, kind)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PARAMETER_REFERENCE {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtValueParameterReference<KotlinTypeBean, Nothing?> {
|
||||||
|
return KtValueParameterReference(dataStream.readInt(), IGNORE_REFERENCE_PARAMETER_NAME)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CONSTANT {
|
||||||
|
override fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?> {
|
||||||
|
return when (val str = dataStream.readNameString()!!) {
|
||||||
|
"TRUE" -> KotlinContractConstantValues.TRUE
|
||||||
|
"FALSE" -> KotlinContractConstantValues.FALSE
|
||||||
|
"NULL" -> KotlinContractConstantValues.NULL
|
||||||
|
"NOT_NULL" -> KotlinContractConstantValues.NOT_NULL
|
||||||
|
"WILDCARD" -> KotlinContractConstantValues.WILDCARD
|
||||||
|
else -> error("Unexpected $str")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract fun deserialize(dataStream: StubInputStream): KtContractDescriptionElement<KotlinTypeBean, Nothing?>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val IGNORE_REFERENCE_PARAMETER_NAME = "<ignore>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinContractSerializationVisitor(val dataStream: StubOutputStream) :
|
||||||
|
KtContractDescriptionVisitor<Unit, Nothing?, KotlinTypeBean, Nothing?>() {
|
||||||
|
override fun visitConditionalEffectDeclaration(
|
||||||
|
conditionalEffect: KtConditionalEffectDeclaration<KotlinTypeBean, Nothing?>,
|
||||||
|
data: Nothing?
|
||||||
|
) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.CONDITIONAL.ordinal)
|
||||||
|
conditionalEffect.effect.accept(this, data)
|
||||||
|
conditionalEffect.condition.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturnsEffectDeclaration(returnsEffect: KtReturnsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.RETURNS.ordinal)
|
||||||
|
returnsEffect.value.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.CALLS.ordinal)
|
||||||
|
callsEffect.valueParameterReference.accept(this, data)
|
||||||
|
dataStream.writeInt(callsEffect.kind.ordinal)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLogicalBinaryOperationContractExpression(
|
||||||
|
binaryLogicExpression: KtBinaryLogicExpression<KotlinTypeBean, Nothing?>,
|
||||||
|
data: Nothing?
|
||||||
|
) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.BOOLEAN_LOGIC.ordinal)
|
||||||
|
dataStream.writeBoolean(binaryLogicExpression.kind == LogicOperationKind.AND)
|
||||||
|
binaryLogicExpression.left.accept(this, data)
|
||||||
|
binaryLogicExpression.right.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLogicalNot(logicalNot: KtLogicalNot<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.NOT.ordinal)
|
||||||
|
logicalNot.arg.accept(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsInstancePredicate(isInstancePredicate: KtIsInstancePredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.IS_INSTANCE.ordinal)
|
||||||
|
isInstancePredicate.arg.accept(this, data)
|
||||||
|
serializeType(dataStream, isInstancePredicate.type)
|
||||||
|
dataStream.writeBoolean(isInstancePredicate.isNegated)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsNullPredicate(isNullPredicate: KtIsNullPredicate<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.IS_NULL.ordinal)
|
||||||
|
isNullPredicate.arg.accept(this, data)
|
||||||
|
dataStream.writeBoolean(isNullPredicate.isNegated)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun visitConstantDescriptor(constantReference: KtConstantReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.CONSTANT.ordinal)
|
||||||
|
dataStream.writeName(constantReference.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitValueParameterReference(valueParameterReference: KtValueParameterReference<KotlinTypeBean, Nothing?>, data: Nothing?) {
|
||||||
|
dataStream.writeInt(KotlinContractEffectType.PARAMETER_REFERENCE.ordinal)
|
||||||
|
dataStream.writeInt(valueParameterReference.parameterIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KotlinContractConstantValues {
|
||||||
|
val NULL = KtConstantReference<KotlinTypeBean, Nothing?>("NULL")
|
||||||
|
val WILDCARD = KtConstantReference<KotlinTypeBean, Nothing?>("WILDCARD")
|
||||||
|
val NOT_NULL = KtConstantReference<KotlinTypeBean, Nothing?>("NOT_NULL")
|
||||||
|
|
||||||
|
val TRUE = KtBooleanConstantReference<KotlinTypeBean, Nothing?>("TRUE")
|
||||||
|
val FALSE = KtBooleanConstantReference<KotlinTypeBean, Nothing?>("FALSE")
|
||||||
}
|
}
|
||||||
@@ -16,13 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi.stubs.impl
|
package org.jetbrains.kotlin.psi.stubs.impl
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.stubs.StubElement
|
import com.intellij.psi.stubs.StubElement
|
||||||
|
import com.intellij.psi.stubs.StubInputStream
|
||||||
|
import com.intellij.psi.stubs.StubOutputStream
|
||||||
import com.intellij.util.io.StringRef
|
import com.intellij.util.io.StringRef
|
||||||
|
import org.jetbrains.kotlin.contracts.description.KtContractDescriptionElement
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
import org.jetbrains.kotlin.psi.stubs.KotlinFunctionStub
|
import org.jetbrains.kotlin.psi.stubs.KotlinFunctionStub
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import java.io.IOException
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
|
|
||||||
class KotlinFunctionStubImpl(
|
class KotlinFunctionStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
@@ -33,7 +37,8 @@ class KotlinFunctionStubImpl(
|
|||||||
private val hasBlockBody: Boolean,
|
private val hasBlockBody: Boolean,
|
||||||
private val hasBody: Boolean,
|
private val hasBody: Boolean,
|
||||||
private val hasTypeParameterListBeforeFunctionName: Boolean,
|
private val hasTypeParameterListBeforeFunctionName: Boolean,
|
||||||
private val mayHaveContract: Boolean
|
private val mayHaveContract: Boolean,
|
||||||
|
val contract: List<KtContractDescriptionElement<KotlinTypeBean, Nothing?>>?
|
||||||
) : KotlinStubBaseImpl<KtNamedFunction>(parent, KtStubElementTypes.FUNCTION), KotlinFunctionStub {
|
) : KotlinStubBaseImpl<KtNamedFunction>(parent, KtStubElementTypes.FUNCTION), KotlinFunctionStub {
|
||||||
init {
|
init {
|
||||||
if (isTopLevel && fqName == null) {
|
if (isTopLevel && fqName == null) {
|
||||||
@@ -50,4 +55,24 @@ class KotlinFunctionStubImpl(
|
|||||||
override fun hasBody() = hasBody
|
override fun hasBody() = hasBody
|
||||||
override fun hasTypeParameterListBeforeFunctionName() = hasTypeParameterListBeforeFunctionName
|
override fun hasTypeParameterListBeforeFunctionName() = hasTypeParameterListBeforeFunctionName
|
||||||
override fun mayHaveContract(): Boolean = mayHaveContract
|
override fun mayHaveContract(): Boolean = mayHaveContract
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun serializeContract(dataStream: StubOutputStream) {
|
||||||
|
val effects: List<KtContractDescriptionElement<KotlinTypeBean, Nothing?>>? = contract
|
||||||
|
dataStream.writeInt(effects?.size ?: 0)
|
||||||
|
val visitor = KotlinContractSerializationVisitor(dataStream)
|
||||||
|
effects?.forEach { it.accept(visitor, null) }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun deserializeContract(dataStream: StubInputStream): List<KtContractDescriptionElement<KotlinTypeBean, Nothing?>> {
|
||||||
|
val effects = mutableListOf<KtContractDescriptionElement<KotlinTypeBean, Nothing?>>()
|
||||||
|
val count: Int = dataStream.readInt()
|
||||||
|
for (i in 0 until count) {
|
||||||
|
val effectType: KotlinContractEffectType = KotlinContractEffectType.values()[dataStream.readInt()]
|
||||||
|
effects.add(effectType.deserialize(dataStream))
|
||||||
|
}
|
||||||
|
return effects
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.contracts.description
|
||||||
|
|
||||||
|
interface KtContractDescriptionElement<Type, Diagnostic> {
|
||||||
|
fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R
|
||||||
|
|
||||||
|
val erroneous: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class KtEffectDeclaration<Type, Diagnostic> : KtContractDescriptionElement<Type, Diagnostic> {
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitEffectDeclaration(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KtBooleanExpression<Type, Diagnostic> : KtContractDescriptionElement<Type, Diagnostic> {
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitBooleanExpression(this, data)
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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.contracts.description
|
||||||
|
|
||||||
|
|
||||||
|
abstract class KtContractDescriptionVisitor<out R, in D, Type, Diagnostic> {
|
||||||
|
open fun visitContractDescriptionElement(contractDescriptionElement: KtContractDescriptionElement<Type, Diagnostic>, data: D): R {
|
||||||
|
throw IllegalStateException("Top of hierarchy reached, no overloads were found for element: $contractDescriptionElement")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Effects
|
||||||
|
open fun visitEffectDeclaration(effectDeclaration: KtEffectDeclaration<Type, Diagnostic>, data: D): R = visitContractDescriptionElement(effectDeclaration, data)
|
||||||
|
|
||||||
|
open fun visitConditionalEffectDeclaration(conditionalEffect: KtConditionalEffectDeclaration<Type, Diagnostic>, data: D): R =
|
||||||
|
visitEffectDeclaration(conditionalEffect, data)
|
||||||
|
|
||||||
|
open fun visitReturnsEffectDeclaration(returnsEffect: KtReturnsEffectDeclaration<Type, Diagnostic>, data: D): R =
|
||||||
|
visitEffectDeclaration(returnsEffect, data)
|
||||||
|
|
||||||
|
open fun visitCallsEffectDeclaration(callsEffect: KtCallsEffectDeclaration<Type, Diagnostic>, data: D): R =
|
||||||
|
visitEffectDeclaration(callsEffect, data)
|
||||||
|
|
||||||
|
open fun visitErroneousCallsEffectDeclaration(callsEffect: KtErroneousCallsEffectDeclaration<Type, Diagnostic>, data: D): R =
|
||||||
|
visitCallsEffectDeclaration(callsEffect, data)
|
||||||
|
|
||||||
|
// Expressions
|
||||||
|
open fun visitBooleanExpression(booleanExpression: KtBooleanExpression<Type, Diagnostic>, data: D): R =
|
||||||
|
visitContractDescriptionElement(booleanExpression, data)
|
||||||
|
|
||||||
|
open fun visitLogicalBinaryOperationContractExpression(binaryLogicExpression: KtBinaryLogicExpression<Type, Diagnostic>, data: D): R =
|
||||||
|
visitBooleanExpression(binaryLogicExpression, data)
|
||||||
|
|
||||||
|
open fun visitLogicalNot(logicalNot: KtLogicalNot<Type, Diagnostic>, data: D): R = visitBooleanExpression(logicalNot, data)
|
||||||
|
|
||||||
|
open fun visitIsInstancePredicate(isInstancePredicate: KtIsInstancePredicate<Type, Diagnostic>, data: D): R =
|
||||||
|
visitBooleanExpression(isInstancePredicate, data)
|
||||||
|
|
||||||
|
open fun visitErroneousIsInstancePredicate(isInstancePredicate: KtErroneousIsInstancePredicate<Type, Diagnostic>, data: D): R =
|
||||||
|
visitIsInstancePredicate(isInstancePredicate, data)
|
||||||
|
|
||||||
|
open fun visitIsNullPredicate(isNullPredicate: KtIsNullPredicate<Type, Diagnostic>, data: D): R = visitBooleanExpression(isNullPredicate, data)
|
||||||
|
|
||||||
|
// Values
|
||||||
|
open fun visitValue(value: KtContractDescriptionValue<Type, Diagnostic>, data: D): R = visitContractDescriptionElement(value, data)
|
||||||
|
|
||||||
|
open fun visitConstantDescriptor(constantReference: KtConstantReference<Type, Diagnostic>, data: D): R = visitValue(constantReference, data)
|
||||||
|
|
||||||
|
open fun visitBooleanConstantDescriptor(booleanConstantDescriptor: KtBooleanConstantReference<Type, Diagnostic>, data: D): R =
|
||||||
|
visitConstantDescriptor(booleanConstantDescriptor, data)
|
||||||
|
|
||||||
|
open fun visitErroneousConstantReference(erroneousConstantReference: KtErroneousConstantReference<Type, Diagnostic>, data: D): R =
|
||||||
|
visitConstantDescriptor(erroneousConstantReference, data)
|
||||||
|
|
||||||
|
open fun visitValueParameterReference(valueParameterReference: KtValueParameterReference<Type, Diagnostic>, data: D): R =
|
||||||
|
visitValue(valueParameterReference, data)
|
||||||
|
|
||||||
|
open fun visitBooleanValueParameterReference(booleanValueParameterReference: KtBooleanValueParameterReference<Type, Diagnostic>, data: D): R =
|
||||||
|
visitValueParameterReference(booleanValueParameterReference, data)
|
||||||
|
|
||||||
|
open fun visitErroneousValueParameterReference(valueParameterReference: KtErroneousValueParameterReference<Type, Diagnostic>, data: D): R =
|
||||||
|
visitValueParameterReference(valueParameterReference, data)
|
||||||
|
|
||||||
|
// Error
|
||||||
|
open fun visitErroneousElement(element: KtErroneousContractElement<Type, Diagnostic>, data: D): R =
|
||||||
|
visitContractDescriptionElement(element, data)
|
||||||
|
}
|
||||||
+19
-18
@@ -1,12 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* 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
|
package org.jetbrains.kotlin.contracts.description
|
||||||
|
|
||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Effect with condition attached to it.
|
* Effect with condition attached to it.
|
||||||
@@ -22,11 +19,14 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
|||||||
* - if [effect] wasn't observed, we *can't* reason that [condition] is false
|
* - if [effect] wasn't observed, we *can't* reason that [condition] is false
|
||||||
* - if [condition] is true, we *can't* reason that [effect] will be observed.
|
* - if [condition] is true, we *can't* reason that [effect] will be observed.
|
||||||
*/
|
*/
|
||||||
class ConeConditionalEffectDeclaration(val effect: ConeEffectDeclaration, val condition: ConeBooleanExpression) : ConeEffectDeclaration() {
|
class KtConditionalEffectDeclaration<Type, Diagnostic>(
|
||||||
|
val effect: KtEffectDeclaration<Type, Diagnostic>,
|
||||||
|
val condition: KtBooleanExpression<Type, Diagnostic>
|
||||||
|
) : KtEffectDeclaration<Type, Diagnostic>() {
|
||||||
override val erroneous: Boolean
|
override val erroneous: Boolean
|
||||||
get() = effect.erroneous || condition.erroneous
|
get() = effect.erroneous || condition.erroneous
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
contractDescriptionVisitor.visitConditionalEffectDeclaration(this, data)
|
contractDescriptionVisitor.visitConditionalEffectDeclaration(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,11 +34,12 @@ class ConeConditionalEffectDeclaration(val effect: ConeEffectDeclaration, val co
|
|||||||
/**
|
/**
|
||||||
* Effect which specifies that subroutine returns some particular value
|
* Effect which specifies that subroutine returns some particular value
|
||||||
*/
|
*/
|
||||||
class ConeReturnsEffectDeclaration(val value: ConeConstantReference) : ConeEffectDeclaration() {
|
class KtReturnsEffectDeclaration<Type, Diagnostic>(val value: KtConstantReference<Type, Diagnostic>) :
|
||||||
|
KtEffectDeclaration<Type, Diagnostic>() {
|
||||||
override val erroneous: Boolean
|
override val erroneous: Boolean
|
||||||
get() = value.erroneous
|
get() = value.erroneous
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
contractDescriptionVisitor.visitReturnsEffectDeclaration(this, data)
|
contractDescriptionVisitor.visitReturnsEffectDeclaration(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,24 +48,24 @@ class ConeReturnsEffectDeclaration(val value: ConeConstantReference) : ConeEffec
|
|||||||
* Effect which specifies, that during execution of subroutine, callable [valueParameterReference] will be invoked
|
* 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.
|
* [kind] amount of times, and will never be invoked after subroutine call is finished.
|
||||||
*/
|
*/
|
||||||
open class ConeCallsEffectDeclaration(
|
open class KtCallsEffectDeclaration<Type, Diagnostic>(
|
||||||
val valueParameterReference: ConeValueParameterReference,
|
val valueParameterReference: KtValueParameterReference<Type, Diagnostic>,
|
||||||
val kind: EventOccurrencesRange
|
val kind: EventOccurrencesRange
|
||||||
) : ConeEffectDeclaration() {
|
) : KtEffectDeclaration<Type, Diagnostic>() {
|
||||||
override val erroneous: Boolean
|
override val erroneous: Boolean
|
||||||
get() = valueParameterReference.erroneous
|
get() = valueParameterReference.erroneous
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
contractDescriptionVisitor.visitCallsEffectDeclaration(this, data)
|
contractDescriptionVisitor.visitCallsEffectDeclaration(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConeErroneousCallsEffectDeclaration(
|
class KtErroneousCallsEffectDeclaration<Type, Diagnostic>(
|
||||||
valueParameterReference: ConeValueParameterReference,
|
valueParameterReference: KtValueParameterReference<Type, Diagnostic>,
|
||||||
val diagnostic: ConeDiagnostic
|
val diagnostic: Diagnostic
|
||||||
) : ConeCallsEffectDeclaration(valueParameterReference, EventOccurrencesRange.UNKNOWN) {
|
) : KtCallsEffectDeclaration<Type, Diagnostic>(valueParameterReference, EventOccurrencesRange.UNKNOWN) {
|
||||||
override val erroneous: Boolean
|
override val erroneous: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|
||||||
override fun <R, D> accept(contractDescriptionVisitor: ConeContractDescriptionVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
contractDescriptionVisitor.visitErroneousCallsEffectDeclaration(this, data)
|
contractDescriptionVisitor.visitErroneousCallsEffectDeclaration(this, data)
|
||||||
}
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* 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.contracts.description
|
||||||
|
|
||||||
|
class KtErroneousContractElement<Type, Diagnostic>(
|
||||||
|
val diagnostic: Diagnostic
|
||||||
|
) : KtEffectDeclaration<Type, Diagnostic>(), KtBooleanExpression<Type, Diagnostic>, KtContractDescriptionValue<Type, Diagnostic> {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R {
|
||||||
|
return contractDescriptionVisitor.visitErroneousElement(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.contracts.description
|
||||||
|
|
||||||
|
class KtBinaryLogicExpression<Type, Diagnostic>(
|
||||||
|
val left: KtBooleanExpression<Type, Diagnostic>,
|
||||||
|
val right: KtBooleanExpression<Type, Diagnostic>,
|
||||||
|
val kind: LogicOperationKind
|
||||||
|
) : KtBooleanExpression<Type, Diagnostic> {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = left.erroneous || right.erroneous
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R {
|
||||||
|
return contractDescriptionVisitor.visitLogicalBinaryOperationContractExpression(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtLogicalNot<Type, Diagnostic>(val arg: KtBooleanExpression<Type, Diagnostic>) : KtBooleanExpression<Type, Diagnostic> {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = arg.erroneous
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitLogicalNot(this, data)
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.contracts.description
|
||||||
|
|
||||||
|
open class KtIsInstancePredicate<Type, Diagnostic>(val arg: KtValueParameterReference<Type, Diagnostic>, val type: Type, val isNegated: Boolean) :
|
||||||
|
KtBooleanExpression<Type, Diagnostic> {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = arg.erroneous
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitIsInstancePredicate(this, data)
|
||||||
|
|
||||||
|
fun negated(): KtIsInstancePredicate<Type, Diagnostic> =
|
||||||
|
KtIsInstancePredicate(arg, type, isNegated.not())
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtErroneousIsInstancePredicate<Type, Diagnostic>(
|
||||||
|
arg: KtValueParameterReference<Type, Diagnostic>,
|
||||||
|
type: Type,
|
||||||
|
isNegated: Boolean,
|
||||||
|
val diagnostic: Diagnostic
|
||||||
|
) : KtIsInstancePredicate<Type, Diagnostic>(arg, type, isNegated) {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitErroneousIsInstancePredicate(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtIsNullPredicate<Type, Diagnostic>(val arg: KtValueParameterReference<Type, Diagnostic>, val isNegated: Boolean) :
|
||||||
|
KtBooleanExpression<Type, Diagnostic> {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = arg.erroneous
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitIsNullPredicate(this, data)
|
||||||
|
|
||||||
|
fun negated(): KtIsNullPredicate<Type, Diagnostic> =
|
||||||
|
KtIsNullPredicate(arg, isNegated.not())
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.contracts.description
|
||||||
|
|
||||||
|
interface KtContractDescriptionValue<Type, Diagnostic> : KtContractDescriptionElement<Type, Diagnostic> {
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitValue(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class KtConstantReference<Type, Diagnostic>(val name: String) : KtContractDescriptionValue<Type, Diagnostic> {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitConstantDescriptor(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtBooleanConstantReference<Type, Diagnostic>(name: String) : KtConstantReference<Type, Diagnostic>(name),
|
||||||
|
KtBooleanExpression<Type, Diagnostic> {
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitBooleanConstantDescriptor(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtErroneousConstantReference<Type, Diagnostic>(val diagnostic: Diagnostic) : KtConstantReference<Type, Diagnostic>("ERROR") {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitErroneousConstantReference(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Index of value parameter of function
|
||||||
|
* -1 means that it is reference to extension receiver
|
||||||
|
*/
|
||||||
|
open class KtValueParameterReference<Type, Diagnostic>(val parameterIndex: Int, val name: String) :
|
||||||
|
KtContractDescriptionValue<Type, Diagnostic> {
|
||||||
|
init {
|
||||||
|
assert(parameterIndex >= -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitValueParameterReference(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtBooleanValueParameterReference<Type, Diagnostic>(parameterIndex: Int, name: String) : KtValueParameterReference<Type, Diagnostic>(parameterIndex, name),
|
||||||
|
KtBooleanExpression<Type, Diagnostic> {
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitBooleanValueParameterReference(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
class KtErroneousValueParameterReference<Type, Diagnostic>(val diagnostic: Diagnostic) : KtValueParameterReference<Type, Diagnostic>(Int.MAX_VALUE, "ERROR") {
|
||||||
|
override val erroneous: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override fun <R, D> accept(contractDescriptionVisitor: KtContractDescriptionVisitor<R, D, Type, Diagnostic>, data: D): R =
|
||||||
|
contractDescriptionVisitor.visitErroneousValueParameterReference(this, data)
|
||||||
|
}
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* 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.expressions
|
package org.jetbrains.kotlin.contracts.description
|
||||||
|
|
||||||
enum class LogicOperationKind(val token: String) {
|
enum class LogicOperationKind(val token: String) {
|
||||||
AND("&&"), OR("||")
|
AND("&&"), OR("||")
|
||||||
}
|
}
|
||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* 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.serialization.deserialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
|
abstract class ProtoBufContractDeserializer<Type, Diagnostic, Owner> {
|
||||||
|
protected fun loadPossiblyConditionalEffect(
|
||||||
|
proto: ProtoBuf.Effect,
|
||||||
|
owner: Owner
|
||||||
|
): KtEffectDeclaration<Type, Diagnostic>? {
|
||||||
|
if (proto.hasConclusionOfConditionalEffect()) {
|
||||||
|
val conclusion = loadExpression(proto.conclusionOfConditionalEffect, owner) ?: return null
|
||||||
|
val effect = loadSimpleEffect(proto, owner) ?: return null
|
||||||
|
return KtConditionalEffectDeclaration(effect, conclusion)
|
||||||
|
}
|
||||||
|
return loadSimpleEffect(proto, owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadSimpleEffect(proto: ProtoBuf.Effect, owner: Owner): KtEffectDeclaration<Type, Diagnostic>? {
|
||||||
|
val type: ProtoBuf.Effect.EffectType = if (proto.hasEffectType()) proto.effectType else return null
|
||||||
|
return when(type) {
|
||||||
|
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> {
|
||||||
|
val argument = proto.effectConstructorArgumentList.firstOrNull()
|
||||||
|
val returnValue = if (argument == null) {
|
||||||
|
getWildcard()
|
||||||
|
} else {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
loadExpression(argument, owner) as? KtConstantReference<Type, Diagnostic> ?: return null
|
||||||
|
}
|
||||||
|
KtReturnsEffectDeclaration(returnValue)
|
||||||
|
}
|
||||||
|
ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL -> {
|
||||||
|
KtReturnsEffectDeclaration(getNotNull())
|
||||||
|
}
|
||||||
|
ProtoBuf.Effect.EffectType.CALLS -> {
|
||||||
|
val argument = proto.effectConstructorArgumentList.firstOrNull() ?: return null
|
||||||
|
val callable = extractVariable(argument, owner) ?: return null
|
||||||
|
val invocationKind = if (proto.hasKind())
|
||||||
|
proto.kind.toDescriptorInvocationKind()
|
||||||
|
else
|
||||||
|
EventOccurrencesRange.UNKNOWN
|
||||||
|
KtCallsEffectDeclaration(callable, invocationKind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadExpression(proto: ProtoBuf.Expression, owner: Owner): KtBooleanExpression<Type, Diagnostic>? {
|
||||||
|
val primitiveType = getPrimitiveType(proto)
|
||||||
|
val primitiveExpression = extractPrimitiveExpression(proto, primitiveType, owner)
|
||||||
|
|
||||||
|
val complexType = getComplexType(proto)
|
||||||
|
val childs: MutableList<KtBooleanExpression<Type, Diagnostic>> = mutableListOf()
|
||||||
|
childs.addIfNotNull(primitiveExpression)
|
||||||
|
|
||||||
|
return when (complexType) {
|
||||||
|
ComplexExpressionType.AND_SEQUENCE -> {
|
||||||
|
proto.andArgumentList.mapTo(childs) { loadExpression(it, owner) ?: return null }
|
||||||
|
childs.reduce { acc, booleanExpression -> KtBinaryLogicExpression(acc, booleanExpression, LogicOperationKind.AND) }
|
||||||
|
}
|
||||||
|
|
||||||
|
ComplexExpressionType.OR_SEQUENCE -> {
|
||||||
|
proto.orArgumentList.mapTo(childs) { loadExpression(it, owner) ?: return null }
|
||||||
|
childs.reduce { acc, booleanExpression -> KtBinaryLogicExpression(acc, booleanExpression, LogicOperationKind.OR) }
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> primitiveExpression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractPrimitiveExpression(proto: ProtoBuf.Expression, primitiveType: PrimitiveExpressionType?, owner: Owner): KtBooleanExpression<Type, Diagnostic>? {
|
||||||
|
val isInverted = Flags.IS_NEGATED.get(proto.flags)
|
||||||
|
|
||||||
|
return when (primitiveType) {
|
||||||
|
PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE, PrimitiveExpressionType.RECEIVER_REFERENCE -> {
|
||||||
|
(extractVariable(proto, owner) as? KtBooleanValueParameterReference<Type, Diagnostic>?)?.invertIfNecessary(isInverted)
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimitiveExpressionType.CONSTANT ->
|
||||||
|
(loadConstant(proto.constantValue) as? KtBooleanConstantReference<Type, Diagnostic>)?.invertIfNecessary(isInverted)
|
||||||
|
|
||||||
|
PrimitiveExpressionType.INSTANCE_CHECK -> {
|
||||||
|
val variable = extractVariable(proto, owner) ?: return null
|
||||||
|
val type = extractType(proto) ?: return null
|
||||||
|
KtIsInstancePredicate(variable, type, isInverted)
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimitiveExpressionType.NULLABILITY_CHECK -> {
|
||||||
|
val variable = extractVariable(proto, owner) ?: return null
|
||||||
|
KtIsNullPredicate(variable, isInverted)
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtBooleanExpression<Type, Diagnostic>.invertIfNecessary(shouldInvert: Boolean): KtBooleanExpression<Type, Diagnostic> =
|
||||||
|
if (shouldInvert) KtLogicalNot(this) else this
|
||||||
|
|
||||||
|
private fun extractVariable(proto: ProtoBuf.Expression, owner: Owner): KtValueParameterReference<Type, Diagnostic>? {
|
||||||
|
if (!proto.hasValueParameterReference()) return null
|
||||||
|
|
||||||
|
return extractVariable(proto.valueParameterReference - 1, owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): EventOccurrencesRange = when (this) {
|
||||||
|
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> EventOccurrencesRange.AT_MOST_ONCE
|
||||||
|
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> EventOccurrencesRange.EXACTLY_ONCE
|
||||||
|
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> EventOccurrencesRange.AT_LEAST_ONCE
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun extractVariable(valueParameterIndex: Int, owner: Owner): KtValueParameterReference<Type, Diagnostic>?
|
||||||
|
|
||||||
|
abstract fun extractType(proto: ProtoBuf.Expression): Type?
|
||||||
|
|
||||||
|
abstract fun loadConstant(value: ProtoBuf.Expression.ConstantValue): KtConstantReference<Type, Diagnostic>
|
||||||
|
|
||||||
|
|
||||||
|
abstract fun getNotNull(): KtConstantReference<Type, Diagnostic>
|
||||||
|
|
||||||
|
abstract fun getWildcard(): KtConstantReference<Type, Diagnostic>
|
||||||
|
|
||||||
|
|
||||||
|
private fun getComplexType(proto: ProtoBuf.Expression): ComplexExpressionType? {
|
||||||
|
val isOrSequence = proto.orArgumentCount != 0
|
||||||
|
val isAndSequence = proto.andArgumentCount != 0
|
||||||
|
return when {
|
||||||
|
isOrSequence && isAndSequence -> null
|
||||||
|
isOrSequence -> ComplexExpressionType.OR_SEQUENCE
|
||||||
|
isAndSequence -> ComplexExpressionType.AND_SEQUENCE
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPrimitiveType(proto: ProtoBuf.Expression): PrimitiveExpressionType? {
|
||||||
|
// Expected to be one element, but can be empty (unknown expression) or contain several elements (invalid data)
|
||||||
|
val expressionTypes: MutableList<PrimitiveExpressionType> = mutableListOf()
|
||||||
|
|
||||||
|
// Check for predicates
|
||||||
|
when {
|
||||||
|
proto.hasValueParameterReference() && proto.hasType() ->
|
||||||
|
expressionTypes.add(PrimitiveExpressionType.INSTANCE_CHECK)
|
||||||
|
|
||||||
|
proto.hasValueParameterReference() && Flags.IS_NULL_CHECK_PREDICATE.get(proto.flags) ->
|
||||||
|
expressionTypes.add(PrimitiveExpressionType.NULLABILITY_CHECK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If message contains correct predicate, then predicate's type overrides type of value,
|
||||||
|
// even is message has one
|
||||||
|
if (expressionTypes.isNotEmpty()) {
|
||||||
|
return expressionTypes.singleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, check if it is a value
|
||||||
|
when {
|
||||||
|
proto.hasValueParameterReference() && proto.valueParameterReference > 0 ->
|
||||||
|
expressionTypes.add(PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE)
|
||||||
|
|
||||||
|
proto.hasValueParameterReference() && proto.valueParameterReference == 0 ->
|
||||||
|
expressionTypes.add(PrimitiveExpressionType.RECEIVER_REFERENCE)
|
||||||
|
|
||||||
|
proto.hasConstantValue() -> expressionTypes.add(PrimitiveExpressionType.CONSTANT)
|
||||||
|
}
|
||||||
|
|
||||||
|
return expressionTypes.singleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ProtoBuf.Expression.hasType(): Boolean = this.hasIsInstanceType() || this.hasIsInstanceTypeId()
|
||||||
|
|
||||||
|
// Arguments of expressions with such types are never other expressions
|
||||||
|
private enum class PrimitiveExpressionType {
|
||||||
|
VALUE_PARAMETER_REFERENCE,
|
||||||
|
RECEIVER_REFERENCE,
|
||||||
|
CONSTANT,
|
||||||
|
INSTANCE_CHECK,
|
||||||
|
NULLABILITY_CHECK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expressions with such type can take other expressions as arguments.
|
||||||
|
// Additionally, for performance reasons, "complex expression" and "primitive expression"
|
||||||
|
// can co-exist in the one and the same message. If "primitive expression" is present
|
||||||
|
// in the current message, it is treated as the first argument of "complex expression".
|
||||||
|
private enum class ComplexExpressionType {
|
||||||
|
AND_SEQUENCE,
|
||||||
|
OR_SEQUENCE
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user