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"); 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") @TestMetadata("safecallAndReturnsNull.kt")
public void testSafecallAndReturnsNull() throws Exception { public void testSafecallAndReturnsNull() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/safecallAndReturnsNull.kt"); 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.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.ContractProviderKey import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.model.Computation import org.jetbrains.kotlin.contracts.model.*
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.functors.* import org.jetbrains.kotlin.contracts.model.functors.*
import org.jetbrains.kotlin.contracts.model.structure.* import org.jetbrains.kotlin.contracts.model.structure.*
import org.jetbrains.kotlin.contracts.model.visitors.Reducer import org.jetbrains.kotlin.contracts.model.visitors.Reducer
@@ -71,12 +68,13 @@ class EffectsExtractingVisitor(
if (resolvedCall.isCallWithUnsupportedReceiver()) return UNKNOWN_COMPUTATION if (resolvedCall.isCallWithUnsupportedReceiver()) return UNKNOWN_COMPUTATION
val arguments = resolvedCall.getCallArgumentsAsComputations() ?: return UNKNOWN_COMPUTATION val arguments = resolvedCall.getCallArgumentsAsComputations() ?: return UNKNOWN_COMPUTATION
val typeSubstitution = resolvedCall.getTypeSubstitution()
val descriptor = resolvedCall.resultingDescriptor val descriptor = resolvedCall.resultingDescriptor
return when { return when {
descriptor.isEqualsDescriptor() -> CallComputation( descriptor.isEqualsDescriptor() -> CallComputation(
ESBooleanType, ESBooleanType,
EqualsFunctor(false).invokeWithArguments(arguments, reducer) EqualsFunctor(false).invokeWithArguments(arguments, typeSubstitution, reducer)
) )
descriptor is ValueDescriptor -> ESVariableWithDataFlowValue( descriptor is ValueDescriptor -> ESVariableWithDataFlowValue(
descriptor, descriptor,
@@ -86,7 +84,7 @@ class EffectsExtractingVisitor(
val esType = descriptor.returnType?.toESType() val esType = descriptor.returnType?.toESType()
CallComputation( CallComputation(
esType, esType,
descriptor.getFunctor()?.invokeWithArguments(arguments, reducer) ?: emptyList() descriptor.getFunctor()?.invokeWithArguments(arguments, typeSubstitution, reducer) ?: emptyList()
) )
} }
else -> UNKNOWN_COMPUTATION else -> UNKNOWN_COMPUTATION
@@ -123,7 +121,7 @@ class EffectsExtractingVisitor(
val arg = extractOrGetCached(expression.leftHandSide) val arg = extractOrGetCached(expression.leftHandSide)
return CallComputation( return CallComputation(
ESBooleanType, 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) val args = listOf(left, right)
return when (expression.operationToken) { return when (expression.operationToken) {
KtTokens.EXCLEQ -> CallComputation(ESBooleanType, EqualsFunctor(true).invokeWithArguments(args, reducer)) KtTokens.EXCLEQ -> CallComputation(ESBooleanType, EqualsFunctor(true).invokeWithArguments(args, emptyMap(), reducer))
KtTokens.EQEQ -> CallComputation(ESBooleanType, EqualsFunctor(false).invokeWithArguments(args, reducer)) KtTokens.EQEQ -> CallComputation(ESBooleanType, EqualsFunctor(false).invokeWithArguments(args, emptyMap(), reducer))
KtTokens.ANDAND -> CallComputation(ESBooleanType, AndFunctor().invokeWithArguments(args, reducer)) KtTokens.ANDAND -> CallComputation(ESBooleanType, AndFunctor().invokeWithArguments(args, emptyMap(), reducer))
KtTokens.OROR -> CallComputation(ESBooleanType, OrFunctor().invokeWithArguments(args, reducer)) KtTokens.OROR -> CallComputation(ESBooleanType, OrFunctor().invokeWithArguments(args, emptyMap(), reducer))
else -> UNKNOWN_COMPUTATION else -> UNKNOWN_COMPUTATION
} }
} }
@@ -215,6 +213,14 @@ class EffectsExtractingVisitor(
return arguments 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? { private fun ResolvedValueArgument.toComputation(): Computation? {
return when (this) { return when (this) {
// Assume that we don't know anything about default arguments // Assume that we don't know anything about default arguments
@@ -16,14 +16,14 @@
package org.jetbrains.kotlin.contracts.parsing package org.jetbrains.kotlin.contracts.parsing
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.ContractDescription import org.jetbrains.kotlin.contracts.description.ContractDescription
import org.jetbrains.kotlin.contracts.description.ContractProviderKey import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.description.LazyContractProvider import org.jetbrains.kotlin.contracts.description.LazyContractProvider
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace 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' // is a *necessary* (but not sufficient, actually) condition for presence of 'LazyContractProvider'
if (!expression.isContractDescriptionCallPsiCheck()) return if (!expression.isContractDescriptionCallPsiCheck()) return
val callContext = ContractCallContext(expression, scope, trace) val callContext = ContractCallContext(expression, scope, trace, languageVersionSettings)
val contractProviderIfAny = val contractProviderIfAny =
(scope.ownerDescriptor as? FunctionDescriptor)?.getUserData(ContractProviderKey) as? LazyContractProvider? (scope.ownerDescriptor as? FunctionDescriptor)?.getUserData(ContractProviderKey) as? LazyContractProvider?
var resultingContractDescription: ContractDescription? = null var resultingContractDescription: ContractDescription? = null
@@ -104,7 +104,8 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
class ContractCallContext( class ContractCallContext(
val contractCallExpression: KtExpression, val contractCallExpression: KtExpression,
val scope: LexicalScope, val scope: LexicalScope,
val trace: BindingTrace val trace: BindingTrace,
val languageVersionSettings: LanguageVersionSettings
) { ) {
val ownerDescriptor: DeclarationDescriptor = scope.ownerDescriptor val ownerDescriptor: DeclarationDescriptor = scope.ownerDescriptor
val functionDescriptor: FunctionDescriptor = ownerDescriptor as FunctionDescriptor val functionDescriptor: FunctionDescriptor = ownerDescriptor as FunctionDescriptor
@@ -16,7 +16,8 @@
package org.jetbrains.kotlin.contracts.parsing 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.contracts.description.expressions.*
import org.jetbrains.kotlin.descriptors.ValueDescriptor import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.impl.AbstractTypeParameterDescriptor import org.jetbrains.kotlin.descriptors.impl.AbstractTypeParameterDescriptor
@@ -47,8 +48,16 @@ internal class PsiConditionParser(
} }
if (descriptor is AbstractTypeParameterDescriptor) { if (descriptor is AbstractTypeParameterDescriptor) {
collector.badDescription("references to type parameters are forbidden in contracts", typeReference) val reifiedGenericsAllowed = callContext.languageVersionSettings.supportsFeature(LanguageFeature.AllowReifiedGenericsInContracts)
return null 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. // 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 package org.jetbrains.kotlin.contracts.model
import org.jetbrains.kotlin.contracts.model.structure.ESKotlinType
import org.jetbrains.kotlin.contracts.model.visitors.Reducer 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. * values, it takes effects and returns effects.
*/ */
interface Functor { 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 { abstract class AbstractFunctor : Functor {
override fun invokeWithArguments(arguments: List<Computation>, reducer: Reducer): List<ESEffect> = override fun invokeWithArguments(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> =
reducer.reduceEffects(doInvocation(arguments, reducer)) 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 package org.jetbrains.kotlin.contracts.model.functors
import org.jetbrains.kotlin.contracts.model.* 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 import org.jetbrains.kotlin.contracts.model.visitors.Reducer
abstract class AbstractBinaryFunctor : AbstractFunctor() { 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}" } assert(arguments.size == 2) { "Wrong size of arguments list for Binary functor: expected 2, got ${arguments.size}" }
return invokeWithArguments(arguments[0], arguments[1]) 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. * be called only on clauses that haven't failed before reaching functor transformation.
*/ */
abstract class AbstractUnaryFunctor : AbstractFunctor() { 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}" } 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])
} }
@@ -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 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 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}" } assert(arguments.size == 2) { "Equals functor expected 2 arguments, got ${arguments.size}" }
// TODO: AnnotationConstructorCaller kills this with implicit receiver. Investigate, how. // 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 import org.jetbrains.kotlin.contracts.model.visitors.Reducer
class IsFunctor(val type: ESType, val isNegated: Boolean) : AbstractFunctor() { 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}" } 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) return if (arg is ESValue)
invokeWithValue(arg) invokeWithValue(arg, typeSubstitution)
else else
emptyList() emptyList()
} }
private fun invokeWithValue(value: ESValue): List<ConditionalEffect> { private fun invokeWithValue(value: ESValue, typeSubstitution: ESTypeSubstitution): List<ConditionalEffect> {
val trueIs = ESIs(value, this) val substitutedType = typeSubstitution[type] ?: type
val falseIs = ESIs(value, IsFunctor(type, isNegated.not()))
val trueIs = ESIs(value, IsFunctor(substitutedType, isNegated))
val falseIs = ESIs(value, IsFunctor(substitutedType, isNegated.not()))
val trueResult = ConditionalEffect(trueIs, ESReturns(ESConstants.trueValue)) val trueResult = ConditionalEffect(trueIs, ESReturns(ESConstants.trueValue))
val falseResult = ConditionalEffect(falseIs, ESReturns(ESConstants.falseValue)) val falseResult = ConditionalEffect(falseIs, ESReturns(ESConstants.falseValue))
@@ -28,7 +28,7 @@ class SubstitutingFunctor(
private val basicEffects: List<ESEffect>, private val basicEffects: List<ESEffect>,
private val ownerFunction: FunctionDescriptor private val ownerFunction: FunctionDescriptor
) : AbstractFunctor() { ) : 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() if (basicEffects.isEmpty()) return emptyList()
val receiver = val receiver =
@@ -40,7 +40,7 @@ class SubstitutingFunctor(
} }
val substitutions = parameters.zip(arguments).toMap() val substitutions = parameters.zip(arguments).toMap()
val substitutor = Substitutor(substitutions, reducer) val substitutor = Substitutor(substitutions, typeSubstitution, reducer)
val substitutedClauses = mutableListOf<ESEffect>() val substitutedClauses = mutableListOf<ESEffect>()
effectsLoop@ for (effect in basicEffects) { effectsLoop@ for (effect in basicEffects) {
@@ -36,6 +36,20 @@ object ESBooleanType : ESType() {
class ESKotlinType(val type: KotlinType) : ESType() { class ESKotlinType(val type: KotlinType) : ESType() {
override fun toKotlinType(builtIns: KotlinBuiltIns): KotlinType = type 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.Computation
import org.jetbrains.kotlin.contracts.model.ESExpression import org.jetbrains.kotlin.contracts.model.ESExpression
import org.jetbrains.kotlin.contracts.model.ESExpressionVisitor import org.jetbrains.kotlin.contracts.model.ESExpressionVisitor
import org.jetbrains.kotlin.contracts.model.ESTypeSubstitution
import org.jetbrains.kotlin.contracts.model.structure.* import org.jetbrains.kotlin.contracts.model.structure.*
/** /**
@@ -28,11 +29,12 @@ import org.jetbrains.kotlin.contracts.model.structure.*
*/ */
class Substitutor( class Substitutor(
private val substitutions: Map<ESVariable, Computation>, private val substitutions: Map<ESVariable, Computation>,
private val typeSubstitution: ESTypeSubstitution,
private val reducer: Reducer private val reducer: Reducer
) : ESExpressionVisitor<Computation?> { ) : ESExpressionVisitor<Computation?> {
override fun visitIs(isOperator: ESIs): Computation? { override fun visitIs(isOperator: ESIs): Computation? {
val arg = isOperator.left.accept(this) ?: return null 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? { override fun visitNot(not: ESNot): Computation? {
@@ -43,7 +45,7 @@ class Substitutor(
override fun visitEqual(equal: ESEqual): Computation? { override fun visitEqual(equal: ESEqual): Computation? {
val left = equal.left.accept(this) ?: return null val left = equal.left.accept(this) ?: return null
val right = equal.right.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? { override fun visitAnd(and: ESAnd): Computation? {
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers // !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // !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 // !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 // !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 // !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 equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final inline fun inlineMember(/*0*/ x: kotlin.Boolean): kotlin.Unit public final inline fun inlineMember(/*0*/ x: kotlin.Boolean): kotlin.Unit
Returns(WILDCARD) -> x
public final fun member(/*0*/ x: kotlin.Boolean): kotlin.Unit public final fun member(/*0*/ x: kotlin.Boolean): kotlin.Unit
Returns(WILDCARD) -> x
public open fun openMemeber(/*0*/ x: kotlin.Boolean): kotlin.Unit public open fun openMemeber(/*0*/ x: kotlin.Boolean): kotlin.Unit
public final suspend fun suspendMember(/*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 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 // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER // !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers // !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers -AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER // !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers // !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER // !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -1,4 +1,4 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers // !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts
// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER // !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
@@ -6,7 +6,7 @@ import kotlin.contracts.*
inline fun <reified T> referToReifiedGeneric(x: Any?) { inline fun <reified T> referToReifiedGeneric(x: Any?) {
contract { 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 Returns(WILDCARD) -> x is Int
public inline fun </*0*/ reified T> referToReifiedGeneric(/*0*/ x: kotlin.Any?): kotlin.Unit 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 referToSubstituted(/*0*/ x: kotlin.Any?): kotlin.Unit
public fun referToSubstitutedWithStar(/*0*/ x: kotlin.Any?): kotlin.Unit public fun referToSubstitutedWithStar(/*0*/ x: kotlin.Any?): kotlin.Unit
Returns(WILDCARD) -> x is Generic<*> 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"); 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") @TestMetadata("safecallAndReturnsNull.kt")
public void testSafecallAndReturnsNull() throws Exception { public void testSafecallAndReturnsNull() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/safecallAndReturnsNull.kt"); 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"); 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") @TestMetadata("safecallAndReturnsNull.kt")
public void testSafecallAndReturnsNull() throws Exception { public void testSafecallAndReturnsNull() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/safecallAndReturnsNull.kt"); 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"); 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") @TestMetadata("contractsOnMembers.kt")
public void testContractsOnMembers() throws Exception { public void testContractsOnMembers() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractsOnMembers.kt"); 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"); 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") @TestMetadata("contractsOnMembers.kt")
public void testContractsOnMembers() throws Exception { public void testContractsOnMembers() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractsOnMembers.kt"); 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"); 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") @TestMetadata("contractsOnMembers.kt")
public void testContractsOnMembers() throws Exception { public void testContractsOnMembers() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractsOnMembers.kt"); runTest("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractsOnMembers.kt");
@@ -122,6 +122,7 @@ enum class LanguageFeature(
AllowResultInReturnType(KOTLIN_1_4), AllowResultInReturnType(KOTLIN_1_4),
PreferJavaFieldOverload(KOTLIN_1_4), PreferJavaFieldOverload(KOTLIN_1_4),
AllowContractsForNonOverridableMembers(KOTLIN_1_4), AllowContractsForNonOverridableMembers(KOTLIN_1_4),
AllowReifiedGenericsInContracts(KOTLIN_1_4),
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX), ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
// Temporarily disabled, see KT-27084/KT-22379 // 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) function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
val mapValueForContract = 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) { if (mapValueForContract != null) {
function.putInUserDataMap(mapValueForContract.first, mapValueForContract.second) function.putInUserDataMap(mapValueForContract.first, mapValueForContract.second)
} }