Allow use reference to reified type parameters in contracts since 1.4

This commit is contained in:
Dmitriy Novozhilov
2019-12-26 13:08:32 +03:00
parent 9c1b68f839
commit 5dfe100ae5
32 changed files with 232 additions and 47 deletions
@@ -1385,6 +1385,11 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/receiver.kt");
}
@TestMetadata("reifiedGeneric.kt")
public void testReifiedGeneric() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.kt");
}
@TestMetadata("safecallAndReturnsNull.kt")
public void testSafecallAndReturnsNull() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/safecallAndReturnsNull.kt");
@@ -20,10 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.model.Computation
import org.jetbrains.kotlin.contracts.model.ConditionalEffect
import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.Functor
import org.jetbrains.kotlin.contracts.model.*
import org.jetbrains.kotlin.contracts.model.functors.*
import org.jetbrains.kotlin.contracts.model.structure.*
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
@@ -71,12 +68,13 @@ class EffectsExtractingVisitor(
if (resolvedCall.isCallWithUnsupportedReceiver()) return UNKNOWN_COMPUTATION
val arguments = resolvedCall.getCallArgumentsAsComputations() ?: return UNKNOWN_COMPUTATION
val typeSubstitution = resolvedCall.getTypeSubstitution()
val descriptor = resolvedCall.resultingDescriptor
return when {
descriptor.isEqualsDescriptor() -> CallComputation(
ESBooleanType,
EqualsFunctor(false).invokeWithArguments(arguments, reducer)
EqualsFunctor(false).invokeWithArguments(arguments, typeSubstitution, reducer)
)
descriptor is ValueDescriptor -> ESVariableWithDataFlowValue(
descriptor,
@@ -86,7 +84,7 @@ class EffectsExtractingVisitor(
val esType = descriptor.returnType?.toESType()
CallComputation(
esType,
descriptor.getFunctor()?.invokeWithArguments(arguments, reducer) ?: emptyList()
descriptor.getFunctor()?.invokeWithArguments(arguments, typeSubstitution, reducer) ?: emptyList()
)
}
else -> UNKNOWN_COMPUTATION
@@ -123,7 +121,7 @@ class EffectsExtractingVisitor(
val arg = extractOrGetCached(expression.leftHandSide)
return CallComputation(
ESBooleanType,
IsFunctor(rightType, expression.isNegated).invokeWithArguments(listOf(arg), reducer)
IsFunctor(rightType, expression.isNegated).invokeWithArguments(listOf(arg), emptyMap(), reducer)
)
}
@@ -148,10 +146,10 @@ class EffectsExtractingVisitor(
val args = listOf(left, right)
return when (expression.operationToken) {
KtTokens.EXCLEQ -> CallComputation(ESBooleanType, EqualsFunctor(true).invokeWithArguments(args, reducer))
KtTokens.EQEQ -> CallComputation(ESBooleanType, EqualsFunctor(false).invokeWithArguments(args, reducer))
KtTokens.ANDAND -> CallComputation(ESBooleanType, AndFunctor().invokeWithArguments(args, reducer))
KtTokens.OROR -> CallComputation(ESBooleanType, OrFunctor().invokeWithArguments(args, reducer))
KtTokens.EXCLEQ -> CallComputation(ESBooleanType, EqualsFunctor(true).invokeWithArguments(args, emptyMap(), reducer))
KtTokens.EQEQ -> CallComputation(ESBooleanType, EqualsFunctor(false).invokeWithArguments(args, emptyMap(), reducer))
KtTokens.ANDAND -> CallComputation(ESBooleanType, AndFunctor().invokeWithArguments(args, emptyMap(), reducer))
KtTokens.OROR -> CallComputation(ESBooleanType, OrFunctor().invokeWithArguments(args, emptyMap(), reducer))
else -> UNKNOWN_COMPUTATION
}
}
@@ -215,6 +213,14 @@ class EffectsExtractingVisitor(
return arguments
}
private fun ResolvedCall<*>.getTypeSubstitution(): ESTypeSubstitution {
val result = mutableMapOf<ESKotlinType, ESKotlinType>()
for ((typeParameter, typeArgument) in typeArguments) {
result[ESKotlinType(typeParameter.defaultType)] = ESKotlinType(typeArgument)
}
return result
}
private fun ResolvedValueArgument.toComputation(): Computation? {
return when (this) {
// Assume that we don't know anything about default arguments
@@ -16,14 +16,14 @@
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.ContractDescription
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.description.LazyContractProvider
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
@@ -46,7 +46,7 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
// is a *necessary* (but not sufficient, actually) condition for presence of 'LazyContractProvider'
if (!expression.isContractDescriptionCallPsiCheck()) return
val callContext = ContractCallContext(expression, scope, trace)
val callContext = ContractCallContext(expression, scope, trace, languageVersionSettings)
val contractProviderIfAny =
(scope.ownerDescriptor as? FunctionDescriptor)?.getUserData(ContractProviderKey) as? LazyContractProvider?
var resultingContractDescription: ContractDescription? = null
@@ -104,7 +104,8 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
class ContractCallContext(
val contractCallExpression: KtExpression,
val scope: LexicalScope,
val trace: BindingTrace
val trace: BindingTrace,
val languageVersionSettings: LanguageVersionSettings
) {
val ownerDescriptor: DeclarationDescriptor = scope.ownerDescriptor
val functionDescriptor: FunctionDescriptor = ownerDescriptor as FunctionDescriptor
@@ -16,7 +16,8 @@
package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.contracts.description.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.contracts.description.BooleanExpression
import org.jetbrains.kotlin.contracts.description.expressions.*
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.impl.AbstractTypeParameterDescriptor
@@ -47,8 +48,16 @@ internal class PsiConditionParser(
}
if (descriptor is AbstractTypeParameterDescriptor) {
collector.badDescription("references to type parameters are forbidden in contracts", typeReference)
return null
val reifiedGenericsAllowed = callContext.languageVersionSettings.supportsFeature(LanguageFeature.AllowReifiedGenericsInContracts)
if (!reifiedGenericsAllowed || !descriptor.isReified) {
val message = if (reifiedGenericsAllowed) {
"references to not reified type parameters are forbidden in contracts"
} else {
"references to type parameters are forbidden in contracts"
}
collector.badDescription(message, typeReference)
return null
}
}
// This should be reported as "Can't check for erased" error, but we explicitly abort contract parsing. Just in case.
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.contracts.model
import org.jetbrains.kotlin.contracts.model.structure.ESKotlinType
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
/**
@@ -27,13 +28,19 @@ import org.jetbrains.kotlin.contracts.model.visitors.Reducer
* values, it takes effects and returns effects.
*/
interface Functor {
fun invokeWithArguments(arguments: List<Computation>, reducer: Reducer): List<ESEffect>
fun invokeWithArguments(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect>
}
abstract class AbstractFunctor : Functor {
override fun invokeWithArguments(arguments: List<Computation>, reducer: Reducer): List<ESEffect> =
reducer.reduceEffects(doInvocation(arguments, reducer))
override fun invokeWithArguments(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> =
reducer.reduceEffects(doInvocation(arguments, typeSubstitution, reducer))
protected abstract fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect>
}
protected abstract fun doInvocation(
arguments: List<Computation>,
typeSubstitution: ESTypeSubstitution,
reducer: Reducer
): List<ESEffect>
}
typealias ESTypeSubstitution = Map<ESKotlinType, ESKotlinType>
@@ -17,11 +17,14 @@
package org.jetbrains.kotlin.contracts.model.functors
import org.jetbrains.kotlin.contracts.model.*
import org.jetbrains.kotlin.contracts.model.structure.*
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
import org.jetbrains.kotlin.contracts.model.structure.ESOr
import org.jetbrains.kotlin.contracts.model.structure.isReturns
import org.jetbrains.kotlin.contracts.model.structure.isWildcard
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
abstract class AbstractBinaryFunctor : AbstractFunctor() {
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
assert(arguments.size == 2) { "Wrong size of arguments list for Binary functor: expected 2, got ${arguments.size}" }
return invokeWithArguments(arguments[0], arguments[1])
}
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.contracts.model.visitors.Reducer
* be called only on clauses that haven't failed before reaching functor transformation.
*/
abstract class AbstractUnaryFunctor : AbstractFunctor() {
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
assert(arguments.size == 1) { "Wrong size of arguments list for Unary operator: expected 1, got ${arguments.size}" }
return invokeWithArguments(arguments[0])
}
@@ -38,7 +38,7 @@ class EqualsFunctor(val isNegated: Boolean) : AbstractFunctor() {
We don't want to code here fair analysis for general cases, because it's too complex. Instead, we just
check some specific cases, which are useful enough in practice
*/
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
assert(arguments.size == 2) { "Equals functor expected 2 arguments, got ${arguments.size}" }
// TODO: AnnotationConstructorCaller kills this with implicit receiver. Investigate, how.
@@ -24,21 +24,23 @@ import org.jetbrains.kotlin.contracts.model.structure.ESType
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
class IsFunctor(val type: ESType, val isNegated: Boolean) : AbstractFunctor() {
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
assert(arguments.size == 1) { "Wrong size of arguments list for Unary operator: expected 1, got ${arguments.size}" }
return invokeWithArguments(arguments[0])
return invokeWithArguments(arguments[0], typeSubstitution)
}
fun invokeWithArguments(arg: Computation): List<ESEffect> {
fun invokeWithArguments(arg: Computation, typeSubstitution: ESTypeSubstitution): List<ESEffect> {
return if (arg is ESValue)
invokeWithValue(arg)
invokeWithValue(arg, typeSubstitution)
else
emptyList()
}
private fun invokeWithValue(value: ESValue): List<ConditionalEffect> {
val trueIs = ESIs(value, this)
val falseIs = ESIs(value, IsFunctor(type, isNegated.not()))
private fun invokeWithValue(value: ESValue, typeSubstitution: ESTypeSubstitution): List<ConditionalEffect> {
val substitutedType = typeSubstitution[type] ?: type
val trueIs = ESIs(value, IsFunctor(substitutedType, isNegated))
val falseIs = ESIs(value, IsFunctor(substitutedType, isNegated.not()))
val trueResult = ConditionalEffect(trueIs, ESReturns(ESConstants.trueValue))
val falseResult = ConditionalEffect(falseIs, ESReturns(ESConstants.falseValue))
@@ -28,7 +28,7 @@ class SubstitutingFunctor(
private val basicEffects: List<ESEffect>,
private val ownerFunction: FunctionDescriptor
) : AbstractFunctor() {
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
if (basicEffects.isEmpty()) return emptyList()
val receiver =
@@ -40,7 +40,7 @@ class SubstitutingFunctor(
}
val substitutions = parameters.zip(arguments).toMap()
val substitutor = Substitutor(substitutions, reducer)
val substitutor = Substitutor(substitutions, typeSubstitution, reducer)
val substitutedClauses = mutableListOf<ESEffect>()
effectsLoop@ for (effect in basicEffects) {
@@ -36,6 +36,20 @@ object ESBooleanType : ESType() {
class ESKotlinType(val type: KotlinType) : ESType() {
override fun toKotlinType(builtIns: KotlinBuiltIns): KotlinType = type
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ESKotlinType
if (type != other.type) return false
return true
}
override fun hashCode(): Int {
return type.hashCode()
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.contracts.model.visitors
import org.jetbrains.kotlin.contracts.model.Computation
import org.jetbrains.kotlin.contracts.model.ESExpression
import org.jetbrains.kotlin.contracts.model.ESExpressionVisitor
import org.jetbrains.kotlin.contracts.model.ESTypeSubstitution
import org.jetbrains.kotlin.contracts.model.structure.*
/**
@@ -28,11 +29,12 @@ import org.jetbrains.kotlin.contracts.model.structure.*
*/
class Substitutor(
private val substitutions: Map<ESVariable, Computation>,
private val typeSubstitution: ESTypeSubstitution,
private val reducer: Reducer
) : ESExpressionVisitor<Computation?> {
override fun visitIs(isOperator: ESIs): Computation? {
val arg = isOperator.left.accept(this) ?: return null
return CallComputation(ESBooleanType, isOperator.functor.invokeWithArguments(arg))
return CallComputation(ESBooleanType, isOperator.functor.invokeWithArguments(arg, typeSubstitution))
}
override fun visitNot(not: ESNot): Computation? {
@@ -43,7 +45,7 @@ class Substitutor(
override fun visitEqual(equal: ESEqual): Computation? {
val left = equal.left.accept(this) ?: return null
val right = equal.right.accept(this) ?: return null
return CallComputation(ESBooleanType, equal.functor.invokeWithArguments(listOf(left, right), reducer))
return CallComputation(ESBooleanType, equal.functor.invokeWithArguments(listOf(left, right), typeSubstitution, reducer))
}
override fun visitAnd(and: ESAnd): Computation? {
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER -NOTHING_TO_INLINE -ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS -ABSTRACT_FUNCTION_WITH_BODY -UNUSED_PARAMETER -UNUSED_VARIABLE -EXPERIMENTAL_FEATURE_WARNING
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER -NOTHING_TO_INLINE -ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS -ABSTRACT_FUNCTION_WITH_BODY -UNUSED_PARAMETER -UNUSED_VARIABLE -EXPERIMENTAL_FEATURE_WARNING
@@ -21,9 +21,15 @@ public open class Class {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final inline fun inlineMember(/*0*/ x: kotlin.Boolean): kotlin.Unit
Returns(WILDCARD) -> x
public final fun member(/*0*/ x: kotlin.Boolean): kotlin.Unit
Returns(WILDCARD) -> x
public open fun openMemeber(/*0*/ x: kotlin.Boolean): kotlin.Unit
public final suspend fun suspendMember(/*0*/ x: kotlin.Boolean): kotlin.Unit
Returns(WILDCARD) -> x
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers -AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers -AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -6,7 +6,7 @@ import kotlin.contracts.*
inline fun <reified T> referToReifiedGeneric(x: Any?) {
contract {
returns() implies (x is <!ERROR_IN_CONTRACT_DESCRIPTION("references to type parameters are forbidden in contracts")!>T<!>)
returns() implies (x is T)
}
}
@@ -6,6 +6,8 @@ public fun referToAliasedSimpleType(/*0*/ x: kotlin.Any?): kotlin.Unit
Returns(WILDCARD) -> x is Int
public inline fun </*0*/ reified T> referToReifiedGeneric(/*0*/ x: kotlin.Any?): kotlin.Unit
Returns(WILDCARD) -> x is T
public fun referToSubstituted(/*0*/ x: kotlin.Any?): kotlin.Unit
public fun referToSubstitutedWithStar(/*0*/ x: kotlin.Any?): kotlin.Unit
Returns(WILDCARD) -> x is Generic<*>
@@ -0,0 +1,31 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER -UNUSED_VARIABLE
import kotlin.contracts.*
inline fun <reified T> requireIsInstance(value: Any?) {
contract {
returns() implies (value is T)
}
if (value !is T) {
throw IllegalArgumentException()
}
}
inline fun <reified T> cast(value: Any?): T {
contract {
returns() implies (value is T)
}
return value as T
}
fun test_1(x: Any) {
requireIsInstance<String>(x)
x.<!UNRESOLVED_REFERENCE!>length<!>
}
fun test_2(x: Any) {
val s: String = cast(x)
x.<!UNRESOLVED_REFERENCE!>length<!>
}
@@ -0,0 +1,31 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER -UNUSED_VARIABLE
import kotlin.contracts.*
inline fun <reified T> requireIsInstance(value: Any?) {
contract {
returns() implies (value is T)
}
if (value !is T) {
throw IllegalArgumentException()
}
}
inline fun <reified T> cast(value: Any?): T {
contract {
returns() implies (value is T)
}
return value as T
}
fun test_1(x: Any) {
requireIsInstance<String>(x)
<!DEBUG_INFO_SMARTCAST!>x<!>.length
}
fun test_2(x: Any) {
val s: String = cast(x)
<!DEBUG_INFO_SMARTCAST!>x<!>.length
}
@@ -0,0 +1,10 @@
package
public inline fun </*0*/ reified T> cast(/*0*/ value: kotlin.Any?): T
Returns(WILDCARD) -> value is T
public inline fun </*0*/ reified T> requireIsInstance(/*0*/ value: kotlin.Any?): kotlin.Unit
Returns(WILDCARD) -> value is T
public fun test_1(/*0*/ x: kotlin.Any): kotlin.Unit
public fun test_2(/*0*/ x: kotlin.Any): kotlin.Unit
@@ -0,0 +1,23 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +ReadDeserializedContracts +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package test
import kotlin.contracts.*
inline fun <reified T> requireIsInstance(value: Any?) {
contract {
returns() implies (value is T)
}
if (value !is T) {
throw IllegalArgumentException()
}
}
inline fun <reified T, reified U> cast(value: Any?, z: U): T {
contract {
returns() implies (value is T)
}
return value as T
}
@@ -0,0 +1,7 @@
package test
public inline fun </*0*/ reified T, /*1*/ reified U> cast(/*0*/ value: kotlin.Any?, /*1*/ z: U): T
Returns(WILDCARD) -> value is T
public inline fun </*0*/ reified T> requireIsInstance(/*0*/ value: kotlin.Any?): kotlin.Unit
Returns(WILDCARD) -> value is T
@@ -1386,6 +1386,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/receiver.kt");
}
@TestMetadata("reifiedGeneric.kt")
public void testReifiedGeneric() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.kt");
}
@TestMetadata("safecallAndReturnsNull.kt")
public void testSafecallAndReturnsNull() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/safecallAndReturnsNull.kt");
@@ -1386,6 +1386,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/receiver.kt");
}
@TestMetadata("reifiedGeneric.kt")
public void testReifiedGeneric() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.kt");
}
@TestMetadata("safecallAndReturnsNull.kt")
public void testSafecallAndReturnsNull() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/safecallAndReturnsNull.kt");
@@ -4650,6 +4650,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt");
}
@TestMetadata("contractWithRefiedGeneric.kt")
public void testContractWithRefiedGeneric() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.kt");
}
@TestMetadata("contractsOnMembers.kt")
public void testContractsOnMembers() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractsOnMembers.kt");
@@ -4651,6 +4651,11 @@ public class IrLoadJavaTestGenerated extends AbstractIrLoadJavaTest {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt");
}
@TestMetadata("contractWithRefiedGeneric.kt")
public void testContractWithRefiedGeneric() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.kt");
}
@TestMetadata("contractsOnMembers.kt")
public void testContractsOnMembers() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractsOnMembers.kt");
@@ -4650,6 +4650,11 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt");
}
@TestMetadata("contractWithRefiedGeneric.kt")
public void testContractWithRefiedGeneric() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.kt");
}
@TestMetadata("contractsOnMembers.kt")
public void testContractsOnMembers() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractsOnMembers.kt");
@@ -122,6 +122,7 @@ enum class LanguageFeature(
AllowResultInReturnType(KOTLIN_1_4),
PreferJavaFieldOverload(KOTLIN_1_4),
AllowContractsForNonOverridableMembers(KOTLIN_1_4),
AllowReifiedGenericsInContracts(KOTLIN_1_4),
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
// Temporarily disabled, see KT-27084/KT-22379
@@ -296,7 +296,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
val mapValueForContract =
c.components.contractDeserializer.deserializeContractFromFunction(proto, function, c.typeTable, c.typeDeserializer)
c.components.contractDeserializer.deserializeContractFromFunction(proto, function, c.typeTable, local.typeDeserializer)
if (mapValueForContract != null) {
function.putInUserDataMap(mapValueForContract.first, mapValueForContract.second)
}