First steps to make distinction between variables and descriptors in ConstraintSystem

A type variable is an entity, the value of which should be solved by the
system; a descriptor is an actual TypeParameterDescriptor declaration
This commit is contained in:
Alexander Udalov
2015-11-02 15:56:02 +03:00
parent eeb925f127
commit 13abc265ad
6 changed files with 56 additions and 49 deletions
@@ -225,7 +225,7 @@ public object Renderers {
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer { ): TabledDescriptorRenderer {
var firstUnknownParameter: TypeParameterDescriptor? = null var firstUnknownParameter: TypeParameterDescriptor? = null
for (typeParameter in inferenceErrorData.constraintSystem.typeVariables) { for (typeParameter in inferenceErrorData.constraintSystem.typeParameterDescriptors) {
if (inferenceErrorData.constraintSystem.getTypeBounds(typeParameter).values.isEmpty()) { if (inferenceErrorData.constraintSystem.getTypeBounds(typeParameter).values.isEmpty()) {
firstUnknownParameter = typeParameter firstUnknownParameter = typeParameter
break break
@@ -362,7 +362,7 @@ public object Renderers {
public val RENDER_COLLECTION_OF_TYPES: Renderer<Collection<KotlinType>> = Renderer { renderTypes(it) } public val RENDER_COLLECTION_OF_TYPES: Renderer<Collection<KotlinType>> = Renderer { renderTypes(it) }
private fun renderConstraintSystem(constraintSystem: ConstraintSystem, renderTypeBounds: Renderer<TypeBounds>): String { private fun renderConstraintSystem(constraintSystem: ConstraintSystem, renderTypeBounds: Renderer<TypeBounds>): String {
val typeVariables = constraintSystem.typeVariables val typeVariables = constraintSystem.typeParameterDescriptors
val typeBounds = linkedSetOf<TypeBounds>() val typeBounds = linkedSetOf<TypeBounds>()
for (variable in typeVariables) { for (variable in typeVariables) {
typeBounds.add(constraintSystem.getTypeBounds(variable)) typeBounds.add(constraintSystem.getTypeBounds(variable))
@@ -24,18 +24,23 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.TypeSubstitutor
interface ConstraintSystem { interface ConstraintSystem {
/**
* Returns a set of all non-external registered type variables.
*/
val typeVariables: Set<TypeParameterDescriptor>
val status: ConstraintSystemStatus val status: ConstraintSystemStatus
/** /**
* Returns the resulting type constraints of solving the constraint system for specific type variable. * Returns a set of all non-external type parameter descriptors.
* Throws IllegalArgumentException if the type variable was not registered.
*/ */
fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds val typeParameterDescriptors: Set<TypeParameterDescriptor>
/**
* Returns a set of all registered type variables.
*/
val typeVariables: Set<TypeParameterDescriptor>
/**
* Returns the resulting type constraints of solving the constraint system for specific type parameter descriptor.
* Throws IllegalArgumentException if the type parameter descriptor is not known to the system.
*/
fun getTypeBounds(descriptor: TypeParameterDescriptor): TypeBounds
/** /**
* Returns the result of solving the constraint system (mapping from the type variable to the resulting type projection). * Returns the result of solving the constraint system (mapping from the type variable to the resulting type projection).
@@ -65,7 +70,7 @@ interface ConstraintSystem {
*/ */
fun registerTypeVariables( fun registerTypeVariables(
typeVariables: Collection<TypeParameterDescriptor>, typeVariables: Collection<TypeParameterDescriptor>,
mapToOriginal: (TypeParameterDescriptor) -> TypeParameterDescriptor = { it }, mapToDescriptor: (TypeParameterDescriptor) -> TypeParameterDescriptor = { it },
external: Boolean = false external: Boolean = false
) )
@@ -54,15 +54,15 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
internal val usedInBounds = HashMap<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>() internal val usedInBounds = HashMap<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>()
internal val errors = ArrayList<ConstraintError>() internal val errors = ArrayList<ConstraintError>()
internal val initialConstraints = ArrayList<Constraint>() internal val initialConstraints = ArrayList<Constraint>()
internal val originalToVariables = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>() internal val descriptorToVariable = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
internal val variablesToOriginal = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>() internal val variableToDescriptor = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
private val originalToVariablesSubstitutor: TypeSubstitutor by lazy { private val descriptorToVariableSubstitutor: TypeSubstitutor by lazy {
TypeSubstitutor.create(object : TypeConstructorSubstitution() { TypeSubstitutor.create(object : TypeConstructorSubstitution() {
override fun get(key: TypeConstructor): TypeProjection? { override fun get(key: TypeConstructor): TypeProjection? {
val descriptor = key.declarationDescriptor val descriptor = key.declarationDescriptor
if (descriptor !is TypeParameterDescriptor) return null if (descriptor !is TypeParameterDescriptor) return null
val typeParameterDescriptor = originalToVariables[descriptor] ?: return null val typeParameterDescriptor = descriptorToVariable[descriptor] ?: return null
return TypeProjectionImpl(typeParameterDescriptor.defaultType) return TypeProjectionImpl(typeParameterDescriptor.defaultType)
} }
}) })
@@ -70,16 +70,16 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
override fun registerTypeVariables( override fun registerTypeVariables(
typeVariables: Collection<TypeParameterDescriptor>, typeVariables: Collection<TypeParameterDescriptor>,
mapToOriginal: (TypeParameterDescriptor) -> TypeParameterDescriptor, mapToDescriptor: (TypeParameterDescriptor) -> TypeParameterDescriptor,
external: Boolean external: Boolean
) { ) {
if (external) externalTypeParameters.addAll(typeVariables) if (external) externalTypeParameters.addAll(typeVariables)
for (typeVariable in typeVariables) { for (typeVariable in typeVariables) {
allTypeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable)) allTypeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable))
val original = mapToOriginal(typeVariable) val descriptor = mapToDescriptor(typeVariable)
originalToVariables[original] = typeVariable descriptorToVariable[descriptor] = typeVariable
variablesToOriginal[typeVariable] = original variableToDescriptor[typeVariable] = descriptor
} }
for ((typeVariable, typeBounds) in allTypeParameterBounds) { for ((typeVariable, typeBounds) in allTypeParameterBounds) {
for (declaredUpperBound in typeVariable.upperBounds) { for (declaredUpperBound in typeVariable.upperBounds) {
@@ -102,18 +102,18 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
internal fun getNestedTypeVariables(type: KotlinType, original: Boolean): List<TypeParameterDescriptor> { internal fun getNestedTypeVariables(type: KotlinType, original: Boolean): List<TypeParameterDescriptor> {
return type.getNestedArguments().map { typeProjection -> return type.getNestedArguments().map { typeProjection ->
typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor
}.filterNotNull().filter { if (original) it in originalToVariables.keys else isMyTypeVariable(it) } }.filterNotNull().filter { if (original) it in descriptorToVariable.keys else isMyTypeVariable(it) }
} }
override fun addSupertypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) { override fun addSupertypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) {
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return
val newSubjectType = originalToVariablesSubstitutor.substitute(subjectType, Variance.INVARIANT) val newSubjectType = descriptorToVariableSubstitutor.substitute(subjectType, Variance.INVARIANT)
addConstraint(SUB_TYPE, newSubjectType, constrainingType, ConstraintContext(constraintPosition, initial = true)) addConstraint(SUB_TYPE, newSubjectType, constrainingType, ConstraintContext(constraintPosition, initial = true))
} }
override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) { override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) {
val newSubjectType = originalToVariablesSubstitutor.substitute(subjectType, Variance.INVARIANT) val newSubjectType = descriptorToVariableSubstitutor.substitute(subjectType, Variance.INVARIANT)
addConstraint(SUB_TYPE, constrainingType, newSubjectType, ConstraintContext(constraintPosition, initial = true)) addConstraint(SUB_TYPE, constrainingType, newSubjectType, ConstraintContext(constraintPosition, initial = true))
} }
@@ -332,15 +332,13 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
internal fun getBoundsUsedIn(typeVariable: TypeParameterDescriptor): List<Bound> = usedInBounds[typeVariable] ?: emptyList() internal fun getBoundsUsedIn(typeVariable: TypeParameterDescriptor): List<Bound> = usedInBounds[typeVariable] ?: emptyList()
internal fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBoundsImpl { internal fun getTypeBounds(descriptor: TypeParameterDescriptor): TypeBoundsImpl {
val variableForOriginal = originalToVariables[typeVariable] val variable = descriptorToVariable[descriptor]
if (variableForOriginal != null && variableForOriginal != typeVariable) { if (variable != null && variable != descriptor) {
return getTypeBounds(variableForOriginal) return getTypeBounds(variable)
} }
if (!isMyTypeVariable(typeVariable)) { return allTypeParameterBounds[descriptor] ?:
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable") throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $descriptor")
}
return allTypeParameterBounds[typeVariable]!!
} }
private fun isMyTypeVariable(typeVariable: TypeParameterDescriptor) = allTypeParameterBounds.contains(typeVariable) private fun isMyTypeVariable(typeVariable: TypeParameterDescriptor) = allTypeParameterBounds.contains(typeVariable)
@@ -378,7 +376,7 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
override fun build(): ConstraintSystem { override fun build(): ConstraintSystem {
return ConstraintSystemImpl(allTypeParameterBounds, externalTypeParameters, usedInBounds, errors, initialConstraints, return ConstraintSystemImpl(allTypeParameterBounds, externalTypeParameters, usedInBounds, errors, initialConstraints,
originalToVariables, variablesToOriginal) descriptorToVariable, variableToDescriptor)
} }
} }
@@ -41,8 +41,8 @@ internal class ConstraintSystemImpl(
private val usedInBounds: Map<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>, private val usedInBounds: Map<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>,
private val errors: List<ConstraintError>, private val errors: List<ConstraintError>,
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>, private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
private val originalToVariables: Map<TypeParameterDescriptor, TypeParameterDescriptor>, private val descriptorToVariable: Map<TypeParameterDescriptor, TypeParameterDescriptor>,
private val variablesToOriginal: Map<TypeParameterDescriptor, TypeParameterDescriptor> private val variableToDescriptor: Map<TypeParameterDescriptor, TypeParameterDescriptor>
) : ConstraintSystem { ) : ConstraintSystem {
private val localTypeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl> private val localTypeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>
get() = if (externalTypeParameters.isEmpty()) allTypeParameterBounds get() = if (externalTypeParameters.isEmpty()) allTypeParameterBounds
@@ -92,7 +92,7 @@ internal class ConstraintSystemImpl(
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>() val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
for ((variable, typeBounds) in typeParameterBounds) { for ((variable, typeBounds) in typeParameterBounds) {
val value = typeBounds.value val value = typeBounds.value
val typeParameter = if (substituteOriginal) variablesToOriginal[variable]!! else variable val typeParameter = if (substituteOriginal) variableToDescriptor[variable]!! else variable
val type = val type =
if (value != null && !TypeUtils.containsSpecialType(value, DONT_CARE)) value if (value != null && !TypeUtils.containsSpecialType(value, DONT_CARE)) value
else getDefaultType(typeParameter) else getDefaultType(typeParameter)
@@ -113,19 +113,22 @@ internal class ConstraintSystemImpl(
override fun getNestedTypeVariables(type: KotlinType): List<TypeParameterDescriptor> { override fun getNestedTypeVariables(type: KotlinType): List<TypeParameterDescriptor> {
return type.getNestedArguments().map { typeProjection -> return type.getNestedArguments().map { typeProjection ->
typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor
}.filterNotNull().filter { it in typeVariables } }.filterNotNull().filter { it in typeParameterDescriptors }
} }
override val typeVariables: Set<TypeParameterDescriptor> override val typeParameterDescriptors: Set<TypeParameterDescriptor>
get() = originalToVariables.keys get() = descriptorToVariable.keys
override fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBoundsImpl { override val typeVariables: Set<TypeParameterDescriptor>
val variableForOriginal = originalToVariables[typeVariable] get() = variableToDescriptor.keys
if (variableForOriginal != null && variableForOriginal != typeVariable) {
return getTypeBounds(variableForOriginal) override fun getTypeBounds(descriptor: TypeParameterDescriptor): TypeBoundsImpl {
val variable = descriptorToVariable[descriptor]
if (variable != null && variable != descriptor) {
return getTypeBounds(variable)
} }
return allTypeParameterBounds[typeVariable] ?: return allTypeParameterBounds[descriptor] ?:
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable") throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $descriptor")
} }
override val resultingSubstitutor: TypeSubstitutor override val resultingSubstitutor: TypeSubstitutor
@@ -176,8 +179,8 @@ internal class ConstraintSystemImpl(
result.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) }) result.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
result.initialConstraints.addAll(initialConstraints.filter { filterConstraintPosition(it.position) }) result.initialConstraints.addAll(initialConstraints.filter { filterConstraintPosition(it.position) })
result.originalToVariables.putAll(originalToVariables) result.descriptorToVariable.putAll(descriptorToVariable)
result.variablesToOriginal.putAll(variablesToOriginal) result.variableToDescriptor.putAll(variableToDescriptor)
return result return result
} }
@@ -31,7 +31,7 @@ import java.util.*;
public class ConstraintsUtil { public class ConstraintsUtil {
@Nullable @Nullable
public static TypeParameterDescriptor getFirstConflictingParameter(@NotNull ConstraintSystem constraintSystem) { public static TypeParameterDescriptor getFirstConflictingParameter(@NotNull ConstraintSystem constraintSystem) {
for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeVariables()) { for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeParameterDescriptors()) {
TypeBounds constraints = constraintSystem.getTypeBounds(typeParameter); TypeBounds constraints = constraintSystem.getTypeBounds(typeParameter);
if (constraints.getValues().size() > 1) { if (constraints.getValues().size() > 1) {
return typeParameter; return typeParameter;
@@ -54,7 +54,7 @@ public class ConstraintsUtil {
substitutionContexts.add(context); substitutionContexts.add(context);
} }
for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeVariables()) { for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeParameterDescriptors()) {
if (typeParameter == firstConflictingParameter) continue; if (typeParameter == firstConflictingParameter) continue;
KotlinType safeType = getSafeValue(constraintSystem, typeParameter); KotlinType safeType = getSafeValue(constraintSystem, typeParameter);
@@ -88,7 +88,8 @@ public class ConstraintsUtil {
KotlinType type = constraintSystem.getTypeBounds(typeParameter).getValue(); KotlinType type = constraintSystem.getTypeBounds(typeParameter).getValue();
if (type == null) return true; if (type == null) return true;
for (KotlinType upperBound : typeParameter.getUpperBounds()) { for (KotlinType upperBound : typeParameter.getUpperBounds()) {
if (!substituteOtherTypeParametersInBound && TypeUtils.dependsOnTypeParameters(upperBound, constraintSystem.getTypeVariables())) { if (!substituteOtherTypeParametersInBound &&
TypeUtils.dependsOnTypeParameters(upperBound, constraintSystem.getTypeParameterDescriptors())) {
continue; continue;
} }
KotlinType substitutedUpperBound = constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT); KotlinType substitutedUpperBound = constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT);
@@ -138,7 +138,7 @@ class FuzzyType(
if (otherSubstitutedType.isError) return null if (otherSubstitutedType.isError) return null
if (!substitutedType.checkInheritance(otherSubstitutedType)) return null if (!substitutedType.checkInheritance(otherSubstitutedType)) return null
val substitution = constraintSystem.typeVariables.toMap({ it.typeConstructor }) { val substitution = constraintSystem.typeParameterDescriptors.toMap({ it.typeConstructor }) {
val type = it.defaultType val type = it.defaultType
val solution = substitutor.substitute(type, Variance.INVARIANT) val solution = substitutor.substitute(type, Variance.INVARIANT)
TypeProjectionImpl(if (solution != null && !ErrorUtils.containsUninferredParameter(solution)) solution else type) TypeProjectionImpl(if (solution != null && !ErrorUtils.containsUninferredParameter(solution)) solution else type)