From dd4a7ac6a9d2828dba0222224fc699224cb1b962 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 2 Nov 2015 19:11:13 +0300 Subject: [PATCH] Make ConstraintSystem work with variables, provide API to map to descriptors --- .../kotlin/diagnostics/rendering/Renderers.kt | 51 +++++++++---------- .../resolve/calls/GenericCandidateResolver.kt | 2 +- .../calls/inference/ConstraintSystem.kt | 6 ++- .../inference/ConstraintSystemBuilderImpl.kt | 14 ++--- .../calls/inference/ConstraintSystemImpl.kt | 21 ++++---- .../calls/inference/ConstraintsUtil.java | 33 ++++++------ 6 files changed, 67 insertions(+), 60 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index f64820ee648..ff7b6cec515 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.types.TypeIntersector import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.PrintWriter import java.io.StringWriter @@ -162,15 +163,15 @@ public object Renderers { substitutedDescriptors.add(substitutedDescriptor) } - val firstConflictingParameter = ConstraintsUtil.getFirstConflictingParameter(inferenceErrorData.constraintSystem) - if (firstConflictingParameter == null) { + val firstConflictingVariable = ConstraintsUtil.getFirstConflictingVariable(inferenceErrorData.constraintSystem) + if (firstConflictingVariable == null) { LOG.error(renderDebugMessage("There is no conflicting parameter for 'conflicting constraints' error.", inferenceErrorData)) return result } result.text(newText() .normal("Cannot infer type parameter ") - .strong(firstConflictingParameter.getName()) + .strong(firstConflictingVariable.name) .normal(" in ")) val table = newTable() result.table(table) @@ -224,21 +225,15 @@ public object Renderers { public fun renderNoInformationForParameterError( inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer ): TabledDescriptorRenderer { - var firstUnknownParameter: TypeParameterDescriptor? = null - for (typeParameter in inferenceErrorData.constraintSystem.typeParameterDescriptors) { - if (inferenceErrorData.constraintSystem.getTypeBounds(typeParameter).values.isEmpty()) { - firstUnknownParameter = typeParameter - break - } - } - if (firstUnknownParameter == null) { + val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable -> + inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty() + } ?: return result.apply { LOG.error(renderDebugMessage("There is no unknown parameter for 'no information for parameter error'.", inferenceErrorData)) - return result } return result .text(newText().normal("Not enough information to infer parameter ") - .strong(firstUnknownParameter.getName()) + .strong(firstUnknownVariable.name) .normal(" in ")) .table(newTable() .descriptor(inferenceErrorData.descriptor) @@ -266,7 +261,8 @@ public object Renderers { return result } - val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeParameterDescriptor).value + val inferredValueForTypeParameter = + systemWithoutWeakConstraints.getTypeBounds(systemWithoutWeakConstraints.descriptorToVariable(typeParameterDescriptor)).value if (inferredValueForTypeParameter == null) { LOG.error(renderDebugMessage("System without weak constraints is not successful, there is no value for type parameter " + typeParameterDescriptor.getName() + "\n: " + systemWithoutWeakConstraints, inferenceErrorData)) @@ -308,15 +304,15 @@ public object Renderers { public fun renderCannotCaptureTypeParameterError( inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer ): TabledDescriptorRenderer { - val constraintSystem = inferenceErrorData.constraintSystem - val errors = constraintSystem.status.constraintErrors - val typeParameterWithCapturedConstraint = (errors.firstOrNull { it is CannotCapture } as? CannotCapture)?.typeVariable - if (typeParameterWithCapturedConstraint == null) { + val system = inferenceErrorData.constraintSystem + val errors = system.status.constraintErrors + val typeVariableWithCapturedConstraint = errors.firstIsInstanceOrNull()?.typeVariable + if (typeVariableWithCapturedConstraint == null) { LOG.error(renderDebugMessage("An error 'cannot capture type parameter' is not found in errors", inferenceErrorData)) return result } - val typeBounds = constraintSystem.getTypeBounds(typeParameterWithCapturedConstraint) + val typeBounds = system.getTypeBounds(typeVariableWithCapturedConstraint) val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() } val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.getConstructor() as? CapturedTypeConstructor if (capturedTypeConstructor == null) { @@ -324,8 +320,10 @@ public object Renderers { return result } + val typeParameter = system.variableToDescriptor(typeVariableWithCapturedConstraint) + val explanation: String - val upperBound = TypeIntersector.getUpperBoundsAsType(typeParameterWithCapturedConstraint) + val upperBound = TypeIntersector.getUpperBoundsAsType(typeParameter) if (!KotlinBuiltIns.isNullableAny(upperBound) && capturedTypeConstructor.typeProjection.getProjectionKind() == Variance.IN_VARIANCE) { explanation = "Type parameter has an upper bound '" + result.getTypeRenderer().render(upperBound) + "'" + " that cannot be satisfied capturing 'in' projection" @@ -333,10 +331,12 @@ public object Renderers { else { explanation = "Only top-level type projections can be captured" } - result.text(newText().normal("'" + typeParameterWithCapturedConstraint.getName() + "'" + - " cannot capture " + - "'" + capturedTypeConstructor.typeProjection + "'. " + - explanation)) + result.text(newText().normal( + "'" + typeParameter.name + "'" + + " cannot capture " + + "'" + capturedTypeConstructor.typeProjection + "'. " + + explanation + )) return result } @@ -362,9 +362,8 @@ public object Renderers { public val RENDER_COLLECTION_OF_TYPES: Renderer> = Renderer { renderTypes(it) } private fun renderConstraintSystem(constraintSystem: ConstraintSystem, renderTypeBounds: Renderer): String { - val typeVariables = constraintSystem.typeParameterDescriptors val typeBounds = linkedSetOf() - for (variable in typeVariables) { + for (variable in constraintSystem.typeVariables) { typeBounds.add(constraintSystem.getTypeBounds(variable)) } return "type parameter bounds:\n" + diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index 38a69d54c9a..baac6dab5c4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -165,7 +165,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidateDescriptor) val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap() - val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull() + val freshVariables = nestedTypeVariables.map { conversion[argumentConstraintSystem.variableToDescriptor(it)] }.filterNotNull() builder.registerTypeVariables(freshVariables, external = true) builder.addSubtypeConstraint(candidateWithFreshVariables.returnType, effectiveExpectedType, constraintPosition) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt index 560b0ec2e7f..e52ef4ee25a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt @@ -36,11 +36,15 @@ interface ConstraintSystem { */ val typeVariables: Set + fun descriptorToVariable(descriptor: TypeParameterDescriptor): TypeParameterDescriptor + + fun variableToDescriptor(typeVariable: TypeParameterDescriptor): 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 + fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds /** * Returns the result of solving the constraint system (mapping from the type variable to the resulting type projection). diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt index 7cc143db9df..b040f200320 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt @@ -149,15 +149,15 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { return true } - override fun capture(typeVariable: KotlinType, typeProjection: TypeProjection): Boolean { + override fun capture(type: KotlinType, typeProjection: TypeProjection): Boolean { if (isMyTypeVariable(typeProjection.type)) return false - val myTypeVariable = getMyTypeVariable(typeVariable) + val myTypeVariable = getMyTypeVariable(type) if (myTypeVariable != null && constraintPosition.isParameter()) { if (depth > 0) { errors.add(CannotCapture(constraintPosition, myTypeVariable)) } - generateTypeParameterCaptureConstraint(typeVariable, typeProjection, newConstraintContext) + generateTypeParameterCaptureConstraint(myTypeVariable, typeProjection, newConstraintContext, type.isMarkedNullable) return true } return false @@ -311,16 +311,16 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { } private fun generateTypeParameterCaptureConstraint( - parameterType: KotlinType, + typeVariable: TypeParameterDescriptor, constrainingTypeProjection: TypeProjection, - constraintContext: ConstraintContext + constraintContext: ConstraintContext, + isTypeMarkedNullable: Boolean ) { - val typeVariable = getMyTypeVariable(parameterType)!! if (!typeVariable.upperBounds.let { it.size == 1 && it.single().isDefaultBound() } && constrainingTypeProjection.projectionKind == Variance.IN_VARIANCE) { errors.add(CannotCapture(constraintContext.position, typeVariable)) } - val typeProjection = if (parameterType.isMarkedNullable) { + val typeProjection = if (isTypeMarkedNullable) { TypeProjectionImpl(constrainingTypeProjection.projectionKind, TypeUtils.makeNotNullable(constrainingTypeProjection.type)) } else { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index 19b61c74e24..1e5d6e52d19 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -112,8 +112,9 @@ internal class ConstraintSystemImpl( override fun getNestedTypeVariables(type: KotlinType): List { return type.getNestedArguments().map { typeProjection -> - typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor - }.filterNotNull().filter { it in typeParameterDescriptors } + val descriptor = typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor + descriptor?.let { descriptorToVariable[it] } + }.filterNotNull() } override val typeParameterDescriptors: Set @@ -122,13 +123,15 @@ internal class ConstraintSystemImpl( override val typeVariables: Set get() = variableToDescriptor.keys - override fun getTypeBounds(descriptor: TypeParameterDescriptor): TypeBoundsImpl { - val variable = descriptorToVariable[descriptor] - if (variable != null && variable != descriptor) { - return getTypeBounds(variable) - } - return allTypeParameterBounds[descriptor] ?: - throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $descriptor") + override fun descriptorToVariable(descriptor: TypeParameterDescriptor): TypeParameterDescriptor = + descriptorToVariable[descriptor] ?: throw IllegalArgumentException("Unknown descriptor: $descriptor") + + override fun variableToDescriptor(typeVariable: TypeParameterDescriptor): TypeParameterDescriptor = + variableToDescriptor[typeVariable] ?: throw IllegalArgumentException("Unknown type variable: $typeVariable") + + override fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBoundsImpl { + return allTypeParameterBounds[typeVariable] ?: + throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable") } override val resultingSubstitutor: TypeSubstitutor diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java index 6f4009693e6..50a31ca36ee 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java @@ -30,11 +30,11 @@ import java.util.*; public class ConstraintsUtil { @Nullable - public static TypeParameterDescriptor getFirstConflictingParameter(@NotNull ConstraintSystem constraintSystem) { - for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeParameterDescriptors()) { - TypeBounds constraints = constraintSystem.getTypeBounds(typeParameter); + public static TypeParameterDescriptor getFirstConflictingVariable(@NotNull ConstraintSystem constraintSystem) { + for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) { + TypeBounds constraints = constraintSystem.getTypeBounds(typeVariable); if (constraints.getValues().size() > 1) { - return typeParameter; + return typeVariable; } } return null; @@ -42,10 +42,11 @@ public class ConstraintsUtil { @NotNull public static Collection getSubstitutorsForConflictingParameters(@NotNull ConstraintSystem constraintSystem) { - TypeParameterDescriptor firstConflictingParameter = getFirstConflictingParameter(constraintSystem); - if (firstConflictingParameter == null) return Collections.emptyList(); + TypeParameterDescriptor firstConflictingVariable = getFirstConflictingVariable(constraintSystem); + if (firstConflictingVariable == null) return Collections.emptyList(); + TypeParameterDescriptor firstConflictingParameter = constraintSystem.variableToDescriptor(firstConflictingVariable); - Collection conflictingTypes = constraintSystem.getTypeBounds(firstConflictingParameter).getValues(); + Collection conflictingTypes = constraintSystem.getTypeBounds(firstConflictingVariable).getValues(); List> substitutionContexts = Lists.newArrayList(); for (KotlinType type : conflictingTypes) { @@ -54,16 +55,16 @@ public class ConstraintsUtil { substitutionContexts.add(context); } - for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeParameterDescriptors()) { - if (typeParameter == firstConflictingParameter) continue; + for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) { + if (typeVariable == firstConflictingVariable) continue; - KotlinType safeType = getSafeValue(constraintSystem, typeParameter); + KotlinType safeType = getSafeValue(constraintSystem, typeVariable); for (Map context : substitutionContexts) { TypeProjection typeProjection = new TypeProjectionImpl(safeType); - context.put(typeParameter.getTypeConstructor(), typeProjection); + context.put(constraintSystem.variableToDescriptor(typeVariable).getTypeConstructor(), typeProjection); } } - Collection typeSubstitutors = Lists.newArrayList(); + Collection typeSubstitutors = new ArrayList(substitutionContexts.size()); for (Map context : substitutionContexts) { typeSubstitutors.add(TypeSubstitutor.create(context)); } @@ -71,13 +72,13 @@ public class ConstraintsUtil { } @NotNull - public static KotlinType getSafeValue(@NotNull ConstraintSystem constraintSystem, @NotNull TypeParameterDescriptor typeParameter) { - KotlinType type = constraintSystem.getTypeBounds(typeParameter).getValue(); + private static KotlinType getSafeValue(@NotNull ConstraintSystem constraintSystem, @NotNull TypeParameterDescriptor typeVariable) { + KotlinType type = constraintSystem.getTypeBounds(typeVariable).getValue(); if (type != null) { return type; } //todo may be error type - return TypeIntersector.getUpperBoundsAsType(typeParameter); + return TypeIntersector.getUpperBoundsAsType(constraintSystem.variableToDescriptor(typeVariable)); } public static boolean checkUpperBoundIsSatisfied( @@ -85,7 +86,7 @@ public class ConstraintsUtil { @NotNull TypeParameterDescriptor typeParameter, boolean substituteOtherTypeParametersInBound ) { - KotlinType type = constraintSystem.getTypeBounds(typeParameter).getValue(); + KotlinType type = constraintSystem.getTypeBounds(constraintSystem.descriptorToVariable(typeParameter)).getValue(); if (type == null) return true; for (KotlinType upperBound : typeParameter.getUpperBounds()) { if (!substituteOtherTypeParametersInBound &&