diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index 4e620384132..64ab20e08e2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -57,6 +57,8 @@ public class ConstraintSystemImpl : ConstraintSystem { get() = if (externalTypeParameters.isEmpty()) allTypeParameterBounds else allTypeParameterBounds.filter { !externalTypeParameters.contains(it.key) } + private val cachedTypeForVariable = HashMap() + private val usedInBounds = HashMap>() private val errors = ArrayList() @@ -139,12 +141,16 @@ public class ConstraintSystemImpl : ConstraintSystem { for (declaredUpperBound in typeVariable.getUpperBounds()) { if (KotlinBuiltIns.getInstance().getNullableAnyType() == declaredUpperBound) continue //todo remove this line (?) val position = TYPE_BOUND_POSITION.position(typeVariable.getIndex()) - val variableType = JetTypeImpl(Annotations.EMPTY, typeVariable.getTypeConstructor(), false, listOf(), JetScope.Empty) - addBound(variableType, Bound(declaredUpperBound, UPPER_BOUND, position, declaredUpperBound.isProper())) + addBound(typeVariable, declaredUpperBound, UPPER_BOUND, position) } } } + val TypeParameterDescriptor.correspondingType: JetType + get() = cachedTypeForVariable.getOrPut(this) { + JetTypeImpl(Annotations.EMPTY, this.getTypeConstructor(), false, listOf(), JetScope.Empty) + } + fun JetType.isProper() = !TypeUtils.containsSpecialType(this) { type -> type.getConstructor().getDeclarationDescriptor() in getAllTypeVariables() } @@ -321,8 +327,14 @@ public class ConstraintSystemImpl : ConstraintSystem { } - fun addBound(variable: JetType, bound: Bound) { - val typeBounds = getTypeBounds(variable) + fun addBound( + 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 typeBounds.addBound(bound) @@ -334,7 +346,7 @@ public class ConstraintSystemImpl : ConstraintSystem { } } - incorporateBound(variable, bound) + incorporateBound(bound) } private fun generateTypeParameterBound( @@ -343,6 +355,8 @@ public class ConstraintSystemImpl : ConstraintSystem { boundKind: TypeBounds.BoundKind, constraintPosition: ConstraintPosition ) { + val typeVariable = getMyTypeVariable(parameterType)!! + var newConstrainingType = constrainingType // Here we are handling the case when T! gets a bound Foo (or Foo?) @@ -354,14 +368,14 @@ public class ConstraintSystemImpl : ConstraintSystem { // Foo >: T! // both Foo and Foo? transform to Foo! here if (parameterType.isFlexible()) { - val typeVariable = parameterType.getCustomTypeVariable() - if (typeVariable != null) { - newConstrainingType = typeVariable.substitutionResult(constrainingType) + val customTypeVariable = parameterType.getCustomTypeVariable() + if (customTypeVariable != null) { + newConstrainingType = customTypeVariable.substitutionResult(constrainingType) } } if (!parameterType.isMarkedNullable() || !TypeUtils.isNullableType(newConstrainingType)) { - addBound(parameterType, Bound(newConstrainingType, boundKind, constraintPosition, newConstrainingType.isProper())) + addBound(typeVariable, newConstrainingType, boundKind, constraintPosition) return } // For parameter type T: @@ -369,14 +383,13 @@ public class ConstraintSystemImpl : ConstraintSystem { // constraint T? = Int! should transform to T >: Int and T <: Int! // constraints T? >: Int?; T? >: Int! should transform to T >: Int - val notNullParameterType = TypeUtils.makeNotNullable(parameterType) val notNullConstrainingType = TypeUtils.makeNotNullable(newConstrainingType) 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 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 } val capturedType = createCapturedType(typeProjection) - addBound(TypeUtils.makeNotNullable(parameterType), Bound(capturedType, EXACT_BOUND, constraintPosition)) + addBound(typeVariable, capturedType, EXACT_BOUND, constraintPosition) } override fun getTypeVariables() = typeParameterBounds.keySet() @@ -441,8 +454,7 @@ public class ConstraintSystemImpl : ConstraintSystem { val value = typeBounds.value ?: return - val type = JetTypeImpl(Annotations.EMPTY, typeVariable.getTypeConstructor(), false, emptyList(), JetScope.Empty) - addBound(type, TypeBounds.Bound(value, TypeBounds.BoundKind.EXACT_BOUND, ConstraintPositionKind.FROM_COMPLETER.position())) + addBound(typeVariable, value, TypeBounds.BoundKind.EXACT_BOUND, ConstraintPositionKind.FROM_COMPLETER.position()) } fun fixVariables() { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBounds.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBounds.kt index 4ac4d79d743..ff52b07e878 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBounds.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBounds.kt @@ -45,19 +45,19 @@ public trait TypeBounds { } public class Bound( + public val typeVariable: TypeParameterDescriptor, public val constrainingType: JetType, public val kind: BoundKind, public val position: ConstraintPosition, public val isProper: Boolean = true ) { - public var typeVariable: TypeParameterDescriptor by Delegates.notNull() - override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || javaClass != other.javaClass) return false val bound = other as Bound + if (typeVariable != bound.typeVariable) return false if (constrainingType != bound.constrainingType) return false if (kind != bound.kind) return false @@ -67,7 +67,8 @@ public trait TypeBounds { } 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 + if (position.isStrong()) 1 else 0 return result diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt index 1a05aaeef8d..0137e7062cb 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt @@ -49,7 +49,9 @@ public class TypeBoundsImpl( public fun addBound(bound: Bound) { 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) } @@ -202,9 +204,7 @@ fun Collection.substitute(substituteTypeVariable: (TypeParameterDescripto it.constrainingType } substitutedType?.let { type -> - val newBound = Bound(type, it.kind, it.position, it.isProper) - newBound.typeVariable = substituteTypeVariable(it.typeVariable) ?: it.typeVariable - newBound + Bound(substituteTypeVariable(it.typeVariable) ?: it.typeVariable, type, it.kind, it.position, it.isProper) } }.filterNotNull() } \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/constraintIncorporation.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/constraintIncorporation.kt index 821a129c10b..b1167b1a5bf 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/constraintIncorporation.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/constraintIncorporation.kt @@ -34,8 +34,8 @@ import org.jetbrains.kotlin.types.Variance.IN_VARIANCE import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments import java.util.ArrayList -fun ConstraintSystemImpl.incorporateBound(variable: JetType, newBound: Bound) { - val typeVariable = getMyTypeVariable(variable)!! +fun ConstraintSystemImpl.incorporateBound(newBound: Bound) { + val typeVariable = newBound.typeVariable val typeBounds = getTypeBounds(typeVariable) for (oldBoundIndex in typeBounds.bounds.indices) { @@ -44,20 +44,18 @@ fun ConstraintSystemImpl.incorporateBound(variable: JetType, newBound: Bound) { val boundsUsedIn = getBoundsUsedIn(typeVariable) for (index in boundsUsedIn.indices) { val boundUsedIn = boundsUsedIn[index] - val type = JetTypeImpl(Annotations.EMPTY, boundUsedIn.typeVariable.getTypeConstructor(), false, listOf(), JetScope.Empty) - generateNewBound(type, boundUsedIn, newBound) + generateNewBound(boundUsedIn, newBound) } val constrainingType = newBound.constrainingType if (isMyTypeVariable(constrainingType)) { - val bound = Bound(variable, newBound.kind.reverse(), newBound.position, isProper = false) - addBound(constrainingType, bound) + addBound(getMyTypeVariable(constrainingType)!!, typeVariable.correspondingType, newBound.kind.reverse(), newBound.position) return } constrainingType.getNestedTypeVariables().forEach { val boundsForNestedVariable = getTypeBounds(it).bounds 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( - variable: JetType, bound: Bound, substitution: Bound ) { @@ -110,7 +107,7 @@ private fun ConstraintSystemImpl.generateNewBound( if (nestedTypeVariables.contains(bound.typeVariable) || nestedTypeVariables.contains(substitution.typeVariable)) return 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? {