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:
+3
-3
@@ -23,7 +23,7 @@ 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.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
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.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
|
||||||
@@ -35,7 +35,7 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
|||||||
fun checkContractAndRecordIfPresent(expression: KtExpression, trace: BindingTrace, scope: LexicalScope, isFirstStatement: Boolean) {
|
fun checkContractAndRecordIfPresent(expression: KtExpression, trace: BindingTrace, scope: LexicalScope, isFirstStatement: Boolean) {
|
||||||
val ownerDescriptor = scope.ownerDescriptor
|
val ownerDescriptor = scope.ownerDescriptor
|
||||||
if (!expression.isContractDescriptionCallPsiCheck() || ownerDescriptor !is FunctionDescriptor) return
|
if (!expression.isContractDescriptionCallPsiCheck() || ownerDescriptor !is FunctionDescriptor) return
|
||||||
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
|
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey)
|
||||||
|
|
||||||
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.AllowContractsForCustomFunctions) ||
|
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.AllowContractsForCustomFunctions) ||
|
||||||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
|
// 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)
|
else -> parseContract(expression, trace, ownerDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
contractProvider.setContractDescription(contractDescriptor)
|
contractProvider?.setContractDescription(contractDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
|
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
|
|||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
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.hasActualModifier
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
|
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.getDefaultModality
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorResolver.getDefaultVisibility
|
import org.jetbrains.kotlin.resolve.DescriptorResolver.getDefaultVisibility
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.getDispatchReceiverParameterIfNeeded
|
import org.jetbrains.kotlin.resolve.DescriptorUtils.getDispatchReceiverParameterIfNeeded
|
||||||
@@ -198,7 +198,13 @@ class FunctionDescriptorResolver(
|
|||||||
function, getDefaultModality(container, visibility, function.hasBody()),
|
function, getDefaultModality(container, visibility, function.hasBody()),
|
||||||
trace.bindingContext, container
|
trace.bindingContext, container
|
||||||
)
|
)
|
||||||
|
|
||||||
val contractProvider = getContractProvider(functionDescriptor, trace, scope, dataFlowInfo, function)
|
val contractProvider = getContractProvider(functionDescriptor, trace, scope, dataFlowInfo, function)
|
||||||
|
val userData = mutableMapOf<FunctionDescriptor.UserDataKey<*>, Any>().apply {
|
||||||
|
if (contractProvider != null) {
|
||||||
|
put(ContractProviderKey, contractProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
functionDescriptor.initialize(
|
functionDescriptor.initialize(
|
||||||
receiverType,
|
receiverType,
|
||||||
@@ -208,8 +214,9 @@ class FunctionDescriptorResolver(
|
|||||||
returnType,
|
returnType,
|
||||||
modality,
|
modality,
|
||||||
visibility,
|
visibility,
|
||||||
mapOf(ContractProviderKey to contractProvider)
|
userData.takeIf { it.isNotEmpty() }
|
||||||
)
|
)
|
||||||
|
|
||||||
functionDescriptor.isOperator = function.hasModifier(KtTokens.OPERATOR_KEYWORD)
|
functionDescriptor.isOperator = function.hasModifier(KtTokens.OPERATOR_KEYWORD)
|
||||||
functionDescriptor.isInfix = function.hasModifier(KtTokens.INFIX_KEYWORD)
|
functionDescriptor.isInfix = function.hasModifier(KtTokens.INFIX_KEYWORD)
|
||||||
functionDescriptor.isExternal = function.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
functionDescriptor.isExternal = function.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||||
@@ -232,17 +239,16 @@ class FunctionDescriptorResolver(
|
|||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
dataFlowInfo: DataFlowInfo,
|
dataFlowInfo: DataFlowInfo,
|
||||||
function: KtFunction
|
function: KtFunction
|
||||||
): LazyContractProvider {
|
): LazyContractProvider? {
|
||||||
val provideByDeferredForceResolve = LazyContractProvider {
|
val provideByDeferredForceResolve = LazyContractProvider {
|
||||||
expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor)
|
expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor)
|
||||||
}
|
}
|
||||||
val emptyContract = LazyContractProvider.createInitialized(null)
|
|
||||||
|
|
||||||
val isContractsEnabled = languageVersionSettings.supportsFeature(LanguageFeature.AllowContractsForCustomFunctions) ||
|
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
|
// 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)
|
languageVersionSettings.getFlag(AnalysisFlag.allowKotlinPackage)
|
||||||
|
|
||||||
if (!isContractsEnabled || !function.isContractPresentPsiCheck()) return emptyContract
|
if (!isContractsEnabled || !function.isContractPresentPsiCheck()) return null
|
||||||
|
|
||||||
return provideByDeferredForceResolve
|
return provideByDeferredForceResolve
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user