Allow use reference to reified type parameters in contracts since 1.4
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.contracts.model
|
||||
|
||||
import org.jetbrains.kotlin.contracts.model.structure.ESKotlinType
|
||||
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
|
||||
|
||||
/**
|
||||
@@ -27,13 +28,19 @@ import org.jetbrains.kotlin.contracts.model.visitors.Reducer
|
||||
* values, it takes effects and returns effects.
|
||||
*/
|
||||
interface Functor {
|
||||
fun invokeWithArguments(arguments: List<Computation>, reducer: Reducer): List<ESEffect>
|
||||
fun invokeWithArguments(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect>
|
||||
}
|
||||
|
||||
|
||||
abstract class AbstractFunctor : Functor {
|
||||
override fun invokeWithArguments(arguments: List<Computation>, reducer: Reducer): List<ESEffect> =
|
||||
reducer.reduceEffects(doInvocation(arguments, reducer))
|
||||
override fun invokeWithArguments(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> =
|
||||
reducer.reduceEffects(doInvocation(arguments, typeSubstitution, reducer))
|
||||
|
||||
protected abstract fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect>
|
||||
}
|
||||
protected abstract fun doInvocation(
|
||||
arguments: List<Computation>,
|
||||
typeSubstitution: ESTypeSubstitution,
|
||||
reducer: Reducer
|
||||
): List<ESEffect>
|
||||
}
|
||||
|
||||
typealias ESTypeSubstitution = Map<ESKotlinType, ESKotlinType>
|
||||
+5
-2
@@ -17,11 +17,14 @@
|
||||
package org.jetbrains.kotlin.contracts.model.functors
|
||||
|
||||
import org.jetbrains.kotlin.contracts.model.*
|
||||
import org.jetbrains.kotlin.contracts.model.structure.*
|
||||
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
|
||||
import org.jetbrains.kotlin.contracts.model.structure.ESOr
|
||||
import org.jetbrains.kotlin.contracts.model.structure.isReturns
|
||||
import org.jetbrains.kotlin.contracts.model.structure.isWildcard
|
||||
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
|
||||
|
||||
abstract class AbstractBinaryFunctor : AbstractFunctor() {
|
||||
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
|
||||
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
|
||||
assert(arguments.size == 2) { "Wrong size of arguments list for Binary functor: expected 2, got ${arguments.size}" }
|
||||
return invokeWithArguments(arguments[0], arguments[1])
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.contracts.model.visitors.Reducer
|
||||
* be called only on clauses that haven't failed before reaching functor transformation.
|
||||
*/
|
||||
abstract class AbstractUnaryFunctor : AbstractFunctor() {
|
||||
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
|
||||
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
|
||||
assert(arguments.size == 1) { "Wrong size of arguments list for Unary operator: expected 1, got ${arguments.size}" }
|
||||
return invokeWithArguments(arguments[0])
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class EqualsFunctor(val isNegated: Boolean) : AbstractFunctor() {
|
||||
We don't want to code here fair analysis for general cases, because it's too complex. Instead, we just
|
||||
check some specific cases, which are useful enough in practice
|
||||
*/
|
||||
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
|
||||
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
|
||||
assert(arguments.size == 2) { "Equals functor expected 2 arguments, got ${arguments.size}" }
|
||||
|
||||
// TODO: AnnotationConstructorCaller kills this with implicit receiver. Investigate, how.
|
||||
|
||||
@@ -24,21 +24,23 @@ import org.jetbrains.kotlin.contracts.model.structure.ESType
|
||||
import org.jetbrains.kotlin.contracts.model.visitors.Reducer
|
||||
|
||||
class IsFunctor(val type: ESType, val isNegated: Boolean) : AbstractFunctor() {
|
||||
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
|
||||
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
|
||||
assert(arguments.size == 1) { "Wrong size of arguments list for Unary operator: expected 1, got ${arguments.size}" }
|
||||
return invokeWithArguments(arguments[0])
|
||||
return invokeWithArguments(arguments[0], typeSubstitution)
|
||||
}
|
||||
|
||||
fun invokeWithArguments(arg: Computation): List<ESEffect> {
|
||||
fun invokeWithArguments(arg: Computation, typeSubstitution: ESTypeSubstitution): List<ESEffect> {
|
||||
return if (arg is ESValue)
|
||||
invokeWithValue(arg)
|
||||
invokeWithValue(arg, typeSubstitution)
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
|
||||
private fun invokeWithValue(value: ESValue): List<ConditionalEffect> {
|
||||
val trueIs = ESIs(value, this)
|
||||
val falseIs = ESIs(value, IsFunctor(type, isNegated.not()))
|
||||
private fun invokeWithValue(value: ESValue, typeSubstitution: ESTypeSubstitution): List<ConditionalEffect> {
|
||||
val substitutedType = typeSubstitution[type] ?: type
|
||||
|
||||
val trueIs = ESIs(value, IsFunctor(substitutedType, isNegated))
|
||||
val falseIs = ESIs(value, IsFunctor(substitutedType, isNegated.not()))
|
||||
|
||||
val trueResult = ConditionalEffect(trueIs, ESReturns(ESConstants.trueValue))
|
||||
val falseResult = ConditionalEffect(falseIs, ESReturns(ESConstants.falseValue))
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ class SubstitutingFunctor(
|
||||
private val basicEffects: List<ESEffect>,
|
||||
private val ownerFunction: FunctionDescriptor
|
||||
) : AbstractFunctor() {
|
||||
override fun doInvocation(arguments: List<Computation>, reducer: Reducer): List<ESEffect> {
|
||||
override fun doInvocation(arguments: List<Computation>, typeSubstitution: ESTypeSubstitution, reducer: Reducer): List<ESEffect> {
|
||||
if (basicEffects.isEmpty()) return emptyList()
|
||||
|
||||
val receiver =
|
||||
@@ -40,7 +40,7 @@ class SubstitutingFunctor(
|
||||
}
|
||||
|
||||
val substitutions = parameters.zip(arguments).toMap()
|
||||
val substitutor = Substitutor(substitutions, reducer)
|
||||
val substitutor = Substitutor(substitutions, typeSubstitution, reducer)
|
||||
val substitutedClauses = mutableListOf<ESEffect>()
|
||||
|
||||
effectsLoop@ for (effect in basicEffects) {
|
||||
|
||||
@@ -36,6 +36,20 @@ object ESBooleanType : ESType() {
|
||||
|
||||
class ESKotlinType(val type: KotlinType) : ESType() {
|
||||
override fun toKotlinType(builtIns: KotlinBuiltIns): KotlinType = type
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ESKotlinType
|
||||
|
||||
if (type != other.type) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return type.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-2
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.contracts.model.visitors
|
||||
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.ESTypeSubstitution
|
||||
import org.jetbrains.kotlin.contracts.model.structure.*
|
||||
|
||||
/**
|
||||
@@ -28,11 +29,12 @@ import org.jetbrains.kotlin.contracts.model.structure.*
|
||||
*/
|
||||
class Substitutor(
|
||||
private val substitutions: Map<ESVariable, Computation>,
|
||||
private val typeSubstitution: ESTypeSubstitution,
|
||||
private val reducer: Reducer
|
||||
) : ESExpressionVisitor<Computation?> {
|
||||
override fun visitIs(isOperator: ESIs): Computation? {
|
||||
val arg = isOperator.left.accept(this) ?: return null
|
||||
return CallComputation(ESBooleanType, isOperator.functor.invokeWithArguments(arg))
|
||||
return CallComputation(ESBooleanType, isOperator.functor.invokeWithArguments(arg, typeSubstitution))
|
||||
}
|
||||
|
||||
override fun visitNot(not: ESNot): Computation? {
|
||||
@@ -43,7 +45,7 @@ class Substitutor(
|
||||
override fun visitEqual(equal: ESEqual): Computation? {
|
||||
val left = equal.left.accept(this) ?: return null
|
||||
val right = equal.right.accept(this) ?: return null
|
||||
return CallComputation(ESBooleanType, equal.functor.invokeWithArguments(listOf(left, right), reducer))
|
||||
return CallComputation(ESBooleanType, equal.functor.invokeWithArguments(listOf(left, right), typeSubstitution, reducer))
|
||||
}
|
||||
|
||||
override fun visitAnd(and: ESAnd): Computation? {
|
||||
|
||||
Reference in New Issue
Block a user