Make ConstraintSystem work with variables, provide API to map to descriptors
This commit is contained in:
@@ -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<CannotCapture>()?.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<Collection<KotlinType>> = Renderer { renderTypes(it) }
|
||||
|
||||
private fun renderConstraintSystem(constraintSystem: ConstraintSystem, renderTypeBounds: Renderer<TypeBounds>): String {
|
||||
val typeVariables = constraintSystem.typeParameterDescriptors
|
||||
val typeBounds = linkedSetOf<TypeBounds>()
|
||||
for (variable in typeVariables) {
|
||||
for (variable in constraintSystem.typeVariables) {
|
||||
typeBounds.add(constraintSystem.getTypeBounds(variable))
|
||||
}
|
||||
return "type parameter bounds:\n" +
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+5
-1
@@ -36,11 +36,15 @@ interface ConstraintSystem {
|
||||
*/
|
||||
val typeVariables: Set<TypeParameterDescriptor>
|
||||
|
||||
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).
|
||||
|
||||
+7
-7
@@ -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 {
|
||||
|
||||
+12
-9
@@ -112,8 +112,9 @@ internal class ConstraintSystemImpl(
|
||||
|
||||
override fun getNestedTypeVariables(type: KotlinType): List<TypeParameterDescriptor> {
|
||||
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<TypeParameterDescriptor>
|
||||
@@ -122,13 +123,15 @@ internal class ConstraintSystemImpl(
|
||||
override val typeVariables: Set<TypeParameterDescriptor>
|
||||
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
|
||||
|
||||
+17
-16
@@ -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<TypeSubstitutor> 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<KotlinType> conflictingTypes = constraintSystem.getTypeBounds(firstConflictingParameter).getValues();
|
||||
Collection<KotlinType> conflictingTypes = constraintSystem.getTypeBounds(firstConflictingVariable).getValues();
|
||||
|
||||
List<Map<TypeConstructor, TypeProjection>> 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<TypeConstructor, TypeProjection> context : substitutionContexts) {
|
||||
TypeProjection typeProjection = new TypeProjectionImpl(safeType);
|
||||
context.put(typeParameter.getTypeConstructor(), typeProjection);
|
||||
context.put(constraintSystem.variableToDescriptor(typeVariable).getTypeConstructor(), typeProjection);
|
||||
}
|
||||
}
|
||||
Collection<TypeSubstitutor> typeSubstitutors = Lists.newArrayList();
|
||||
Collection<TypeSubstitutor> typeSubstitutors = new ArrayList<TypeSubstitutor>(substitutionContexts.size());
|
||||
for (Map<TypeConstructor, TypeProjection> 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 &&
|
||||
|
||||
Reference in New Issue
Block a user