From a3e949674f4e91d81015d997960a50b0dcdaa8f2 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 8 Dec 2014 14:05:42 +0300 Subject: [PATCH] Preserve nullability while substituting captured types --- .../nullableTypeVariable.kt | 11 +++++++++ .../capturedTypes/captureForNullableTypes.kt | 24 +++++++++++++++++++ .../capturedTypes/captureForNullableTypes.txt | 7 ++++++ .../checkers/JetDiagnosticsTestGenerated.java | 6 +++++ ...apturedTypeApproximationTestGenerated.java | 6 +++++ .../lang/types/CapturedTypeApproximation.kt | 11 ++++++--- 6 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/capturedTypeApproximation/nullableTypeVariable.kt create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.kt create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.txt diff --git a/compiler/testData/capturedTypeApproximation/nullableTypeVariable.kt b/compiler/testData/capturedTypeApproximation/nullableTypeVariable.kt new file mode 100644 index 00000000000..88e4d883c25 --- /dev/null +++ b/compiler/testData/capturedTypeApproximation/nullableTypeVariable.kt @@ -0,0 +1,11 @@ +class Inv + +fun foo(a: Inv) {} + +// T captures 'in Int' +// lower: Nothing +// upper: Inv + +// T captures 'out Int' +// lower: Nothing +// upper: Inv diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.kt new file mode 100644 index 00000000000..fa6156ae15a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.kt @@ -0,0 +1,24 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// !CHECK_TYPE + +fun bar(a: Array): Array = null!! + +fun test1(a: Array) { + val r: Array = bar(a) + val t = bar(a) + t checkType { it : _> } +} + +fun foo(l: Array): Array> = null!! + +fun test2(a: Array) { + val r: Array> = foo(a) + val t = foo(a) + t checkType { it : _>> } +} + +fun test3(a: Array) { + val r: Array> = foo(a) + val t = foo(a) + t checkType { it : _>> } +} diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.txt b/compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.txt new file mode 100644 index 00000000000..02493a2504f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.txt @@ -0,0 +1,7 @@ +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 +internal fun test3(/*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 689158dee78..de494b44769 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("captureForNullableTypes.kt") + public void testCaptureForNullableTypes() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureForNullableTypes.kt"); + doTest(fileName); + } + @TestMetadata("captureForPlatformTypes.kt") public void testCaptureForPlatformTypes() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureForPlatformTypes.kt"); diff --git a/compiler/tests/org/jetbrains/jet/resolve/typeApproximation/CapturedTypeApproximationTestGenerated.java b/compiler/tests/org/jetbrains/jet/resolve/typeApproximation/CapturedTypeApproximationTestGenerated.java index 3da38c221c3..eb2957a3c98 100644 --- a/compiler/tests/org/jetbrains/jet/resolve/typeApproximation/CapturedTypeApproximationTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/resolve/typeApproximation/CapturedTypeApproximationTestGenerated.java @@ -72,6 +72,12 @@ public class CapturedTypeApproximationTestGenerated extends AbstractCapturedType doTest(fileName); } + @TestMetadata("nullableTypeVariable.kt") + public void testNullableTypeVariable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/nullableTypeVariable.kt"); + doTest(fileName); + } + @TestMetadata("useSiteVarianceIn.kt") public void testUseSiteVarianceIn() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/capturedTypeApproximation/useSiteVarianceIn.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/CapturedTypeApproximation.kt b/core/descriptors/src/org/jetbrains/jet/lang/types/CapturedTypeApproximation.kt index 2c72ead8421..ff99a29c884 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/CapturedTypeApproximation.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/CapturedTypeApproximation.kt @@ -51,12 +51,14 @@ private val NULLABLE_ANY = KotlinBuiltIns.getInstance().getNullableAnyType() private val NOTHING = KotlinBuiltIns.getInstance().getNothingType() +private val NULLABLE_NOTHING = KotlinBuiltIns.getInstance().getNullableNothingType() + private fun TypeArgument.toTypeProjection(): TypeProjection { assert(isConsistent) { "Only consistent enhanced type propection can be converted to type projection" } fun removeProjectionIfRedundant(variance: Variance) = if (variance == typeParameter.getVariance()) Variance.INVARIANT else variance return when { inProjection == outProjection -> TypeProjectionImpl(inProjection) - inProjection == NOTHING -> TypeProjectionImpl(removeProjectionIfRedundant(Variance.OUT_VARIANCE), outProjection) + inProjection == NOTHING || inProjection == NULLABLE_NOTHING -> TypeProjectionImpl(removeProjectionIfRedundant(Variance.OUT_VARIANCE), outProjection) outProjection == NULLABLE_ANY -> TypeProjectionImpl(removeProjectionIfRedundant(Variance.IN_VARIANCE), inProjection) else -> throw AssertionError("Enhanced type projection can't be converted to type projection: $this") } @@ -99,10 +101,13 @@ public fun approximateCapturedTypes(type: JetType): ApproximationBounds val typeConstructor = type.getConstructor() if (type.isCaptured()) { val typeProjection = (typeConstructor as CapturedTypeConstructor).typeProjection + // todo: preserve flexibility as well + fun JetType.makeNullableIfNeeded() = TypeUtils.makeNullableIfNeeded(this, type.isMarkedNullable()) + val bound = typeProjection.getType().makeNullableIfNeeded() return when (typeProjection.getProjectionKind()) { - Variance.IN_VARIANCE -> ApproximationBounds(typeProjection.getType(), NULLABLE_ANY) - Variance.OUT_VARIANCE -> ApproximationBounds(NOTHING, typeProjection.getType()) + Variance.IN_VARIANCE -> ApproximationBounds(bound, NULLABLE_ANY) + Variance.OUT_VARIANCE -> ApproximationBounds(NOTHING.makeNullableIfNeeded(), bound) else -> throw AssertionError("Only nontrivial projections should have been captured, not: $typeProjection") } }