Allow use reference to reified type parameters in contracts since 1.4
This commit is contained in:
@@ -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
|
||||
|
||||
+6
-5
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user