Do not use DefaultBuiltIns in contracts
Default built-ins represent built-ins loaded from the compiler jar via class loader, and they may not be equivalent to the built-ins present in the standard library that is used in compilation dependencies, in case the compiler and stdlib versions do not match. Use built-ins from the given module instead. This commit deals with more-or-less obvious usages of DefaultBuiltIns; next commits refactor the ESConstant values and related code to support injected built-ins
This commit is contained in:
+5
-5
@@ -19,6 +19,7 @@ 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.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
/**
|
||||
@@ -38,12 +39,11 @@ open class ContractDescription(
|
||||
val ownerFunction: FunctionDescriptor,
|
||||
storageManager: StorageManager
|
||||
) {
|
||||
private val functorLazyValue = storageManager.createNullableLazyValue {
|
||||
ContractInterpretationDispatcher().convertContractDescriptorToFunctor(this)
|
||||
private val computeFunctor = storageManager.createMemoizedFunctionWithNullableValues<ModuleDescriptor, Functor> { module ->
|
||||
ContractInterpretationDispatcher(module).convertContractDescriptorToFunctor(this)
|
||||
}
|
||||
|
||||
val functor: Functor?
|
||||
get() = functorLazyValue()
|
||||
fun getFunctor(usageModule: ModuleDescriptor): Functor? = computeFunctor(usageModule)
|
||||
}
|
||||
|
||||
interface ContractDescriptionElement {
|
||||
@@ -58,4 +58,4 @@ interface EffectDeclaration : ContractDescriptionElement {
|
||||
interface BooleanExpression : ContractDescriptionElement {
|
||||
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
|
||||
contractDescriptionVisitor.visitBooleanExpression(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-8
@@ -16,21 +16,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.contracts.interpretation
|
||||
|
||||
import org.jetbrains.kotlin.contracts.description.*
|
||||
import org.jetbrains.kotlin.contracts.description.BooleanExpression
|
||||
import org.jetbrains.kotlin.contracts.description.ConditionalEffectDeclaration
|
||||
import org.jetbrains.kotlin.contracts.description.ContractDescription
|
||||
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
|
||||
import org.jetbrains.kotlin.contracts.description.expressions.ConstantReference
|
||||
import org.jetbrains.kotlin.contracts.description.expressions.VariableReference
|
||||
import org.jetbrains.kotlin.contracts.model.functors.SubstitutingFunctor
|
||||
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
|
||||
import org.jetbrains.kotlin.contracts.model.structure.ESVariable
|
||||
import org.jetbrains.kotlin.contracts.model.ESEffect
|
||||
import org.jetbrains.kotlin.contracts.model.ESExpression
|
||||
import org.jetbrains.kotlin.contracts.model.Functor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.contracts.model.functors.SubstitutingFunctor
|
||||
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
|
||||
import org.jetbrains.kotlin.contracts.model.structure.ESVariable
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
|
||||
/**
|
||||
* This class manages conversion of [ContractDescription] to [Functor]
|
||||
*/
|
||||
class ContractInterpretationDispatcher {
|
||||
class ContractInterpretationDispatcher(internal val module: ModuleDescriptor) {
|
||||
private val constantsInterpreter = ConstantValuesInterpreter()
|
||||
private val conditionInterpreter = ConditionInterpreter(this)
|
||||
private val conditionalEffectInterpreter = ConditionalEffectInterpreter(this)
|
||||
@@ -48,7 +51,7 @@ class ContractInterpretationDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
return SubstitutingFunctor(resultingClauses, contractDescription.ownerFunction)
|
||||
return SubstitutingFunctor(resultingClauses, contractDescription.ownerFunction, module.builtIns)
|
||||
}
|
||||
|
||||
internal fun interpretEffect(effectDeclaration: EffectDeclaration): ESEffect? {
|
||||
@@ -63,4 +66,4 @@ class ContractInterpretationDispatcher {
|
||||
booleanExpression.accept(conditionInterpreter, Unit)
|
||||
|
||||
internal fun interpretVariable(variableReference: VariableReference): ESVariable? = ESVariable(variableReference.descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.contracts.model.functors
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.contracts.model.*
|
||||
import org.jetbrains.kotlin.contracts.model.structure.*
|
||||
import org.jetbrains.kotlin.contracts.model.visitors.Substitutor
|
||||
@@ -23,8 +24,11 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueDescriptor
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class SubstitutingFunctor(private val basicEffects: List<ESEffect>, private val ownerFunction: FunctionDescriptor) :
|
||||
AbstractReducingFunctor() {
|
||||
class SubstitutingFunctor(
|
||||
private val basicEffects: List<ESEffect>,
|
||||
private val ownerFunction: FunctionDescriptor,
|
||||
private val builtIns: KotlinBuiltIns
|
||||
) : AbstractReducingFunctor() {
|
||||
override fun doInvocation(arguments: List<Computation>): List<ESEffect> {
|
||||
if (basicEffects.isEmpty()) return emptyList()
|
||||
|
||||
@@ -37,7 +41,7 @@ class SubstitutingFunctor(private val basicEffects: List<ESEffect>, private val
|
||||
}
|
||||
|
||||
val substitutions = parameters.zip(arguments).toMap()
|
||||
val substitutor = Substitutor(substitutions)
|
||||
val substitutor = Substitutor(substitutions, builtIns)
|
||||
val substitutedClauses = mutableListOf<ESEffect>()
|
||||
|
||||
effectsLoop@ for (effect in basicEffects) {
|
||||
|
||||
+14
-9
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.contracts.model.visitors
|
||||
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.contracts.model.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.contracts.model.Computation
|
||||
import org.jetbrains.kotlin.contracts.model.ESExpression
|
||||
import org.jetbrains.kotlin.contracts.model.ESExpressionVisitor
|
||||
import org.jetbrains.kotlin.contracts.model.structure.*
|
||||
|
||||
/**
|
||||
@@ -25,36 +27,39 @@ import org.jetbrains.kotlin.contracts.model.structure.*
|
||||
* and then flattens resulting tree, producing an [EffectSchema], which describes effects
|
||||
* of this [ESExpression] with effects of arguments taken into consideration.
|
||||
*/
|
||||
class Substitutor(private val substitutions: Map<ESVariable, Computation>) : ESExpressionVisitor<Computation?> {
|
||||
class Substitutor(
|
||||
private val substitutions: Map<ESVariable, Computation>,
|
||||
private val builtIns: KotlinBuiltIns
|
||||
) : ESExpressionVisitor<Computation?> {
|
||||
override fun visitIs(isOperator: ESIs): Computation? {
|
||||
val arg = isOperator.left.accept(this) ?: return null
|
||||
return CallComputation(DefaultBuiltIns.Instance.booleanType, isOperator.functor.invokeWithArguments(arg))
|
||||
return CallComputation(builtIns.booleanType, isOperator.functor.invokeWithArguments(arg))
|
||||
}
|
||||
|
||||
override fun visitNot(not: ESNot): Computation? {
|
||||
val arg = not.arg.accept(this) ?: return null
|
||||
return CallComputation(DefaultBuiltIns.Instance.booleanType, not.functor.invokeWithArguments(arg))
|
||||
return CallComputation(builtIns.booleanType, not.functor.invokeWithArguments(arg))
|
||||
}
|
||||
|
||||
override fun visitEqual(equal: ESEqual): Computation? {
|
||||
val left = equal.left.accept(this) ?: return null
|
||||
val right = equal.right.accept(this) ?: return null
|
||||
return CallComputation(DefaultBuiltIns.Instance.booleanType, equal.functor.invokeWithArguments(listOf(left, right)))
|
||||
return CallComputation(builtIns.booleanType, equal.functor.invokeWithArguments(listOf(left, right)))
|
||||
}
|
||||
|
||||
override fun visitAnd(and: ESAnd): Computation? {
|
||||
val left = and.left.accept(this) ?: return null
|
||||
val right = and.right.accept(this) ?: return null
|
||||
return CallComputation(DefaultBuiltIns.Instance.booleanType, and.functor.invokeWithArguments(left, right))
|
||||
return CallComputation(builtIns.booleanType, and.functor.invokeWithArguments(left, right))
|
||||
}
|
||||
|
||||
override fun visitOr(or: ESOr): Computation? {
|
||||
val left = or.left.accept(this) ?: return null
|
||||
val right = or.right.accept(this) ?: return null
|
||||
return CallComputation(DefaultBuiltIns.Instance.booleanType, or.functor.invokeWithArguments(left, right))
|
||||
return CallComputation(builtIns.booleanType, or.functor.invokeWithArguments(left, right))
|
||||
}
|
||||
|
||||
override fun visitVariable(esVariable: ESVariable): Computation? = substitutions[esVariable] ?: esVariable
|
||||
|
||||
override fun visitConstant(esConstant: ESConstant): Computation? = esConstant
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user