Fixed rendering of error message for 'cannot capture type' error

Type variable should be chosen correctly
This commit is contained in:
Svetlana Isakova
2015-01-21 22:25:25 +03:00
parent 971ad53bcc
commit 6cac6350a6
6 changed files with 47 additions and 13 deletions
@@ -394,18 +394,26 @@ public class Renderers {
@NotNull InferenceErrorData inferenceErrorData,
@NotNull TabledDescriptorRenderer result
) {
ConstraintSystem constraintSystem = inferenceErrorData.constraintSystem;
ConstraintSystemImpl constraintSystem = (ConstraintSystemImpl) inferenceErrorData.constraintSystem;
List<ConstraintError> errors = constraintSystem.getConstraintErrors();
TypeParameterDescriptor typeParameterWithCapturedConstraint = null;
for (ConstraintError error : errors) {
if (error instanceof CannotCapture) {
typeParameterWithCapturedConstraint = ((CannotCapture) error).getTypeVariable();
}
}
if (typeParameterWithCapturedConstraint == null) {
LOG.error(renderDebugMessage("An error 'cannot capture type parameter' is not found in errors", inferenceErrorData));
return result;
}
CapturedTypeConstructor capturedTypeConstructor = null;
for (TypeParameterDescriptor typeParameter : constraintSystem.getTypeVariables()) {
TypeBounds typeBounds = constraintSystem.getTypeBounds(typeParameter);
TypeBounds typeBounds = constraintSystem.getTypeBounds(typeParameterWithCapturedConstraint);
for (TypeBounds.Bound bound : typeBounds.getBounds()) {
TypeConstructor constructor = bound.getConstrainingType().getConstructor();
if (constructor instanceof CapturedTypeConstructor) {
typeParameterWithCapturedConstraint = typeParameter;
capturedTypeConstructor = (CapturedTypeConstructor) constructor;
}
}
}
if (capturedTypeConstructor == null) {
LOG.error(renderDebugMessage("There is no captured type in bounds, but there is an error 'cannot capture type parameter'",
@@ -26,3 +26,6 @@ class TypeConstructorMismatch(constraintPosition: ConstraintPosition): Constrain
class ErrorInConstrainingType(constraintPosition: ConstraintPosition): ConstraintError(constraintPosition)
class CannotCapture(constraintPosition: ConstraintPosition, val typeVariable: TypeParameterDescriptor): ConstraintError(constraintPosition)
fun ConstraintError.substituteTypeVariable(substitution: (TypeParameterDescriptor) -> TypeParameterDescriptor) =
if (this is CannotCapture) CannotCapture(constraintPosition, substitution(typeVariable)) else this
@@ -51,7 +51,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
private val typeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
private val errors = ArrayList<ConstraintError>()
public val constraintErrors: List<ConstraintError>
get() = errors
private val constraintSystemStatus = object : ConstraintSystemStatus {
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
@@ -134,7 +137,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
public fun copy(): ConstraintSystem = createNewConstraintSystemFromThis({ it }, { it.copy() }, { true })
public fun substituteTypeVariables(typeVariablesMap: (TypeParameterDescriptor) -> TypeParameterDescriptor?): ConstraintSystem {
public fun substituteTypeVariables(typeVariablesMap: (TypeParameterDescriptor) -> TypeParameterDescriptor): ConstraintSystem {
// type bounds are proper types and don't contain other variables
return createNewConstraintSystemFromThis(typeVariablesMap, { it }, { true })
}
@@ -163,16 +166,16 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
private fun createNewConstraintSystemFromThis(
substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor?,
substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor,
replaceTypeBounds: (TypeBoundsImpl) -> TypeBoundsImpl,
filterConstraintPosition: (ConstraintPosition) -> Boolean
): ConstraintSystem {
val newSystem = ConstraintSystemImpl()
for ((typeParameter, typeBounds) in typeParameterBounds) {
val newTypeParameter = substituteTypeVariable(typeParameter)
newSystem.typeParameterBounds.put(newTypeParameter!!, replaceTypeBounds(typeBounds))
newSystem.typeParameterBounds.put(newTypeParameter, replaceTypeBounds(typeBounds))
}
newSystem.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
newSystem.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) }.map { it.substituteTypeVariable(substituteTypeVariable) })
return newSystem
}
@@ -188,11 +191,12 @@ public class ConstraintSystemImpl : ConstraintSystem {
private fun addConstraint(constraintKind: ConstraintKind, subType: JetType?, superType: JetType?, constraintPosition: ConstraintPosition) {
val typeCheckingProcedure = TypeCheckingProcedure(object : TypeCheckingProcedureCallbacks {
private var isTopLevel = true
private var depth = 0
override fun assertEqualTypes(a: JetType, b: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
isTopLevel = false
depth++
doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure)
depth--
return true
}
@@ -202,15 +206,16 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
override fun assertSubtype(subtype: JetType, supertype: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
isTopLevel = false
depth++
doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure)
depth--
return true
}
override fun capture(typeVariable: JetType, typeProjection: TypeProjection): Boolean {
val myTypeVariable = getMyTypeVariable(typeVariable)
if (myTypeVariable != null && constraintPosition.isCaptureAllowed()) {
if (!isTopLevel) {
if (depth > 0) {
errors.add(CannotCapture(constraintPosition, myTypeVariable))
}
generateTypeParameterCaptureConstraint(typeVariable, typeProjection, constraintPosition)
@@ -0,0 +1,10 @@
// !DIAGNOSTICS_NUMBER: 1
// !DIAGNOSTICS: TYPE_INFERENCE_CANNOT_CAPTURE_TYPES
class My<R, T>
fun <R, T> foo(my: My<Array<R>, T>): My<Array<R>, T> = my
fun test11(my: My<Array<out Int>, out Int>) {
foo(my)
}
@@ -0,0 +1,2 @@
<!-- typeInferenceCannotCaptureTypes1 -->
Type inference failed: 'R' cannot capture 'out Int'. Only top-level type projections can be captured
@@ -150,6 +150,12 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes
doTest(fileName);
}
@TestMetadata("typeInferenceCannotCaptureTypes.kt")
public void testTypeInferenceCannotCaptureTypes() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes.kt");
doTest(fileName);
}
@TestMetadata("typeInferenceExpectedTypeMismatch.kt")
public void testTypeInferenceExpectedTypeMismatch() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeInferenceExpectedTypeMismatch.kt");