Cache type corresponding to type variable

This commit is contained in:
Svetlana Isakova
2015-06-29 20:10:30 +03:00
parent db8085c399
commit ac578f7e5b
4 changed files with 41 additions and 31 deletions
@@ -57,6 +57,8 @@ public class ConstraintSystemImpl : ConstraintSystem {
get() = if (externalTypeParameters.isEmpty()) allTypeParameterBounds get() = if (externalTypeParameters.isEmpty()) allTypeParameterBounds
else allTypeParameterBounds.filter { !externalTypeParameters.contains(it.key) } else allTypeParameterBounds.filter { !externalTypeParameters.contains(it.key) }
private val cachedTypeForVariable = HashMap<TypeParameterDescriptor, JetType>()
private val usedInBounds = HashMap<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>() private val usedInBounds = HashMap<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>()
private val errors = ArrayList<ConstraintError>() private val errors = ArrayList<ConstraintError>()
@@ -139,12 +141,16 @@ public class ConstraintSystemImpl : ConstraintSystem {
for (declaredUpperBound in typeVariable.getUpperBounds()) { for (declaredUpperBound in typeVariable.getUpperBounds()) {
if (KotlinBuiltIns.getInstance().getNullableAnyType() == declaredUpperBound) continue //todo remove this line (?) if (KotlinBuiltIns.getInstance().getNullableAnyType() == declaredUpperBound) continue //todo remove this line (?)
val position = TYPE_BOUND_POSITION.position(typeVariable.getIndex()) val position = TYPE_BOUND_POSITION.position(typeVariable.getIndex())
val variableType = JetTypeImpl(Annotations.EMPTY, typeVariable.getTypeConstructor(), false, listOf(), JetScope.Empty) addBound(typeVariable, declaredUpperBound, UPPER_BOUND, position)
addBound(variableType, Bound(declaredUpperBound, UPPER_BOUND, position, declaredUpperBound.isProper()))
} }
} }
} }
val TypeParameterDescriptor.correspondingType: JetType
get() = cachedTypeForVariable.getOrPut(this) {
JetTypeImpl(Annotations.EMPTY, this.getTypeConstructor(), false, listOf(), JetScope.Empty)
}
fun JetType.isProper() = !TypeUtils.containsSpecialType(this) { fun JetType.isProper() = !TypeUtils.containsSpecialType(this) {
type -> type.getConstructor().getDeclarationDescriptor() in getAllTypeVariables() type -> type.getConstructor().getDeclarationDescriptor() in getAllTypeVariables()
} }
@@ -321,8 +327,14 @@ public class ConstraintSystemImpl : ConstraintSystem {
} }
fun addBound(variable: JetType, bound: Bound) { fun addBound(
val typeBounds = getTypeBounds(variable) typeVariable: TypeParameterDescriptor,
constrainingType: JetType,
kind: TypeBounds.BoundKind,
position: ConstraintPosition
) {
val bound = Bound(typeVariable, constrainingType, kind, position, constrainingType.isProper())
val typeBounds = getTypeBounds(typeVariable)
if (typeBounds.bounds.contains(bound)) return if (typeBounds.bounds.contains(bound)) return
typeBounds.addBound(bound) typeBounds.addBound(bound)
@@ -334,7 +346,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
} }
} }
incorporateBound(variable, bound) incorporateBound(bound)
} }
private fun generateTypeParameterBound( private fun generateTypeParameterBound(
@@ -343,6 +355,8 @@ public class ConstraintSystemImpl : ConstraintSystem {
boundKind: TypeBounds.BoundKind, boundKind: TypeBounds.BoundKind,
constraintPosition: ConstraintPosition constraintPosition: ConstraintPosition
) { ) {
val typeVariable = getMyTypeVariable(parameterType)!!
var newConstrainingType = constrainingType var newConstrainingType = constrainingType
// Here we are handling the case when T! gets a bound Foo (or Foo?) // Here we are handling the case when T! gets a bound Foo (or Foo?)
@@ -354,14 +368,14 @@ public class ConstraintSystemImpl : ConstraintSystem {
// Foo >: T! // Foo >: T!
// both Foo and Foo? transform to Foo! here // both Foo and Foo? transform to Foo! here
if (parameterType.isFlexible()) { if (parameterType.isFlexible()) {
val typeVariable = parameterType.getCustomTypeVariable() val customTypeVariable = parameterType.getCustomTypeVariable()
if (typeVariable != null) { if (customTypeVariable != null) {
newConstrainingType = typeVariable.substitutionResult(constrainingType) newConstrainingType = customTypeVariable.substitutionResult(constrainingType)
} }
} }
if (!parameterType.isMarkedNullable() || !TypeUtils.isNullableType(newConstrainingType)) { if (!parameterType.isMarkedNullable() || !TypeUtils.isNullableType(newConstrainingType)) {
addBound(parameterType, Bound(newConstrainingType, boundKind, constraintPosition, newConstrainingType.isProper())) addBound(typeVariable, newConstrainingType, boundKind, constraintPosition)
return return
} }
// For parameter type T: // For parameter type T:
@@ -369,14 +383,13 @@ public class ConstraintSystemImpl : ConstraintSystem {
// constraint T? = Int! should transform to T >: Int and T <: Int! // constraint T? = Int! should transform to T >: Int and T <: Int!
// constraints T? >: Int?; T? >: Int! should transform to T >: Int // constraints T? >: Int?; T? >: Int! should transform to T >: Int
val notNullParameterType = TypeUtils.makeNotNullable(parameterType)
val notNullConstrainingType = TypeUtils.makeNotNullable(newConstrainingType) val notNullConstrainingType = TypeUtils.makeNotNullable(newConstrainingType)
if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) { if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) {
addBound(notNullParameterType, Bound(notNullConstrainingType, LOWER_BOUND, constraintPosition, notNullConstrainingType.isProper())) addBound(typeVariable, notNullConstrainingType, LOWER_BOUND, constraintPosition)
} }
// constraints T? <: Int?; T? <: Int! should transform to T <: Int?; T <: Int! correspondingly // constraints T? <: Int?; T? <: Int! should transform to T <: Int?; T <: Int! correspondingly
if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) { if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) {
addBound(notNullParameterType, Bound(newConstrainingType, UPPER_BOUND, constraintPosition, newConstrainingType.isProper())) addBound(typeVariable, newConstrainingType, UPPER_BOUND, constraintPosition)
} }
} }
@@ -397,7 +410,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
constrainingTypeProjection constrainingTypeProjection
} }
val capturedType = createCapturedType(typeProjection) val capturedType = createCapturedType(typeProjection)
addBound(TypeUtils.makeNotNullable(parameterType), Bound(capturedType, EXACT_BOUND, constraintPosition)) addBound(typeVariable, capturedType, EXACT_BOUND, constraintPosition)
} }
override fun getTypeVariables() = typeParameterBounds.keySet() override fun getTypeVariables() = typeParameterBounds.keySet()
@@ -441,8 +454,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
val value = typeBounds.value ?: return val value = typeBounds.value ?: return
val type = JetTypeImpl(Annotations.EMPTY, typeVariable.getTypeConstructor(), false, emptyList(), JetScope.Empty) addBound(typeVariable, value, TypeBounds.BoundKind.EXACT_BOUND, ConstraintPositionKind.FROM_COMPLETER.position())
addBound(type, TypeBounds.Bound(value, TypeBounds.BoundKind.EXACT_BOUND, ConstraintPositionKind.FROM_COMPLETER.position()))
} }
fun fixVariables() { fun fixVariables() {
@@ -45,19 +45,19 @@ public trait TypeBounds {
} }
public class Bound( public class Bound(
public val typeVariable: TypeParameterDescriptor,
public val constrainingType: JetType, public val constrainingType: JetType,
public val kind: BoundKind, public val kind: BoundKind,
public val position: ConstraintPosition, public val position: ConstraintPosition,
public val isProper: Boolean = true public val isProper: Boolean = true
) { ) {
public var typeVariable: TypeParameterDescriptor by Delegates.notNull()
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other == null || javaClass != other.javaClass) return false if (other == null || javaClass != other.javaClass) return false
val bound = other as Bound val bound = other as Bound
if (typeVariable != bound.typeVariable) return false
if (constrainingType != bound.constrainingType) return false if (constrainingType != bound.constrainingType) return false
if (kind != bound.kind) return false if (kind != bound.kind) return false
@@ -67,7 +67,8 @@ public trait TypeBounds {
} }
override fun hashCode(): Int { override fun hashCode(): Int {
var result = constrainingType.hashCode() var result = typeVariable.hashCode();
result = 31 * result + constrainingType.hashCode()
result = 31 * result + kind.hashCode() result = 31 * result + kind.hashCode()
result = 31 * result + if (position.isStrong()) 1 else 0 result = 31 * result + if (position.isStrong()) 1 else 0
return result return result
@@ -49,7 +49,9 @@ public class TypeBoundsImpl(
public fun addBound(bound: Bound) { public fun addBound(bound: Bound) {
resultValues = null resultValues = null
bound.typeVariable = typeVariable assert(bound.typeVariable == typeVariable) {
"$bound is added for incorrect type variable ${bound.typeVariable.getName()}. Expected: ${typeVariable.getName()}"
}
bounds.add(bound) bounds.add(bound)
} }
@@ -202,9 +204,7 @@ fun Collection<Bound>.substitute(substituteTypeVariable: (TypeParameterDescripto
it.constrainingType it.constrainingType
} }
substitutedType?.let { type -> substitutedType?.let { type ->
val newBound = Bound(type, it.kind, it.position, it.isProper) Bound(substituteTypeVariable(it.typeVariable) ?: it.typeVariable, type, it.kind, it.position, it.isProper)
newBound.typeVariable = substituteTypeVariable(it.typeVariable) ?: it.typeVariable
newBound
} }
}.filterNotNull() }.filterNotNull()
} }
@@ -34,8 +34,8 @@ import org.jetbrains.kotlin.types.Variance.IN_VARIANCE
import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments
import java.util.ArrayList import java.util.ArrayList
fun ConstraintSystemImpl.incorporateBound(variable: JetType, newBound: Bound) { fun ConstraintSystemImpl.incorporateBound(newBound: Bound) {
val typeVariable = getMyTypeVariable(variable)!! val typeVariable = newBound.typeVariable
val typeBounds = getTypeBounds(typeVariable) val typeBounds = getTypeBounds(typeVariable)
for (oldBoundIndex in typeBounds.bounds.indices) { for (oldBoundIndex in typeBounds.bounds.indices) {
@@ -44,20 +44,18 @@ fun ConstraintSystemImpl.incorporateBound(variable: JetType, newBound: Bound) {
val boundsUsedIn = getBoundsUsedIn(typeVariable) val boundsUsedIn = getBoundsUsedIn(typeVariable)
for (index in boundsUsedIn.indices) { for (index in boundsUsedIn.indices) {
val boundUsedIn = boundsUsedIn[index] val boundUsedIn = boundsUsedIn[index]
val type = JetTypeImpl(Annotations.EMPTY, boundUsedIn.typeVariable.getTypeConstructor(), false, listOf(), JetScope.Empty) generateNewBound(boundUsedIn, newBound)
generateNewBound(type, boundUsedIn, newBound)
} }
val constrainingType = newBound.constrainingType val constrainingType = newBound.constrainingType
if (isMyTypeVariable(constrainingType)) { if (isMyTypeVariable(constrainingType)) {
val bound = Bound(variable, newBound.kind.reverse(), newBound.position, isProper = false) addBound(getMyTypeVariable(constrainingType)!!, typeVariable.correspondingType, newBound.kind.reverse(), newBound.position)
addBound(constrainingType, bound)
return return
} }
constrainingType.getNestedTypeVariables().forEach { constrainingType.getNestedTypeVariables().forEach {
val boundsForNestedVariable = getTypeBounds(it).bounds val boundsForNestedVariable = getTypeBounds(it).bounds
for (index in boundsForNestedVariable.indices) { for (index in boundsForNestedVariable.indices) {
generateNewBound(variable, newBound, boundsForNestedVariable[index]) generateNewBound(newBound, boundsForNestedVariable[index])
} }
} }
} }
@@ -82,7 +80,6 @@ private fun ConstraintSystemImpl.addConstraintFromBounds(old: Bound, new: Bound)
} }
private fun ConstraintSystemImpl.generateNewBound( private fun ConstraintSystemImpl.generateNewBound(
variable: JetType,
bound: Bound, bound: Bound,
substitution: Bound substitution: Bound
) { ) {
@@ -110,7 +107,7 @@ private fun ConstraintSystemImpl.generateNewBound(
if (nestedTypeVariables.contains(bound.typeVariable) || nestedTypeVariables.contains(substitution.typeVariable)) return if (nestedTypeVariables.contains(bound.typeVariable) || nestedTypeVariables.contains(substitution.typeVariable)) return
val position = CompoundConstraintPosition(bound.position, substitution.position) val position = CompoundConstraintPosition(bound.position, substitution.position)
addBound(variable, Bound(newConstrainingType, newKind, position, newConstrainingType.isProper())) addBound(bound.typeVariable, newConstrainingType, newKind, position)
} }
private fun computeKindOfNewBound(constrainingKind: BoundKind, substitutionVariance: Variance, substitutionKind: BoundKind): BoundKind? { private fun computeKindOfNewBound(constrainingKind: BoundKind, substitutionVariance: Variance, substitutionKind: BoundKind): BoundKind? {