From 6cac6350a6c4f43f26d595c072ef54bfd5870949 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 21 Jan 2015 22:25:25 +0300 Subject: [PATCH] Fixed rendering of error message for 'cannot capture type' error Type variable should be chosen correctly --- .../diagnostics/rendering/Renderers.java | 18 +++++++++++----- .../calls/inference/ConstraintError.kt | 3 +++ .../calls/inference/ConstraintSystemImpl.kt | 21 ++++++++++++------- .../typeInferenceCannotCaptureTypes.kt | 10 +++++++++ .../typeInferenceCannotCaptureTypes1.txt | 2 ++ .../DiagnosticMessageTestGenerated.java | 6 ++++++ 6 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes.kt create mode 100644 idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes1.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.java index 48fc3c95fd3..1af15b9edf1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.java @@ -394,18 +394,26 @@ public class Renderers { @NotNull InferenceErrorData inferenceErrorData, @NotNull TabledDescriptorRenderer result ) { - ConstraintSystem constraintSystem = inferenceErrorData.constraintSystem; + ConstraintSystemImpl constraintSystem = (ConstraintSystemImpl) inferenceErrorData.constraintSystem; + List 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'", diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintError.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintError.kt index b9b325279ac..5818c150f54 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintError.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintError.kt @@ -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 \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index 3a475315055..959b205a78c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -51,7 +51,10 @@ public class ConstraintSystemImpl : ConstraintSystem { } private val typeParameterBounds = LinkedHashMap() + private val errors = ArrayList() + public val constraintErrors: List + 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) diff --git a/idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes.kt b/idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes.kt new file mode 100644 index 00000000000..acfd7aca9b9 --- /dev/null +++ b/idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS_NUMBER: 1 +// !DIAGNOSTICS: TYPE_INFERENCE_CANNOT_CAPTURE_TYPES + +class My + +fun foo(my: My, T>): My, T> = my + +fun test11(my: My, out Int>) { + foo(my) +} \ No newline at end of file diff --git a/idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes1.txt b/idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes1.txt new file mode 100644 index 00000000000..2080a7f5710 --- /dev/null +++ b/idea/testData/diagnosticMessage/typeInferenceCannotCaptureTypes1.txt @@ -0,0 +1,2 @@ + +Type inference failed: 'R' cannot capture 'out Int'. Only top-level type projections can be captured \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/DiagnosticMessageTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/highlighter/DiagnosticMessageTestGenerated.java index b4fa1ecff39..e6a059d6c87 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/DiagnosticMessageTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/DiagnosticMessageTestGenerated.java @@ -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");