diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 1a336b368ac..cfb44e11331 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -52,6 +52,7 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue; import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.constants.KClassValue; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; @@ -155,6 +156,11 @@ public class FunctionCodegen { Method asmMethod = jvmSignature.getAsmMethod(); int flags = getMethodAsmFlags(functionDescriptor, contextKind); + + if (origin.getOriginKind() == JvmDeclarationOriginKind.SAM_DELEGATION) { + flags |= ACC_SYNTHETIC; + } + boolean isNative = NativeKt.hasNativeAnnotation(functionDescriptor); if (isNative && owner instanceof MultifileClassFacadeContext) { @@ -923,19 +929,42 @@ public class FunctionCodegen { iv.visitLabel(afterBarrier); } + public void genSamDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { + FunctionDescriptor delegatedTo = overriddenDescriptor.getOriginal(); + JvmDeclarationOrigin declarationOrigin = + JvmDeclarationOriginKt.SamDelegation(functionDescriptor); + genDelegate( + functionDescriptor, delegatedTo, + declarationOrigin, + (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), + field); + } + public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(), (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field); } public void genDelegate( + @NotNull FunctionDescriptor delegateFunction, + FunctionDescriptor delegatedTo, + ClassDescriptor toClass, + StackValue field + ) { + JvmDeclarationOrigin declarationOrigin = + JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction); + genDelegate(delegateFunction, delegatedTo, declarationOrigin, toClass, field); + } + + private void genDelegate( @NotNull final FunctionDescriptor delegateFunction, final FunctionDescriptor delegatedTo, + @NotNull JvmDeclarationOrigin declarationOrigin, final ClassDescriptor toClass, final StackValue field ) { generateMethod( - JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction), delegateFunction, + declarationOrigin, delegateFunction, new FunctionGenerationStrategy() { @Override public void generateBody( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperCodegen.java index aee4b1a82d3..de8566334f0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamWrapperCodegen.java @@ -152,7 +152,7 @@ public class SamWrapperCodegen { FunctionDescriptor invokeFunction = functionJetType.getMemberScope().getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).iterator().next().getOriginal(); StackValue functionField = StackValue.field(functionType, ownerType, FUNCTION_FIELD_NAME, false, StackValue.none()); - codegen.genDelegate(erasedInterfaceFunction, invokeFunction, functionField); + codegen.genSamDelegate(erasedInterfaceFunction, invokeFunction, functionField); // generate sam bridges // TODO: erasedInterfaceFunction is actually not an interface function, but function in generated class diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt index bdbde630c63..b57c02fdb52 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmDeclarationOrigin.kt @@ -34,6 +34,7 @@ enum class JvmDeclarationOriginKind { INTERFACE_DEFAULT_IMPL, DELEGATION_TO_DEFAULT_IMPLS, DELEGATION, + SAM_DELEGATION, BRIDGE, MULTIFILE_CLASS, MULTIFILE_CLASS_PART, @@ -78,4 +79,6 @@ fun DelegationToTraitImpl(element: PsiElement?, descriptor: FunctionDescriptor): fun Delegation(element: PsiElement?, descriptor: FunctionDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(DELEGATION, element, descriptor) +fun SamDelegation(descriptor: FunctionDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(SAM_DELEGATION, null, descriptor) + fun Synthetic(element: PsiElement?, descriptor: CallableMemberDescriptor): JvmDeclarationOrigin = JvmDeclarationOrigin(SYNTHETIC, element, descriptor) \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/outs/samAdapter.out b/idea/testData/debugger/tinyApp/outs/samAdapter.out new file mode 100644 index 00000000000..5bb422802f0 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/samAdapter.out @@ -0,0 +1,15 @@ +LineBreakpoint created at samAdapter.kt:5 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! samAdapter.SamAdapterKt +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +samAdapter.kt:5 +samAdapter.kt:6 +samAdapter.kt:10 +MyJavaClass.java:20 +samAdapter.kt:6 +MyJavaClass.java:20 +samAdapter.kt:10 +samAdapter.kt:6 +samAdapter.kt:7 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/forTests/Computable.java b/idea/testData/debugger/tinyApp/src/forTests/Computable.java new file mode 100644 index 00000000000..c053d0ef357 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/forTests/Computable.java @@ -0,0 +1,5 @@ +package forTests; + +public interface Computable { + T compute(); +} \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/forTests/MyJavaClass.java b/idea/testData/debugger/tinyApp/src/forTests/MyJavaClass.java index 7d95c88844e..62e29a9e79d 100644 --- a/idea/testData/debugger/tinyApp/src/forTests/MyJavaClass.java +++ b/idea/testData/debugger/tinyApp/src/forTests/MyJavaClass.java @@ -15,4 +15,8 @@ public class MyJavaClass { public static int staticFun(Object s) { return 1; } + + public static T runReadAction(@NotNull Computable computation) { + return computation.compute(); + } } diff --git a/idea/testData/debugger/tinyApp/src/stepping/stepInto/samAdapter.kt b/idea/testData/debugger/tinyApp/src/stepping/stepInto/samAdapter.kt new file mode 100644 index 00000000000..0abe13a71f5 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/stepping/stepInto/samAdapter.kt @@ -0,0 +1,13 @@ +package samAdapter + +fun main(args: Array) { + //Breakpoint! + val a = 1 + runReadAction { 1 } +} + +fun runReadAction(action: () -> Int): Int { + return forTests.MyJavaClass.runReadAction(action) +} + +// STEP_INTO: 8 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java index 34ea5f13329..ffa3daa998d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/KotlinSteppingTestGenerated.java @@ -241,6 +241,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest { doStepIntoTest(fileName); } + @TestMetadata("samAdapter.kt") + public void testSamAdapter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepInto/samAdapter.kt"); + doStepIntoTest(fileName); + } + @TestMetadata("skipSimpleGetter.kt") public void testSkipSimpleGetter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepInto/skipSimpleGetter.kt");