From 607f32615f5f39d800c4882f9162752a56f8ec54 Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Wed, 13 Jan 2016 14:29:52 +0300 Subject: [PATCH] Type uncapturing --- .../kotlin/codegen/ExpressionCodegen.java | 3 ++- .../signature/inProjectionSubstitution.1.kt | 17 +++++++++++++++++ .../signature/inProjectionSubstitution.2.kt | 12 ++++++++++++ .../signature/outProjectionSubstitution.1.kt | 17 +++++++++++++++++ .../signature/outProjectionSubstitution.2.kt | 12 ++++++++++++ .../signature/starProjectionSubstitution.1.kt | 17 +++++++++++++++++ .../signature/starProjectionSubstitution.2.kt | 12 ++++++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 18 ++++++++++++++++++ ...KotlinAgainstInlineKotlinTestGenerated.java | 18 ++++++++++++++++++ .../org/jetbrains/kotlin/types/TypeUtils.java | 17 +++++++++++++++++ 10 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.1.kt create mode 100644 compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.2.kt create mode 100644 compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.1.kt create mode 100644 compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.2.kt create mode 100644 compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.1.kt create mode 100644 compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.2.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index c2273428b63..9a61b4ff393 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2459,7 +2459,8 @@ public class ExpressionCodegen extends KtVisitor impleme for (Map.Entry entry : typeArguments.entrySet()) { TypeParameterDescriptor key = entry.getKey(); - KotlinType type = entry.getValue(); + KotlinType type = TypeUtils.uncaptureTypeForInlineMapping(entry.getValue()); + TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type); if (parameterDescriptor == null) { // type is not generic diff --git a/compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.1.kt b/compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.1.kt new file mode 100644 index 00000000000..0f66c5ae2fd --- /dev/null +++ b/compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.1.kt @@ -0,0 +1,17 @@ +//NO_CHECK_LAMBDA_INLINING + +import test.* +import java.util.* + +public fun Array.slice1() = copyOfRange1 { 1 } + +fun box(): String { + val comparable = arrayOf("123").slice1() + val method = comparable.javaClass.getMethod("test", Any::class.java) + val genericParameterTypes = method.genericParameterTypes + if (genericParameterTypes.size != 1) return "fail 1: ${genericParameterTypes.size}" + var name = (genericParameterTypes[0] as Class<*>).name + if (name != "java.lang.Object") return "fail 2: ${name}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.2.kt b/compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.2.kt new file mode 100644 index 00000000000..326f2c37d8a --- /dev/null +++ b/compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.2.kt @@ -0,0 +1,12 @@ +package test + +interface F { + fun test(p: T) : Int +} + +inline fun Array.copyOfRange1(crossinline toIndex: () -> Int) = + object : F { + override fun test(p: T): Int { + return toIndex() + } + } diff --git a/compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.1.kt b/compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.1.kt new file mode 100644 index 00000000000..b3ce24539e2 --- /dev/null +++ b/compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.1.kt @@ -0,0 +1,17 @@ +//NO_CHECK_LAMBDA_INLINING + +import test.* +import java.util.* + +public fun Array.slice1() = copyOfRange1 { 1 } + +fun box(): String { + val comparable = arrayOf("123").slice1() + val method = comparable.javaClass.getMethod("test", Any::class.java) + val genericParameterTypes = method.genericParameterTypes + if (genericParameterTypes.size != 1) return "fail 1: ${genericParameterTypes.size}" + var name = (genericParameterTypes[0] as Class<*>).name + if (name != "java.lang.CharSequence") return "fail 2: ${name}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.2.kt b/compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.2.kt new file mode 100644 index 00000000000..c7e25ef8375 --- /dev/null +++ b/compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.2.kt @@ -0,0 +1,12 @@ +package test + +interface F { + fun test(p: T) : Int +} + +inline fun Array.copyOfRange1(crossinline toIndex: () -> Int) = + object : F { + override fun test(p: T): Int { + return toIndex() + } + } diff --git a/compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.1.kt b/compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.1.kt new file mode 100644 index 00000000000..4631b0e39bf --- /dev/null +++ b/compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.1.kt @@ -0,0 +1,17 @@ +//NO_CHECK_LAMBDA_INLINING + +import test.* +import java.util.* + +public fun Array<*>.slice1() = copyOfRange1 { 1 } + +fun box(): String { + val comparable = arrayOf("123").slice1() + val method = comparable.javaClass.getMethod("test", Any::class.java) + val genericParameterTypes = method.genericParameterTypes + if (genericParameterTypes.size != 1) return "fail 1: ${genericParameterTypes.size}" + var name = (genericParameterTypes[0] as Class<*>).name + if (name != "java.lang.Object") return "fail 2: ${name}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.2.kt b/compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.2.kt new file mode 100644 index 00000000000..c7e25ef8375 --- /dev/null +++ b/compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.2.kt @@ -0,0 +1,12 @@ +package test + +interface F { + fun test(p: T) : Int +} + +inline fun Array.copyOfRange1(crossinline toIndex: () -> Int) = + object : F { + override fun test(p: T): Int { + return toIndex() + } + } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 9cb2b38a74f..12f839c5ada 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -1429,6 +1429,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/signature"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("inProjectionSubstitution.1.kt") + public void testInProjectionSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("outProjectionSubstitution.1.kt") + public void testOutProjectionSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("recursion.1.kt") public void testRecursion() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/recursion.1.kt"); @@ -1447,6 +1459,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("starProjectionSubstitution.1.kt") + public void testStarProjectionSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("typeParameterInLambda.1.kt") public void testTypeParameterInLambda() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/typeParameterInLambda.1.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 276ec6c48ec..feee11a8559 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1429,6 +1429,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/signature"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("inProjectionSubstitution.1.kt") + public void testInProjectionSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/inProjectionSubstitution.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("outProjectionSubstitution.1.kt") + public void testOutProjectionSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/outProjectionSubstitution.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("recursion.1.kt") public void testRecursion() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/recursion.1.kt"); @@ -1447,6 +1459,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("starProjectionSubstitution.1.kt") + public void testStarProjectionSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/starProjectionSubstitution.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("typeParameterInLambda.1.kt") public void testTypeParameterInLambda() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/typeParameterInLambda.1.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java index 5cd2612c2f8..707531ff814 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java @@ -25,9 +25,12 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.resolve.calls.inference.CapturedType; +import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructor; import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor; import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; +import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import java.util.*; @@ -514,8 +517,22 @@ public class TypeUtils { return typeParameterDescriptor != null && typeParameterDescriptor.isReified(); } + @NotNull + public static KotlinType uncaptureTypeForInlineMapping(@NotNull KotlinType type) { + TypeConstructor constructor = type.getConstructor(); + if (constructor instanceof CapturedTypeConstructor) { + TypeProjection projection = ((CapturedTypeConstructor) constructor).getTypeProjection(); + if (Variance.IN_VARIANCE == projection.getProjectionKind()) { + //in variance could be captured only for or declarations + return TypeUtilsKt.getBuiltIns(type).getNullableAnyType(); + } + return uncaptureTypeForInlineMapping(projection.getType()); + } + return type; + } @Nullable public static TypeParameterDescriptor getTypeParameterDescriptorOrNull(@NotNull KotlinType type) { + assert !(type instanceof CapturedType) : "Type should be non-captured " + type; if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { return (TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor(); }