diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 07a9c48e927..b9bc0288fd0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -133,7 +133,7 @@ public class FunctionCodegen { new FunctionGenerationStrategy.FunctionDefault(state, function)); } - generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), functionDescriptor, owner.getContextKind(), + generateDefaultIfNeeded(owner.intoFunction(functionDescriptor, true), functionDescriptor, owner.getContextKind(), DefaultParameterValueLoader.DEFAULT, function); generateOverloadsWithDefaultValues(function, functionDescriptor, functionDescriptor); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index 7d0d7c3db5f..78580cb60cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -66,6 +66,8 @@ import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.*; import static org.jetbrains.kotlin.codegen.AsmUtil.*; +import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8Interface; +import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceMember; import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; import static org.jetbrains.kotlin.resolve.BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL; import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_ALIAS; @@ -375,7 +377,14 @@ public abstract class MemberCodegen context) { CodegenContext outermost = context.getClassOrPackageParentContext(); if (outermost instanceof ClassContext) { - return typeMapper.mapType(((ClassContext) outermost).getContextDescriptor()); + ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor(); + if (context instanceof MethodContext) { + FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor(); + if (isInterface(functionDescriptor.getContainingDeclaration()) && !isJvm8InterfaceMember(functionDescriptor, state)) { + return typeMapper.mapDefaultImpls(classDescriptor); + } + } + return typeMapper.mapType(classDescriptor); } else if (outermost instanceof MultifileClassFacadeContext || outermost instanceof DelegatingToPartContext) { Type implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(outermost); @@ -393,10 +402,17 @@ public abstract class MemberCodegen")) { - return method; + FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor(); + if ("".equals(functionDescriptor.getName().asString())) { + return null; } + + if (((MethodContext) context).isDefaultFunctionContext()) { + return typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind()); + } + + return typeMapper.mapAsmMethod(functionDescriptor, context.getContextKind()); + } return null; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java index d49ba2dd6fc..5e0de72dc19 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java @@ -299,9 +299,14 @@ public abstract class CodegenContext { return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen); } + @NotNull + public MethodContext intoFunction(FunctionDescriptor descriptor, boolean isDefaultFunctionContext) { + return new MethodContext(descriptor, getContextKind(), this, null, isDefaultFunctionContext); + } + @NotNull public MethodContext intoFunction(FunctionDescriptor descriptor) { - return new MethodContext(descriptor, getContextKind(), this, null); + return intoFunction(descriptor, false); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ConstructorContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ConstructorContext.java index 8d34ab09276..6980b4a404d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ConstructorContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ConstructorContext.java @@ -34,7 +34,7 @@ public class ConstructorContext extends MethodContext { @NotNull CodegenContext parent, @Nullable MutableClosure closure ) { - super(contextDescriptor, kind, parent, closure); + super(contextDescriptor, kind, parent, closure, false); } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/InlineLambdaContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/InlineLambdaContext.kt index 119a456d4a7..934c636795b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/InlineLambdaContext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/InlineLambdaContext.kt @@ -27,7 +27,7 @@ class InlineLambdaContext( closure: MutableClosure?, val isCrossInline: Boolean, val isPropertyReference: Boolean -) : MethodContext(functionDescriptor, contextKind, parentContext, closure) { +) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) { override fun getFirstCrossInlineOrNonInlineContext(): CodegenContext<*> { if (isCrossInline) return this diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/MethodContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/MethodContext.java index 2c2a152b7b5..4a5ffa4b17c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/MethodContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/MethodContext.java @@ -39,16 +39,19 @@ public class MethodContext extends CodegenContext { // Note: in case of code inside property accessors, functionDescriptor will be that accessor, // but CodegenContext#contextDescriptor will be the corresponding property private final FunctionDescriptor functionDescriptor; + private final boolean isDefaultFunctionContext; protected MethodContext( @NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind contextKind, @NotNull CodegenContext parentContext, - @Nullable MutableClosure closure + @Nullable MutableClosure closure, + boolean isDefaultFunctionContext ) { super(JvmCodegenUtil.getDirectMember(functionDescriptor), contextKind, parentContext, closure, parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null); this.functionDescriptor = functionDescriptor; + this.isDefaultFunctionContext = isDefaultFunctionContext; } @NotNull @@ -126,4 +129,8 @@ public class MethodContext extends CodegenContext { public FunctionDescriptor getFunctionDescriptor() { return functionDescriptor; } + + public boolean isDefaultFunctionContext() { + return isDefaultFunctionContext; + } } diff --git a/compiler/testData/codegen/box/reflection/enclosing/kt11969.kt b/compiler/testData/codegen/box/reflection/enclosing/kt11969.kt new file mode 100644 index 00000000000..420b28cedc5 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/enclosing/kt11969.kt @@ -0,0 +1,63 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JS + +interface Z { + private fun privateFun() = { "OK" } + + fun callPrivateFun() = privateFun() + + fun publicFun() = { "OK" } + + fun funWithDefaultArgs(s: () -> Unit = {}): () -> Unit + + val property: () -> Unit + get() = {} + + class Nested +} + +class Test : Z { + override fun funWithDefaultArgs(s: () -> Unit): () -> Unit { + return s + } + + fun funWithDefaultArgsInClass(s: () -> Unit = {}): () -> Unit { + return s + } +} + +fun box(): String { + + val privateFun = Test().callPrivateFun() + var enclosing = privateFun.javaClass.enclosingMethod!! + if (enclosing.name != "privateFun") return "fail 1: ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 2: ${enclosing.getDeclaringClass().simpleName}" + + val publicFun = Test().publicFun() + enclosing = publicFun.javaClass.enclosingMethod!! + if (enclosing.name != "publicFun") return "fail 3: ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 4: ${enclosing.getDeclaringClass().simpleName}" + + val property = Test().property + enclosing = property.javaClass.enclosingMethod!! + if (enclosing.name != "getProperty") return "fail 4: ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 5: ${enclosing.getDeclaringClass().simpleName}" + + val defaultArgs = Test().funWithDefaultArgs() + enclosing = defaultArgs.javaClass.enclosingMethod!! + if (enclosing.name != "funWithDefaultArgs\$default") return "fail 6: ${enclosing.name}" + if (enclosing.parameterTypes.size != 4) return "fail 7: not default method ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 8: ${enclosing.getDeclaringClass().simpleName}" + + val defaultArgsInClass = Test().funWithDefaultArgsInClass() + enclosing = defaultArgsInClass.javaClass.enclosingMethod!! + if (enclosing.name != "funWithDefaultArgsInClass\$default") return "fail 6: ${enclosing.name}" + if (enclosing.parameterTypes.size != 4) return "fail 7: not default method ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "Test") return "fail 8: ${enclosing.getDeclaringClass().simpleName}" + + val nested = Z.Nested::class.java + val enclosingClass = nested.enclosingClass!! + if (enclosingClass.name != "Z") return "fail 9: ${enclosingClass.name}" + + return "OK" +} diff --git a/compiler/testData/codegen/java8/box/jvm8/kt11969.kt b/compiler/testData/codegen/java8/box/jvm8/kt11969.kt new file mode 100644 index 00000000000..5a3810cb5e2 --- /dev/null +++ b/compiler/testData/codegen/java8/box/jvm8/kt11969.kt @@ -0,0 +1,54 @@ +// JVM_TARGET: 1.8 +// WITH_RUNTIME +// IGNORE_BACKEND: JS + +interface Z { + private fun privateFun() = { "OK" } + + fun callPrivateFun() = privateFun() + + fun publicFun() = { "OK" } + + fun funWithDefaultArgs(s: () -> Unit = {}): () -> Unit + + val property: () -> Unit + get() = {} + + class Nested +} + +class Test : Z { + override fun funWithDefaultArgs(s: () -> Unit): () -> Unit { + return s + } +} + +fun box(): String { + + val privateFun = Test().callPrivateFun() + var enclosing = privateFun.javaClass.enclosingMethod!! + if (enclosing.name != "privateFun") return "fail 1: ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 2: ${enclosing.getDeclaringClass().simpleName}" + + val publicFun = Test().publicFun() + enclosing = publicFun.javaClass.enclosingMethod!! + if (enclosing.name != "publicFun") return "fail 3: ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 4: ${enclosing.getDeclaringClass().simpleName}" + + val property = Test().property + enclosing = property.javaClass.enclosingMethod!! + if (enclosing.name != "getProperty") return "fail 4: ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 5: ${enclosing.getDeclaringClass().simpleName}" + + val defaultArgs = Test().funWithDefaultArgs() + enclosing = defaultArgs.javaClass.enclosingMethod!! + if (enclosing.name != "funWithDefaultArgs\$default") return "fail 6: ${enclosing.name}" + if (enclosing.parameterTypes.size != 4) return "fail 7: not default method ${enclosing.name}" + if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 8: ${enclosing.getDeclaringClass().simpleName}" + + val nested = Z.Nested::class.java + val enclosingClass = nested.enclosingClass!! + if (enclosingClass.name != "Z") return "fail 9: ${enclosingClass.name}" + + return "OK" +} diff --git a/compiler/testData/codegen/light-analysis/reflection/enclosing/kt11969.txt b/compiler/testData/codegen/light-analysis/reflection/enclosing/kt11969.txt new file mode 100644 index 00000000000..636fc49de8b --- /dev/null +++ b/compiler/testData/codegen/light-analysis/reflection/enclosing/kt11969.txt @@ -0,0 +1,36 @@ +public final class Kt11969Kt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +public final class Test { + public method (): void + public @org.jetbrains.annotations.NotNull method callPrivateFun(): kotlin.jvm.functions.Function0 + public @org.jetbrains.annotations.NotNull method funWithDefaultArgs(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): kotlin.jvm.functions.Function0 + public synthetic static method funWithDefaultArgsInClass$default(p0: Test, p1: kotlin.jvm.functions.Function0, p2: int, p3: java.lang.Object): kotlin.jvm.functions.Function0 + public final @org.jetbrains.annotations.NotNull method funWithDefaultArgsInClass(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): kotlin.jvm.functions.Function0 + public @org.jetbrains.annotations.NotNull method getProperty(): kotlin.jvm.functions.Function0 + public @org.jetbrains.annotations.NotNull method publicFun(): kotlin.jvm.functions.Function0 +} + +public interface Z { + inner class Z/DefaultImpls + inner class Z/Nested + public abstract @org.jetbrains.annotations.NotNull method callPrivateFun(): kotlin.jvm.functions.Function0 + public abstract @org.jetbrains.annotations.NotNull method funWithDefaultArgs(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): kotlin.jvm.functions.Function0 + public abstract @org.jetbrains.annotations.NotNull method getProperty(): kotlin.jvm.functions.Function0 + public abstract @org.jetbrains.annotations.NotNull method publicFun(): kotlin.jvm.functions.Function0 +} + +public final class Z/DefaultImpls { + inner class Z/DefaultImpls + public static @org.jetbrains.annotations.NotNull method callPrivateFun(p0: Z): kotlin.jvm.functions.Function0 + public synthetic static method funWithDefaultArgs$default(p0: Z, p1: kotlin.jvm.functions.Function0, p2: int, p3: java.lang.Object): kotlin.jvm.functions.Function0 + public static @org.jetbrains.annotations.NotNull method getProperty(p0: Z): kotlin.jvm.functions.Function0 + private static method privateFun(p0: Z): kotlin.jvm.functions.Function0 + public static @org.jetbrains.annotations.NotNull method publicFun(p0: Z): kotlin.jvm.functions.Function0 +} + +public final static class Z/Nested { + inner class Z/Nested + public method (): void +} 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 dd4f1c58615..fc60b1cafbf 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 @@ -13234,6 +13234,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("kt11969.kt") + public void testKt11969() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt"); + doTest(fileName); + } + @TestMetadata("kt6368.kt") public void testKt6368() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt"); diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java index 3b0bd2299c0..a5ef25cc9c6 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java @@ -203,6 +203,12 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg doTest(fileName); } + @TestMetadata("kt11969.kt") + public void testKt11969() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/kt11969.kt"); + doTest(fileName); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/kt14243.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 49eadb998e4..6ac4f80e843 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13234,6 +13234,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt11969.kt") + public void testKt11969() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt"); + doTest(fileName); + } + @TestMetadata("kt6368.kt") public void testKt6368() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java index 6d2f7e85b92..ca2388a1656 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java @@ -13234,6 +13234,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis doTest(fileName); } + @TestMetadata("kt11969.kt") + public void testKt11969() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt"); + doTest(fileName); + } + @TestMetadata("kt6368.kt") public void testKt6368() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 864fd825899..fdec455de65 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -16139,6 +16139,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } + @TestMetadata("kt11969.kt") + public void testKt11969() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + @TestMetadata("kt6368.kt") public void testKt6368() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt");