Cache type corresponding to type variable
This commit is contained in:
+27
-15
@@ -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()
|
||||||
}
|
}
|
||||||
+6
-9
@@ -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? {
|
||||||
|
|||||||
Reference in New Issue
Block a user