Get rid of FUNCTOR slice, use lazy value in ContractDecription instead

Functor is an imperative representation of function's contract (contrary
to ContractDescription, which is a declarative one). ContractDescription
is convenient when we deal with sources of contracts declarations
(binaries, source), while Functors are convenient for analyzing code
with contracts.

It means that we have to convert ContractDescription into Functor when
we start working with contracts. This computation isn't trivial, and
Functor and ContractDescription are in 1-1 correspondence, so we would
like to cache Functor for each ContractDescription somewhere.

We used to do this in binding trace, in slice FUNCTOR.

Now, it turns out that this approach causes "Rewrite at slice"
exception, see KT-28847. We won't go into details of why that happens
here, you can see the issue comments for details (but be prepared for the
very long and nitty-gritty story)

This commit removes the problematic slice and introduces another
approach, where Functor is attached to the ContractDescription, computed
lazily and cached here.

^KT-28847 Fixed
This commit is contained in:
Dmitry Savvinov
2018-12-20 13:00:00 +03:00
parent 594a6588f9
commit a4d1a8f60a
11 changed files with 43 additions and 29 deletions
@@ -16,7 +16,10 @@
package org.jetbrains.kotlin.contracts.description
import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher
import org.jetbrains.kotlin.contracts.model.Functor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.storage.StorageManager
/**
* This is actual model of contracts, i.e. what is expected to be parsed from
@@ -30,7 +33,18 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
* backward compatibility. Ideally, this model should only be extended, but not
* changed.
*/
open class ContractDescription(val effects: List<EffectDeclaration>, val ownerFunction: FunctionDescriptor)
open class ContractDescription(
val effects: List<EffectDeclaration>,
val ownerFunction: FunctionDescriptor,
storageManager: StorageManager
) {
private val functorLazyValue = storageManager.createNullableLazyValue {
ContractInterpretationDispatcher().convertContractDescriptorToFunctor(this)
}
val functor: Functor?
get() = functorLazyValue()
}
interface ContractDescriptionElement {
fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R
@@ -39,12 +39,7 @@ class ContractInterpretationDispatcher {
CallsEffectInterpreter(this)
)
fun resolveFunctor(functionDescriptor: FunctionDescriptor): Functor? {
val contractDescriptor = functionDescriptor.getUserData(ContractProviderKey)?.getContractDescription() ?: return null
return convertContractDescriptorToFunctor(contractDescriptor)
}
private fun convertContractDescriptorToFunctor(contractDescription: ContractDescription): Functor? {
fun convertContractDescriptorToFunctor(contractDescription: ContractDescription): Functor? {
val resultingClauses = contractDescription.effects.map { effect ->
if (effect is ConditionalEffectDeclaration) {
conditionalEffectInterpreter.interpret(effect) ?: return null