diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java index eba1dff4e61..306c832fa75 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestWithStdlibGenerated.java @@ -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"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.kt index b78d77f75ee..6a83e670ffa 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.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() + 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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/ContractParsingServices.kt b/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/ContractParsingServices.kt index 8d0b8068dcd..a62fc87b33a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/ContractParsingServices.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/ContractParsingServices.kt @@ -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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/PsiConditionParser.kt b/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/PsiConditionParser.kt index 7d0a9e35054..ce56ca82abd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/PsiConditionParser.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/contracts/parsing/PsiConditionParser.kt @@ -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. diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/Functor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/Functor.kt index b811086f2ad..5025ff4fe2d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/Functor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/Functor.kt @@ -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, reducer: Reducer): List + fun invokeWithArguments(arguments: List, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List } abstract class AbstractFunctor : Functor { - override fun invokeWithArguments(arguments: List, reducer: Reducer): List = - reducer.reduceEffects(doInvocation(arguments, reducer)) + override fun invokeWithArguments(arguments: List, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List = + reducer.reduceEffects(doInvocation(arguments, typeSubstitution, reducer)) - protected abstract fun doInvocation(arguments: List, reducer: Reducer): List -} \ No newline at end of file + protected abstract fun doInvocation( + arguments: List, + typeSubstitution: ESTypeSubstitution, + reducer: Reducer + ): List +} + +typealias ESTypeSubstitution = Map \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractBinaryFunctor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractBinaryFunctor.kt index 969a29e7574..a47a7f0714c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractBinaryFunctor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractBinaryFunctor.kt @@ -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, reducer: Reducer): List { + override fun doInvocation(arguments: List, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List { assert(arguments.size == 2) { "Wrong size of arguments list for Binary functor: expected 2, got ${arguments.size}" } return invokeWithArguments(arguments[0], arguments[1]) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractUnaryFunctor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractUnaryFunctor.kt index b54fbbb0425..933bcd58cc3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractUnaryFunctor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/AbstractUnaryFunctor.kt @@ -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, reducer: Reducer): List { + override fun doInvocation(arguments: List, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List { assert(arguments.size == 1) { "Wrong size of arguments list for Unary operator: expected 1, got ${arguments.size}" } return invokeWithArguments(arguments[0]) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/EqualsFunctor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/EqualsFunctor.kt index 10553ed1d16..7eaeb8c1453 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/EqualsFunctor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/EqualsFunctor.kt @@ -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, reducer: Reducer): List { + override fun doInvocation(arguments: List, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List { assert(arguments.size == 2) { "Equals functor expected 2 arguments, got ${arguments.size}" } // TODO: AnnotationConstructorCaller kills this with implicit receiver. Investigate, how. diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt index 2d0714ad418..6ac71edb971 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/IsFunctor.kt @@ -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, reducer: Reducer): List { + override fun doInvocation(arguments: List, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List { 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 { + fun invokeWithArguments(arg: Computation, typeSubstitution: ESTypeSubstitution): List { return if (arg is ESValue) - invokeWithValue(arg) + invokeWithValue(arg, typeSubstitution) else emptyList() } - private fun invokeWithValue(value: ESValue): List { - val trueIs = ESIs(value, this) - val falseIs = ESIs(value, IsFunctor(type, isNegated.not())) + private fun invokeWithValue(value: ESValue, typeSubstitution: ESTypeSubstitution): List { + 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)) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/SubstitutingFunctor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/SubstitutingFunctor.kt index d49cf147cd9..5303efa94d2 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/SubstitutingFunctor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/functors/SubstitutingFunctor.kt @@ -28,7 +28,7 @@ class SubstitutingFunctor( private val basicEffects: List, private val ownerFunction: FunctionDescriptor ) : AbstractFunctor() { - override fun doInvocation(arguments: List, reducer: Reducer): List { + override fun doInvocation(arguments: List, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List { 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() effectsLoop@ for (effect in basicEffects) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/structure/Types.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/structure/Types.kt index 38d33843871..4dbf95d9733 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/structure/Types.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/structure/Types.kt @@ -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() + } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/visitors/Substitutor.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/visitors/Substitutor.kt index f8b509d5629..b802e96d154 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/visitors/Substitutor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/model/visitors/Substitutor.kt @@ -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, + private val typeSubstitution: ESTypeSubstitution, private val reducer: Reducer ) : ESExpressionVisitor { 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? { diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.fir.kt index a6f4fb9e283..6b012c9d1a6 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.fir.kt @@ -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 diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.kt index 3783e353b0b..39020cae00f 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.kt @@ -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 diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.txt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.txt index 782ee3bf818..9cc74749b47 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/contractCallSites.1.4.txt @@ -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 } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.fir.kt index 9d7206cece6..7f2d66eba2e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.fir.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers +// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers -AllowReifiedGenericsInContracts // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.kt index 9d9d9d359f8..52b1475d107 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.3.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers +// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect -AllowContractsForNonOverridableMembers -AllowReifiedGenericsInContracts // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.fir.kt index fe26e1eeedf..7c3a4a218c8 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.fir.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +AllowContractsForNonOverridableMembers +AllowReifiedGenericsInContracts // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts // !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.kt index e8cba8fa5f2..329ae838c54 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.kt @@ -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 referToReifiedGeneric(x: Any?) { contract { - returns() implies (x is T) + returns() implies (x is T) } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.txt b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.txt index e4735c40c68..527ac5672ec 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/dsl/errors/typeReferences.1.4.txt @@ -6,6 +6,8 @@ public fun referToAliasedSimpleType(/*0*/ x: kotlin.Any?): kotlin.Unit Returns(WILDCARD) -> x is Int public inline fun 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<*> diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.fir.kt new file mode 100644 index 00000000000..ace4415ee00 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.fir.kt @@ -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 requireIsInstance(value: Any?) { + contract { + returns() implies (value is T) + } + if (value !is T) { + throw IllegalArgumentException() + } +} + +inline fun cast(value: Any?): T { + contract { + returns() implies (value is T) + } + return value as T +} + +fun test_1(x: Any) { + requireIsInstance(x) + x.length +} + +fun test_2(x: Any) { + val s: String = cast(x) + x.length +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.kt new file mode 100644 index 00000000000..ed040a3689c --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.kt @@ -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 requireIsInstance(value: Any?) { + contract { + returns() implies (value is T) + } + if (value !is T) { + throw IllegalArgumentException() + } +} + +inline fun cast(value: Any?): T { + contract { + returns() implies (value is T) + } + return value as T +} + +fun test_1(x: Any) { + requireIsInstance(x) + x.length +} + +fun test_2(x: Any) { + val s: String = cast(x) + x.length +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.txt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.txt new file mode 100644 index 00000000000..f53ef137105 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/reifiedGeneric.txt @@ -0,0 +1,10 @@ +package + +public inline fun cast(/*0*/ value: kotlin.Any?): T + Returns(WILDCARD) -> value is T + +public inline fun 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 diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.kt new file mode 100644 index 00000000000..23c67194ff8 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.kt @@ -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 requireIsInstance(value: Any?) { + contract { + returns() implies (value is T) + } + if (value !is T) { + throw IllegalArgumentException() + } +} + +inline fun cast(value: Any?, z: U): T { + contract { + returns() implies (value is T) + } + return value as T +} diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.txt new file mode 100644 index 00000000000..b32d83ad4c9 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/contractWithRefiedGeneric.txt @@ -0,0 +1,7 @@ +package test + +public inline fun cast(/*0*/ value: kotlin.Any?, /*1*/ z: U): T + Returns(WILDCARD) -> value is T + +public inline fun requireIsInstance(/*0*/ value: kotlin.Any?): kotlin.Unit + Returns(WILDCARD) -> value is T diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 334b6186903..52bd1c74fe0 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index b7e6f16270a..fea556ba5c7 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index c218bf3d9aa..8390b7e022d 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java index d80a43e47f4..4447d679f10 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java index 4e5496e1998..a4526b79662 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java @@ -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"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index d6af8a27ce3..aece7b97353 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.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 diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt index 8bc65150c79..bdd9d46f87d 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt @@ -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) }