Avoid storing ContractProviderKey in user data of every function
Whenever the key is absent it means that for some reason contract can't be defined there. But we still want to check them properly, thus checkContractAndRecordIfPresent should work even if contract is inapplicable here (no ContractProviderKey in owner's user data)
This commit is contained in:
+4
-4
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.contracts.description.ContractDescription
|
||||
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
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
|
||||
@@ -35,7 +35,7 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
||||
fun checkContractAndRecordIfPresent(expression: KtExpression, trace: BindingTrace, scope: LexicalScope, isFirstStatement: Boolean) {
|
||||
val ownerDescriptor = scope.ownerDescriptor
|
||||
if (!expression.isContractDescriptionCallPsiCheck() || ownerDescriptor !is FunctionDescriptor) return
|
||||
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
|
||||
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey)
|
||||
|
||||
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.AllowContractsForCustomFunctions) ||
|
||||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
|
||||
@@ -62,7 +62,7 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
||||
else -> parseContract(expression, trace, ownerDescriptor)
|
||||
}
|
||||
|
||||
contractProvider.setContractDescription(contractDescriptor)
|
||||
contractProvider?.setContractDescription(contractDescriptor)
|
||||
}
|
||||
|
||||
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
|
||||
@@ -76,4 +76,4 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
||||
|
||||
private fun KtExpression.isContractDescriptionCallPreciseCheck(context: BindingContext): Boolean =
|
||||
getResolvedCall(context)?.resultingDescriptor?.isContractCallDescriptor() ?: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isContractPresentPsiCheck
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isContractPresentPsiCheck
|
||||
import org.jetbrains.kotlin.resolve.DescriptorResolver.getDefaultModality
|
||||
import org.jetbrains.kotlin.resolve.DescriptorResolver.getDefaultVisibility
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.getDispatchReceiverParameterIfNeeded
|
||||
@@ -198,7 +198,13 @@ class FunctionDescriptorResolver(
|
||||
function, getDefaultModality(container, visibility, function.hasBody()),
|
||||
trace.bindingContext, container
|
||||
)
|
||||
|
||||
val contractProvider = getContractProvider(functionDescriptor, trace, scope, dataFlowInfo, function)
|
||||
val userData = mutableMapOf<FunctionDescriptor.UserDataKey<*>, Any>().apply {
|
||||
if (contractProvider != null) {
|
||||
put(ContractProviderKey, contractProvider)
|
||||
}
|
||||
}
|
||||
|
||||
functionDescriptor.initialize(
|
||||
receiverType,
|
||||
@@ -208,8 +214,9 @@ class FunctionDescriptorResolver(
|
||||
returnType,
|
||||
modality,
|
||||
visibility,
|
||||
mapOf(ContractProviderKey to contractProvider)
|
||||
userData.takeIf { it.isNotEmpty() }
|
||||
)
|
||||
|
||||
functionDescriptor.isOperator = function.hasModifier(KtTokens.OPERATOR_KEYWORD)
|
||||
functionDescriptor.isInfix = function.hasModifier(KtTokens.INFIX_KEYWORD)
|
||||
functionDescriptor.isExternal = function.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
@@ -232,17 +239,16 @@ class FunctionDescriptorResolver(
|
||||
scope: LexicalScope,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
function: KtFunction
|
||||
): LazyContractProvider {
|
||||
): LazyContractProvider? {
|
||||
val provideByDeferredForceResolve = LazyContractProvider {
|
||||
expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor)
|
||||
}
|
||||
val emptyContract = LazyContractProvider.createInitialized(null)
|
||||
|
||||
val isContractsEnabled = languageVersionSettings.supportsFeature(LanguageFeature.AllowContractsForCustomFunctions) ||
|
||||
// We need to enable contracts if we're compiling "kotlin"-package to be able to ship contracts in stdlib in 1.2
|
||||
languageVersionSettings.getFlag(AnalysisFlag.allowKotlinPackage)
|
||||
|
||||
if (!isContractsEnabled || !function.isContractPresentPsiCheck()) return emptyContract
|
||||
if (!isContractsEnabled || !function.isContractPresentPsiCheck()) return null
|
||||
|
||||
return provideByDeferredForceResolve
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user