From 1f6f607f40f7c7c92ce933d57e0873d7e35d5899 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Thu, 11 Dec 2014 18:49:16 +0300 Subject: [PATCH] Type variable with non-trivial upper bound cannot capture 'in' projection --- .../lang/diagnostics/rendering/Renderers.java | 13 ++++++++++++- .../capturedTypes/cannotCaptureInProjection.kt | 16 ++++++++++++++++ .../capturedTypes/cannotCaptureInProjection.txt | 6 ++++++ .../checkers/JetDiagnosticsTestGenerated.java | 6 ++++++ .../calls/inference/ConstraintSystemImpl.kt | 7 ++++++- .../jet/lang/types/lang/KotlinBuiltIns.java | 4 ++++ 6 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java index 2e497089b27..c4ad257f721 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java @@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.renderer.DescriptorRenderer; import org.jetbrains.jet.renderer.Renderer; @@ -412,10 +413,20 @@ public class Renderers { return result; } + String explanation; + JetType upperBound = typeParameterWithCapturedConstraint.getUpperBoundsAsType(); + if (!KotlinBuiltIns.isNullableAny(upperBound) + && capturedTypeConstructor.getTypeProjection().getProjectionKind() == Variance.IN_VARIANCE) { + explanation = "Type parameter has an upper bound '" + result.getTypeRenderer().render(upperBound) + "'" + + " that cannot be satisfied capturing 'in' projection"; + } + else { + explanation = "Only top level type projections can be captured"; + } result.text(newText().normal("'" + typeParameterWithCapturedConstraint.getName() + "'" + " cannot capture " + "'" + capturedTypeConstructor.getTypeProjection() + "'. " + - "Only top level type projections can be captured")); + explanation)); return result; } diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt new file mode 100644 index 00000000000..766b703d065 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// !CHECK_TYPE + +fun bar(a: Array): Array = null!! + +fun test1(a: Array) { + val r: Array = bar(a) + bar(a) +} + +fun foo(l: Array): Array> = null!! + +fun test2(a: Array) { + val r: Array> = foo(a) + foo(a) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.txt b/compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.txt new file mode 100644 index 00000000000..95bb306319f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.txt @@ -0,0 +1,6 @@ +package + +internal fun bar(/*0*/ a: kotlin.Array): kotlin.Array +internal fun foo(/*0*/ l: kotlin.Array): kotlin.Array> +internal fun test1(/*0*/ a: kotlin.Array): kotlin.Unit +internal fun test2(/*0*/ a: kotlin.Array): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 049ce363015..2f0e333fa5c 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -5094,6 +5094,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/capturedTypes"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("cannotCaptureInProjection.kt") + public void testCannotCaptureInProjection() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt"); + doTest(fileName); + } + @TestMetadata("captureForNullableTypes.kt") public void testCaptureForNullableTypes() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.kt b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.kt index a457e45963f..8d2558357a9 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.kt @@ -379,7 +379,12 @@ public class ConstraintSystemImpl : ConstraintSystem { constrainingTypeProjection: TypeProjection, constraintPosition: ConstraintPosition ) { - val typeBounds = getTypeBounds(parameterType) + val typeVariable = getMyTypeVariable(parameterType)!! + if (!KotlinBuiltIns.isNullableAny(typeVariable.getUpperBoundsAsType()) + && constrainingTypeProjection.getProjectionKind() == Variance.IN_VARIANCE) { + cannotCaptureTypesError = true + } + val typeBounds = getTypeBounds(typeVariable) val typeProjection = if (parameterType.isMarkedNullable()) { TypeProjectionImpl(constrainingTypeProjection.getProjectionKind(), TypeUtils.makeNotNullable(constrainingTypeProjection.getType())) } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java index 37e04bf5a35..2fc3090959a 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java @@ -878,6 +878,10 @@ public class KotlinBuiltIns { return isConstructedFromGivenClass(type, FQ_NAMES.any); } + public static boolean isNullableAny(@NotNull JetType type) { + return isAnyOrNullableAny(type) && type.isMarkedNullable(); + } + public static boolean isUnit(@NotNull JetType type) { return isNotNullConstructedFromGivenClass(type, FQ_NAMES.unit); }