Fixed rendering of error message for 'cannot capture type' error
Type variable should be chosen correctly
This commit is contained in:
@@ -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
|
||||
+13
-8
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user