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:
Alexander Udalov
2018-12-21 16:35:59 +01:00
parent 7561502956
commit 9516d6e89b
7 changed files with 77 additions and 60 deletions
@@ -16,8 +16,9 @@
package org.jetbrains.kotlin.contracts package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.expressions.ConstantReference
import org.jetbrains.kotlin.contracts.model.ESValue import org.jetbrains.kotlin.contracts.model.ESValue
import org.jetbrains.kotlin.contracts.model.MutableContextInfo import org.jetbrains.kotlin.contracts.model.MutableContextInfo
import org.jetbrains.kotlin.contracts.model.structure.ESConstant import org.jetbrains.kotlin.contracts.model.structure.ESConstant
@@ -26,41 +27,47 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.IdentifierInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.IdentifierInfo
fun MutableContextInfo.toDataFlowInfo(languageVersionSettings: LanguageVersionSettings): DataFlowInfo { fun MutableContextInfo.toDataFlowInfo(languageVersionSettings: LanguageVersionSettings, builtIns: KotlinBuiltIns): DataFlowInfo {
var resultingDataFlowInfo = DataFlowInfoFactory.EMPTY var resultingDataFlowInfo = DataFlowInfoFactory.EMPTY
extractDataFlowStatements(equalValues) { leftDfv, rightValue -> extractDataFlowStatements(equalValues, builtIns) { leftDfv, rightValue ->
val rightDfv = rightValue.toDataFlowValue() val rightDfv = rightValue.toDataFlowValue(builtIns)
if (rightDfv != null) { if (rightDfv != null) {
resultingDataFlowInfo = resultingDataFlowInfo.equate(leftDfv, rightDfv, false, languageVersionSettings) resultingDataFlowInfo = resultingDataFlowInfo.equate(leftDfv, rightDfv, false, languageVersionSettings)
} }
IntArray(42) { it } IntArray(42) { it }
} }
extractDataFlowStatements(notEqualValues) { leftDfv, rightValue -> extractDataFlowStatements(notEqualValues, builtIns) { leftDfv, rightValue ->
val rightDfv = rightValue.toDataFlowValue() val rightDfv = rightValue.toDataFlowValue(builtIns)
if (rightDfv != null) { if (rightDfv != null) {
resultingDataFlowInfo = resultingDataFlowInfo.disequate(leftDfv, rightDfv, languageVersionSettings) resultingDataFlowInfo = resultingDataFlowInfo.disequate(leftDfv, rightDfv, languageVersionSettings)
} }
} }
extractDataFlowStatements(subtypes) { leftDfv, type -> extractDataFlowStatements(subtypes, builtIns) { leftDfv, type ->
resultingDataFlowInfo = resultingDataFlowInfo.establishSubtyping(leftDfv, type, languageVersionSettings) resultingDataFlowInfo = resultingDataFlowInfo.establishSubtyping(leftDfv, type, languageVersionSettings)
} }
return resultingDataFlowInfo return resultingDataFlowInfo
} }
inline private fun <D> extractDataFlowStatements(dictionary: Map<ESValue, Set<D>>, callback: (DataFlowValue, D) -> Unit) { private inline fun <D> extractDataFlowStatements(
dictionary: Map<ESValue, Set<D>>,
builtIns: KotlinBuiltIns,
callback: (DataFlowValue, D) -> Unit
) {
for ((key, setOfValues) in dictionary) { for ((key, setOfValues) in dictionary) {
val leftDfv = key.toDataFlowValue() ?: continue val leftDfv = key.toDataFlowValue(builtIns) ?: continue
setOfValues.forEach { callback(leftDfv, it) } setOfValues.forEach { callback(leftDfv, it) }
} }
} }
private fun ESValue.toDataFlowValue(): DataFlowValue? = when (this) { private fun ESValue.toDataFlowValue(builtIns: KotlinBuiltIns): DataFlowValue? = when (this) {
is ESDataFlowValue -> dataFlowValue is ESDataFlowValue -> dataFlowValue
ESConstant.NULL -> DataFlowValue.nullValue(DefaultBuiltIns.Instance) is ESConstant -> when (constantReference) {
is ESConstant -> DataFlowValue(IdentifierInfo.NO, type) ConstantReference.NULL -> DataFlowValue.nullValue(builtIns)
else -> DataFlowValue(IdentifierInfo.NO, type)
}
else -> null else -> null
} }
@@ -18,15 +18,11 @@ package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.model.structure.ESCalls
import org.jetbrains.kotlin.contracts.model.structure.ESReturns
import org.jetbrains.kotlin.contracts.model.functors.EqualsFunctor
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
import org.jetbrains.kotlin.contracts.model.structure.UNKNOWN_COMPUTATION
import org.jetbrains.kotlin.contracts.model.structure.lift
import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.Computation import org.jetbrains.kotlin.contracts.model.Computation
import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.MutableContextInfo import org.jetbrains.kotlin.contracts.model.MutableContextInfo
import org.jetbrains.kotlin.contracts.model.functors.EqualsFunctor
import org.jetbrains.kotlin.contracts.model.structure.*
import org.jetbrains.kotlin.contracts.model.visitors.InfoCollector import org.jetbrains.kotlin.contracts.model.visitors.InfoCollector
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
@@ -54,7 +50,7 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings, val dat
val resultContextInfo = getContextInfoWhen(ESReturns(ESConstant.WILDCARD), callExpression, bindingTrace, moduleDescriptor) val resultContextInfo = getContextInfoWhen(ESReturns(ESConstant.WILDCARD), callExpression, bindingTrace, moduleDescriptor)
return resultContextInfo.toDataFlowInfo(languageVersionSettings) return resultContextInfo.toDataFlowInfo(languageVersionSettings, moduleDescriptor.builtIns)
} }
fun getDataFlowInfoWhenEquals( fun getDataFlowInfoWhenEquals(
@@ -73,12 +69,13 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings, val dat
val effects = EqualsFunctor(false).invokeWithArguments(leftComputation, rightComputation) val effects = EqualsFunctor(false).invokeWithArguments(leftComputation, rightComputation)
val builtIns = moduleDescriptor.builtIns
val equalsContextInfo = InfoCollector(ESReturns(true.lift())).collectFromSchema(effects) val equalsContextInfo = InfoCollector(ESReturns(true.lift())).collectFromSchema(effects)
val notEqualsContextInfo = InfoCollector(ESReturns(false.lift())).collectFromSchema(effects) val notEqualsContextInfo = InfoCollector(ESReturns(false.lift())).collectFromSchema(effects)
return ConditionalDataFlowInfo( return ConditionalDataFlowInfo(
equalsContextInfo.toDataFlowInfo(languageVersionSettings), equalsContextInfo.toDataFlowInfo(languageVersionSettings, builtIns),
notEqualsContextInfo.toDataFlowInfo(languageVersionSettings) notEqualsContextInfo.toDataFlowInfo(languageVersionSettings, builtIns)
) )
} }
@@ -107,7 +104,7 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings, val dat
if (condition == null) return DataFlowInfo.EMPTY if (condition == null) return DataFlowInfo.EMPTY
return getContextInfoWhen(ESReturns(value.lift()), condition, bindingTrace, moduleDescriptor) return getContextInfoWhen(ESReturns(value.lift()), condition, bindingTrace, moduleDescriptor)
.toDataFlowInfo(languageVersionSettings) .toDataFlowInfo(languageVersionSettings, moduleDescriptor.builtIns)
} }
private fun getContextInfoWhen( private fun getContextInfoWhen(
@@ -16,9 +16,8 @@
package org.jetbrains.kotlin.contracts package org.jetbrains.kotlin.contracts
import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.contracts.description.ContractProviderKey import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher
import org.jetbrains.kotlin.contracts.model.Computation import org.jetbrains.kotlin.contracts.model.Computation
import org.jetbrains.kotlin.contracts.model.ConditionalEffect import org.jetbrains.kotlin.contracts.model.ConditionalEffect
import org.jetbrains.kotlin.contracts.model.ESEffect import org.jetbrains.kotlin.contracts.model.ESEffect
@@ -54,6 +53,8 @@ class EffectsExtractingVisitor(
private val moduleDescriptor: ModuleDescriptor, private val moduleDescriptor: ModuleDescriptor,
private val dataFlowValueFactory: DataFlowValueFactory private val dataFlowValueFactory: DataFlowValueFactory
) : KtVisitor<Computation, Unit>() { ) : KtVisitor<Computation, Unit>() {
private val builtIns: KotlinBuiltIns = moduleDescriptor.builtIns
fun extractOrGetCached(element: KtElement): Computation { fun extractOrGetCached(element: KtElement): Computation {
trace[BindingContext.EXPRESSION_EFFECTS, element]?.let { return it } trace[BindingContext.EXPRESSION_EFFECTS, element]?.let { return it }
return element.accept(this, Unit).also { trace.record(BindingContext.EXPRESSION_EFFECTS, element, it) } return element.accept(this, Unit).also { trace.record(BindingContext.EXPRESSION_EFFECTS, element, it) }
@@ -68,7 +69,7 @@ class EffectsExtractingVisitor(
val descriptor = resolvedCall.resultingDescriptor val descriptor = resolvedCall.resultingDescriptor
return when { return when {
descriptor.isEqualsDescriptor() -> CallComputation( descriptor.isEqualsDescriptor() -> CallComputation(
DefaultBuiltIns.Instance.booleanType, builtIns.booleanType,
EqualsFunctor(false).invokeWithArguments(arguments) EqualsFunctor(false).invokeWithArguments(arguments)
) )
descriptor is ValueDescriptor -> ESDataFlowValue( descriptor is ValueDescriptor -> ESDataFlowValue(
@@ -112,7 +113,7 @@ class EffectsExtractingVisitor(
val rightType: KotlinType = trace[BindingContext.TYPE, expression.typeReference] ?: return UNKNOWN_COMPUTATION val rightType: KotlinType = trace[BindingContext.TYPE, expression.typeReference] ?: return UNKNOWN_COMPUTATION
val arg = extractOrGetCached(expression.leftHandSide) val arg = extractOrGetCached(expression.leftHandSide)
return CallComputation( return CallComputation(
DefaultBuiltIns.Instance.booleanType, builtIns.booleanType,
IsFunctor(rightType, expression.isNegated).invokeWithArguments(listOf(arg)) IsFunctor(rightType, expression.isNegated).invokeWithArguments(listOf(arg))
) )
} }
@@ -138,10 +139,10 @@ class EffectsExtractingVisitor(
val args = listOf(left, right) val args = listOf(left, right)
return when (expression.operationToken) { return when (expression.operationToken) {
KtTokens.EXCLEQ -> CallComputation(DefaultBuiltIns.Instance.booleanType, EqualsFunctor(true).invokeWithArguments(args)) KtTokens.EXCLEQ -> CallComputation(builtIns.booleanType, EqualsFunctor(true).invokeWithArguments(args))
KtTokens.EQEQ -> CallComputation(DefaultBuiltIns.Instance.booleanType, EqualsFunctor(false).invokeWithArguments(args)) KtTokens.EQEQ -> CallComputation(builtIns.booleanType, EqualsFunctor(false).invokeWithArguments(args))
KtTokens.ANDAND -> CallComputation(DefaultBuiltIns.Instance.booleanType, AndFunctor().invokeWithArguments(args)) KtTokens.ANDAND -> CallComputation(builtIns.booleanType, AndFunctor().invokeWithArguments(args))
KtTokens.OROR -> CallComputation(DefaultBuiltIns.Instance.booleanType, OrFunctor().invokeWithArguments(args)) KtTokens.OROR -> CallComputation(builtIns.booleanType, OrFunctor().invokeWithArguments(args))
else -> UNKNOWN_COMPUTATION else -> UNKNOWN_COMPUTATION
} }
} }
@@ -149,7 +150,7 @@ class EffectsExtractingVisitor(
override fun visitUnaryExpression(expression: KtUnaryExpression, data: Unit): Computation { override fun visitUnaryExpression(expression: KtUnaryExpression, data: Unit): Computation {
val arg = extractOrGetCached(expression.baseExpression ?: return UNKNOWN_COMPUTATION) val arg = extractOrGetCached(expression.baseExpression ?: return UNKNOWN_COMPUTATION)
return when (expression.operationToken) { return when (expression.operationToken) {
KtTokens.EXCL -> CallComputation(DefaultBuiltIns.Instance.booleanType, NotFunctor().invokeWithArguments(arg)) KtTokens.EXCL -> CallComputation(builtIns.booleanType, NotFunctor().invokeWithArguments(arg))
else -> UNKNOWN_COMPUTATION else -> UNKNOWN_COMPUTATION
} }
} }
@@ -170,7 +171,7 @@ class EffectsExtractingVisitor(
private fun FunctionDescriptor.getFunctor(): Functor? { private fun FunctionDescriptor.getFunctor(): Functor? {
val contractDescription = getUserData(ContractProviderKey)?.getContractDescription() ?: return null val contractDescription = getUserData(ContractProviderKey)?.getContractDescription() ?: return null
return contractDescription.functor return contractDescription.getFunctor(moduleDescriptor)
} }
private fun ResolvedCall<*>.isCallWithUnsupportedReceiver(): Boolean = private fun ResolvedCall<*>.isCallWithUnsupportedReceiver(): Boolean =
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.contracts.description
import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher
import org.jetbrains.kotlin.contracts.model.Functor import org.jetbrains.kotlin.contracts.model.Functor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
/** /**
@@ -38,12 +39,11 @@ open class ContractDescription(
val ownerFunction: FunctionDescriptor, val ownerFunction: FunctionDescriptor,
storageManager: StorageManager storageManager: StorageManager
) { ) {
private val functorLazyValue = storageManager.createNullableLazyValue { private val computeFunctor = storageManager.createMemoizedFunctionWithNullableValues<ModuleDescriptor, Functor> { module ->
ContractInterpretationDispatcher().convertContractDescriptorToFunctor(this) ContractInterpretationDispatcher(module).convertContractDescriptorToFunctor(this)
} }
val functor: Functor? fun getFunctor(usageModule: ModuleDescriptor): Functor? = computeFunctor(usageModule)
get() = functorLazyValue()
} }
interface ContractDescriptionElement { interface ContractDescriptionElement {
@@ -16,21 +16,24 @@
package org.jetbrains.kotlin.contracts.interpretation 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.ConstantReference
import org.jetbrains.kotlin.contracts.description.expressions.VariableReference 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.ESEffect
import org.jetbrains.kotlin.contracts.model.ESExpression import org.jetbrains.kotlin.contracts.model.ESExpression
import org.jetbrains.kotlin.contracts.model.Functor 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] * This class manages conversion of [ContractDescription] to [Functor]
*/ */
class ContractInterpretationDispatcher { class ContractInterpretationDispatcher(internal val module: ModuleDescriptor) {
private val constantsInterpreter = ConstantValuesInterpreter() private val constantsInterpreter = ConstantValuesInterpreter()
private val conditionInterpreter = ConditionInterpreter(this) private val conditionInterpreter = ConditionInterpreter(this)
private val conditionalEffectInterpreter = ConditionalEffectInterpreter(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? { internal fun interpretEffect(effectDeclaration: EffectDeclaration): ESEffect? {
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.contracts.model.functors 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.*
import org.jetbrains.kotlin.contracts.model.structure.* import org.jetbrains.kotlin.contracts.model.structure.*
import org.jetbrains.kotlin.contracts.model.visitors.Substitutor 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.descriptors.ValueDescriptor
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
class SubstitutingFunctor(private val basicEffects: List<ESEffect>, private val ownerFunction: FunctionDescriptor) : class SubstitutingFunctor(
AbstractReducingFunctor() { private val basicEffects: List<ESEffect>,
private val ownerFunction: FunctionDescriptor,
private val builtIns: KotlinBuiltIns
) : AbstractReducingFunctor() {
override fun doInvocation(arguments: List<Computation>): List<ESEffect> { override fun doInvocation(arguments: List<Computation>): List<ESEffect> {
if (basicEffects.isEmpty()) return emptyList() 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 substitutions = parameters.zip(arguments).toMap()
val substitutor = Substitutor(substitutions) val substitutor = Substitutor(substitutions, builtIns)
val substitutedClauses = mutableListOf<ESEffect>() val substitutedClauses = mutableListOf<ESEffect>()
effectsLoop@ for (effect in basicEffects) { effectsLoop@ for (effect in basicEffects) {
@@ -16,8 +16,10 @@
package org.jetbrains.kotlin.contracts.model.visitors package org.jetbrains.kotlin.contracts.model.visitors
import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.contracts.model.* 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.* import org.jetbrains.kotlin.contracts.model.structure.*
/** /**
@@ -25,33 +27,36 @@ import org.jetbrains.kotlin.contracts.model.structure.*
* and then flattens resulting tree, producing an [EffectSchema], which describes effects * and then flattens resulting tree, producing an [EffectSchema], which describes effects
* of this [ESExpression] with effects of arguments taken into consideration. * 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? { override fun visitIs(isOperator: ESIs): Computation? {
val arg = isOperator.left.accept(this) ?: return null 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? { override fun visitNot(not: ESNot): Computation? {
val arg = not.arg.accept(this) ?: return null 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? { override fun visitEqual(equal: ESEqual): Computation? {
val left = equal.left.accept(this) ?: return null val left = equal.left.accept(this) ?: return null
val right = equal.right.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? { override fun visitAnd(and: ESAnd): Computation? {
val left = and.left.accept(this) ?: return null val left = and.left.accept(this) ?: return null
val right = and.right.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? { override fun visitOr(or: ESOr): Computation? {
val left = or.left.accept(this) ?: return null val left = or.left.accept(this) ?: return null
val right = or.right.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 visitVariable(esVariable: ESVariable): Computation? = substitutions[esVariable] ?: esVariable