From f3092bf390033072242f681eefe44122d4f2eefa Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Thu, 29 Oct 2015 16:23:41 +0300 Subject: [PATCH] Fix for KT-9637: Runtime crash when using class literal in inline functions with reified type parameters #KT-9637 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 17 ++++++++++------- .../codegen/boxInline/reified/kt9637.1.kt | 15 +++++++++++++++ .../codegen/boxInline/reified/kt9637.2.kt | 16 ++++++++++++++++ .../codegen/boxInline/reified/kt9637_2.1.kt | 8 ++++++++ .../codegen/boxInline/reified/kt9637_2.2.kt | 10 ++++++++++ .../jetbrains/kotlin/codegen/InlineTestUtil.kt | 1 - .../BlackBoxInlineCodegenTestGenerated.java | 12 ++++++++++++ ...eKotlinAgainstInlineKotlinTestGenerated.java | 12 ++++++++++++ 8 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/reified/kt9637.1.kt create mode 100644 compiler/testData/codegen/boxInline/reified/kt9637.2.kt create mode 100644 compiler/testData/codegen/boxInline/reified/kt9637_2.1.kt create mode 100644 compiler/testData/codegen/boxInline/reified/kt9637_2.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 ebb2137513f..1b86c8b7176 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2793,7 +2793,7 @@ public class ExpressionCodegen extends KtVisitor impleme assert state.getReflectionTypes().getKClass().getTypeConstructor().equals(type.getConstructor()) : "::class expression should be type checked to a KClass: " + type; - return generateClassLiteralReference(typeMapper, CollectionsKt.single(type.getArguments()).getType()); + return generateClassLiteralReference(typeMapper, CollectionsKt.single(type.getArguments()).getType(), this); } @Override @@ -2839,7 +2839,12 @@ public class ExpressionCodegen extends KtVisitor impleme } @NotNull - public static StackValue generateClassLiteralReference(@NotNull final JetTypeMapper typeMapper, @NotNull final KotlinType type) { + public static StackValue generateClassLiteralReference(@NotNull JetTypeMapper typeMapper, @NotNull KotlinType type) { + return generateClassLiteralReference(typeMapper, type, null); + } + + @NotNull + private static StackValue generateClassLiteralReference(@NotNull final JetTypeMapper typeMapper, @NotNull final KotlinType type, @Nullable final ExpressionCodegen codegen) { return StackValue.operation(K_CLASS_TYPE, new Function1() { @Override public Unit invoke(InstructionAdapter v) { @@ -2849,11 +2854,9 @@ public class ExpressionCodegen extends KtVisitor impleme TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor; assert typeParameterDescriptor.isReified() : "Non-reified type parameter under ::class should be rejected by type checker: " + typeParameterDescriptor; - v.visitLdcInsn(typeParameterDescriptor.getName().asString()); - v.invokestatic( - IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.JAVA_CLASS_MARKER_METHOD_NAME, - Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false - ); + assert codegen != null : + "Reference to member of reified type should be rejected by type checker " + typeParameterDescriptor; + codegen.putReifierMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.JAVA_CLASS_MARKER_METHOD_NAME); } putJavaLangClassInstance(v, classAsmType); diff --git a/compiler/testData/codegen/boxInline/reified/kt9637.1.kt b/compiler/testData/codegen/boxInline/reified/kt9637.1.kt new file mode 100644 index 00000000000..f9f20035e7d --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/kt9637.1.kt @@ -0,0 +1,15 @@ +//NO_CHECK_LAMBDA_INLINING +import test.* + +class Boxer { + val box: () -> Box by injectFnc() +} + +fun box(): String { + val box = Box() + registerFnc { box } + val prop = Boxer().box + if (prop() != box) return "fail 1" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/reified/kt9637.2.kt b/compiler/testData/codegen/boxInline/reified/kt9637.2.kt new file mode 100644 index 00000000000..7d3863a3817 --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/kt9637.2.kt @@ -0,0 +1,16 @@ +package test + +import java.util.* +import kotlin.reflect.KClass + +val valuesInjectFnc = HashMap, Any>() + +inline fun injectFnc(): Lazy> = lazy(LazyThreadSafetyMode.NONE) { + (valuesInjectFnc[T::class] ?: throw Exception("no inject ${T::class.simpleName}")) as Function0 +} + +inline fun registerFnc(noinline value: Function0) { + valuesInjectFnc[T::class] = value +} + +public class Box \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/reified/kt9637_2.1.kt b/compiler/testData/codegen/boxInline/reified/kt9637_2.1.kt new file mode 100644 index 00000000000..f7a292de7cf --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/kt9637_2.1.kt @@ -0,0 +1,8 @@ +import test.* + +fun box(): String { + val boxClass = injectFnc() + if (boxClass != Box::class) return "fail 1" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/reified/kt9637_2.2.kt b/compiler/testData/codegen/boxInline/reified/kt9637_2.2.kt new file mode 100644 index 00000000000..75a34e201b5 --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/kt9637_2.2.kt @@ -0,0 +1,10 @@ +package test + +import kotlin.reflect.KClass + +inline fun injectFnc(): KClass = { + T::class +} () + +public class Box + diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt b/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt index e809c322aa3..9089eae1349 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt @@ -65,7 +65,6 @@ public object InlineTestUtil { val cr = ClassReader(bytes) val inlineFunctions = inlineFunctionsJvmNames(bytes) - if (inlineFunctions.isEmpty()) continue val classVisitor = object : ClassVisitorWithName() { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 57898732e30..9241e625aa3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -1108,6 +1108,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("kt9637.1.kt") + public void testKt9637() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt9637.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("kt9637_2.1.kt") + public void testKt9637_2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt9637_2.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("packages.1.kt") public void testPackages() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.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 b448e38bd3d..6a696f9a798 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1108,6 +1108,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("kt9637.1.kt") + public void testKt9637() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt9637.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("kt9637_2.1.kt") + public void testKt9637_2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt9637_2.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("packages.1.kt") public void testPackages() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");