From 20ddbc96982a9395dafd254d7a1e1a6beb10ec35 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 19 Jul 2018 20:37:29 +0200 Subject: [PATCH] Do not generate generic signature for SAM wrapper methods #KT-23870 Fixed --- .../kotlin/codegen/FunctionCodegen.java | 25 ++++++---- .../codegen/FunctionGenerationStrategy.java | 4 ++ .../genericSignature/delegatedMembers.kt | 32 ++++++++++++ .../samWrappedLambdaVsReference.kt | 50 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 ++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 ++++ .../LightAnalysisModeTestGenerated.java | 10 ++++ 7 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/genericSignature/delegatedMembers.kt create mode 100644 compiler/testData/codegen/box/reflection/genericSignature/samWrappedLambdaVsReference.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 64b9a126de8..16f9ec4c54a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.config.JvmDefaultMode; import org.jetbrains.kotlin.config.JvmTarget; -import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotated; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; @@ -218,7 +217,7 @@ public class FunctionCodegen { flags, asmMethod.getName(), asmMethod.getDescriptor(), - jvmSignature.getGenericsSignature(), + strategy.skipGenericSignature() ? null : jvmSignature.getGenericsSignature(), getThrownExceptions(functionDescriptor, typeMapper) ), flags, asmMethod.getName(), @@ -1546,13 +1545,15 @@ public class FunctionCodegen { public void genSamDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { FunctionDescriptor delegatedTo = overriddenDescriptor.getOriginal(); - JvmDeclarationOrigin declarationOrigin = - JvmDeclarationOriginKt.SamDelegation(functionDescriptor); + JvmDeclarationOrigin declarationOrigin = JvmDeclarationOriginKt.SamDelegation(functionDescriptor); + // Skip writing generic signature for the SAM wrapper class method because it may reference type parameters from the SAM interface + // which would make little sense outside of that interface and may break Java reflection. + // E.g. functionDescriptor for a SAM wrapper for java.util.function.Predicate is the method `test` with signature "(T) -> Boolean" genDelegate( - functionDescriptor, delegatedTo, - declarationOrigin, + functionDescriptor, delegatedTo, declarationOrigin, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), - field); + field, true + ); } public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { @@ -1568,7 +1569,7 @@ public class FunctionCodegen { ) { JvmDeclarationOrigin declarationOrigin = JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction); - genDelegate(delegateFunction, delegatedTo, declarationOrigin, toClass, field); + genDelegate(delegateFunction, delegatedTo, declarationOrigin, toClass, field, false); } private void genDelegate( @@ -1576,7 +1577,8 @@ public class FunctionCodegen { FunctionDescriptor delegatedTo, @NotNull JvmDeclarationOrigin declarationOrigin, ClassDescriptor toClass, - StackValue field + StackValue field, + boolean skipGenericSignature ) { generateMethod( declarationOrigin, delegateFunction, @@ -1631,6 +1633,11 @@ public class FunctionCodegen { public boolean skipNotNullAssertionsForParameters() { return false; } + + @Override + public boolean skipGenericSignature() { + return skipGenericSignature; + } } ); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java index b3032d50a27..a1232d2949c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionGenerationStrategy.java @@ -28,6 +28,10 @@ public abstract class FunctionGenerationStrategy { public abstract boolean skipNotNullAssertionsForParameters(); + public boolean skipGenericSignature() { + return false; + } + public MethodVisitor wrapMethodVisitor(@NotNull MethodVisitor mv, int access, @NotNull String name, @NotNull String desc) { return mv; } diff --git a/compiler/testData/codegen/box/reflection/genericSignature/delegatedMembers.kt b/compiler/testData/codegen/box/reflection/genericSignature/delegatedMembers.kt new file mode 100644 index 00000000000..d07dedaacfe --- /dev/null +++ b/compiler/testData/codegen/box/reflection/genericSignature/delegatedMembers.kt @@ -0,0 +1,32 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FILE: J.java + +import java.util.*; + +public interface J { + T foo(List p0, Map> p1); +} + +// FILE: K.kt + +import kotlin.test.assertEquals + +object O : J { + override fun foo(p0: List, p1: Map>): Long = 42L +} + +class A : J by O + +fun box(): String { + val m = A::class.java.getDeclaredMethod("foo", List::class.java, Map::class.java) + assertEquals( + "[interface java.util.List, interface java.util.Map]", + m.parameterTypes.contentToString() + ) + assertEquals( + "[java.util.List, java.util.Map>]", + m.genericParameterTypes.contentToString() + ) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/genericSignature/samWrappedLambdaVsReference.kt b/compiler/testData/codegen/box/reflection/genericSignature/samWrappedLambdaVsReference.kt new file mode 100644 index 00000000000..41f5b26f737 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/genericSignature/samWrappedLambdaVsReference.kt @@ -0,0 +1,50 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FULL_JDK + +// FILE: Java.java + +import java.lang.reflect.Method; +import java.util.function.Predicate; +import java.util.*; + +public final class Java { + public static Method getTest(Predicate predicate) throws NoSuchMethodException { + return predicate.getClass().getMethod("test", Object.class); + } + + public static Method getFoo(ComplexPredicate predicate) throws NoSuchMethodException { + return predicate.getClass().getMethod("foo", Number.class, List.class, Map.class); + } +} + +// FILE: ComplexPredicate.java + +import java.util.*; + +public interface ComplexPredicate { + boolean foo(T p0, List p1, Map> p2); +} + +// FILE: K.kt + +import java.lang.reflect.Method +import java.util.* +import kotlin.test.assertEquals + +fun check(title: String, expected: String, method: Method) { + assertEquals(expected, method.parameterTypes.contentToString(), "Fail parameterTypes of $title") + assertEquals(expected, method.genericParameterTypes.contentToString(), "Fail genericParameterTypes of $title") +} + +private fun bar(p0: Long, p1: List, p2: Map>) = true + +fun box(): String { + check("SAM-implementing lambda 1", "[class java.lang.Object]", Java.getTest { Objects.nonNull(it) }) + check("SAM-wrapped function reference 1", "[class java.lang.Object]", Java.getTest(Objects::nonNull)) + + check("SAM-implementing lambda 2", "[class java.lang.Number, interface java.util.List, interface java.util.Map]", Java.getFoo { p0, p1, p2 -> bar(p0, p1, p2) }) + check("SAM-wrapped function reference 2", "[class java.lang.Number, interface java.util.List, interface java.util.Map]", Java.getFoo(::bar)) + + return "OK" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 0d2bcbc8d59..d457b424aad 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -17601,6 +17601,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/genericSignature/defaultImplsGenericSignature.kt"); } + @TestMetadata("delegatedMembers.kt") + public void testDelegatedMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/genericSignature/delegatedMembers.kt"); + } + @TestMetadata("functionLiteralGenericSignature.kt") public void testFunctionLiteralGenericSignature() throws Exception { runTest("compiler/testData/codegen/box/reflection/genericSignature/functionLiteralGenericSignature.kt"); @@ -17631,6 +17636,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/genericSignature/kt6106.kt"); } + @TestMetadata("samWrappedLambdaVsReference.kt") + public void testSamWrappedLambdaVsReference() throws Exception { + runTest("compiler/testData/codegen/box/reflection/genericSignature/samWrappedLambdaVsReference.kt"); + } + @TestMetadata("signatureOfDeepGenericInner.kt") public void testSignatureOfDeepGenericInner() throws Exception { runTest("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 09291251cdb..fc53f72bbb7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -17601,6 +17601,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/genericSignature/defaultImplsGenericSignature.kt"); } + @TestMetadata("delegatedMembers.kt") + public void testDelegatedMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/genericSignature/delegatedMembers.kt"); + } + @TestMetadata("functionLiteralGenericSignature.kt") public void testFunctionLiteralGenericSignature() throws Exception { runTest("compiler/testData/codegen/box/reflection/genericSignature/functionLiteralGenericSignature.kt"); @@ -17631,6 +17636,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/genericSignature/kt6106.kt"); } + @TestMetadata("samWrappedLambdaVsReference.kt") + public void testSamWrappedLambdaVsReference() throws Exception { + runTest("compiler/testData/codegen/box/reflection/genericSignature/samWrappedLambdaVsReference.kt"); + } + @TestMetadata("signatureOfDeepGenericInner.kt") public void testSignatureOfDeepGenericInner() throws Exception { runTest("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 24b20890b1a..ef281933de2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -17601,6 +17601,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/genericSignature/defaultImplsGenericSignature.kt"); } + @TestMetadata("delegatedMembers.kt") + public void testDelegatedMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/genericSignature/delegatedMembers.kt"); + } + @TestMetadata("functionLiteralGenericSignature.kt") public void testFunctionLiteralGenericSignature() throws Exception { runTest("compiler/testData/codegen/box/reflection/genericSignature/functionLiteralGenericSignature.kt"); @@ -17631,6 +17636,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/genericSignature/kt6106.kt"); } + @TestMetadata("samWrappedLambdaVsReference.kt") + public void testSamWrappedLambdaVsReference() throws Exception { + runTest("compiler/testData/codegen/box/reflection/genericSignature/samWrappedLambdaVsReference.kt"); + } + @TestMetadata("signatureOfDeepGenericInner.kt") public void testSignatureOfDeepGenericInner() throws Exception { runTest("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt");