Force-resolve body in contract computation under lock
Even though acquire/release pattern guarantees memory visibility across threads, it doesn't prevents concurrent access to critical section (i.e. to force-resolve of the corresponding body). This can lead to multiple resolution passes over one and the same PSI in IDE, which, in turn, leads to 'rewrite at slice'-exceptions. See KT-30030 for case description and details. ^KT-30030 Fixed
This commit is contained in:
@@ -41,14 +41,14 @@ class ContractDeserializerImpl(
|
||||
ownerFunction: FunctionDescriptor,
|
||||
typeTable: TypeTable,
|
||||
typeDeserializer: TypeDeserializer
|
||||
): Pair<CallableDescriptor.UserDataKey<*>, LazyContractProvider>? {
|
||||
): Pair<CallableDescriptor.UserDataKey<*>, AbstractContractProvider>? {
|
||||
if (!proto.hasContract()) return null
|
||||
|
||||
if (!configuration.readDeserializedContracts) return null
|
||||
|
||||
val worker = ContractDeserializationWorker(typeTable, typeDeserializer, ownerFunction, storageManager)
|
||||
val contract = worker.deserializeContract(proto.contract) ?: return null
|
||||
return ContractProviderKey to LazyContractProvider.createInitialized(contract)
|
||||
return ContractProviderKey to ContractProviderImpl(contract)
|
||||
}
|
||||
|
||||
private class ContractDeserializationWorker(
|
||||
|
||||
+3
-1
@@ -21,6 +21,7 @@ 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.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
@@ -50,7 +51,8 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
||||
if (!expression.isContractDescriptionCallPsiCheck()) return
|
||||
|
||||
val callContext = ContractCallContext(expression, isFirstStatement, scope, trace)
|
||||
val contractProviderIfAny = (scope.ownerDescriptor as? FunctionDescriptor)?.getUserData(ContractProviderKey)
|
||||
val contractProviderIfAny =
|
||||
(scope.ownerDescriptor as? FunctionDescriptor)?.getUserData(ContractProviderKey) as? LazyContractProvider?
|
||||
var resultingContractDescription: ContractDescription? = null
|
||||
|
||||
try {
|
||||
|
||||
@@ -263,7 +263,7 @@ class FunctionDescriptorResolver(
|
||||
|
||||
if (!isContractsEnabled || !function.mayHaveContract()) return null
|
||||
|
||||
return LazyContractProvider {
|
||||
return LazyContractProvider(storageManager) {
|
||||
AstLoadingFilter.forceAllowTreeLoading(function.containingFile) {
|
||||
expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user