diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index a83caf4062e..e36efec26c0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2165,21 +2165,15 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitCallExpression(@NotNull JetCallExpression expression, StackValue receiver) { ResolvedCall resolvedCall = getResolvedCallWithAssert(expression, bindingContext); - CallableDescriptor funDescriptor = resolvedCall.getResultingDescriptor(); + FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall); - if (!(funDescriptor instanceof FunctionDescriptor)) { - throw new UnsupportedOperationException("unknown type of callee descriptor: " + funDescriptor); - } - - funDescriptor = accessibleFunctionDescriptor((FunctionDescriptor) funDescriptor); - - if (funDescriptor instanceof ConstructorDescriptor) { + if (descriptor instanceof ConstructorDescriptor) { return generateNewCall(expression, resolvedCall); } - if (funDescriptor.getOriginal() instanceof SamConstructorDescriptor) { + if (descriptor.getOriginal() instanceof SamConstructorDescriptor) { JetExpression argumentExpression = bindingContext.get(SAM_CONSTRUCTOR_TO_ARGUMENT, expression); - assert argumentExpression != null : "Argument expression is not saved for a SAM constructor: " + funDescriptor; + assert argumentExpression != null : "Argument expression is not saved for a SAM constructor: " + descriptor; return genSamInterfaceValue(argumentExpression, this); } @@ -2233,13 +2227,26 @@ public class ExpressionCodegen extends JetVisitor implem } @NotNull - private PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) { + private PropertyDescriptor accessiblePropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { return context.accessiblePropertyDescriptor(propertyDescriptor); } @NotNull - protected FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) { - return context.accessibleFunctionDescriptor(fd); + private FunctionDescriptor accessibleFunctionDescriptor(@NotNull ResolvedCall resolvedCall) { + FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); + // $default method is not private, so you need no accessor to call it + return usesDefaultArguments(resolvedCall) ? descriptor : context.accessibleFunctionDescriptor(descriptor); + } + + private static boolean usesDefaultArguments(@NotNull ResolvedCall resolvedCall) { + List valueArguments = resolvedCall.getValueArgumentsByIndex(); + if (valueArguments == null) return false; + + for (ResolvedValueArgument argument : valueArguments) { + if (argument instanceof DefaultValueArgument) return true; + } + + return false; } @NotNull @@ -2253,7 +2260,7 @@ public class ExpressionCodegen extends JetVisitor implem return invokeFunction(call, ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall(), receiver); } - FunctionDescriptor fd = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); + FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall); JetSuperExpression superCallExpression = getSuperCallExpression(call); boolean superCall = superCallExpression != null; @@ -2266,8 +2273,7 @@ public class ExpressionCodegen extends JetVisitor implem } } - FunctionDescriptor accessibleFunctionDescriptor = accessibleFunctionDescriptor(fd); - Callable callable = resolveToCallable(accessibleFunctionDescriptor, superCall, resolvedCall); + Callable callable = resolveToCallable(fd, superCall, resolvedCall); return callable.invokeMethodWithArguments(resolvedCall, receiver, this); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 56a79cea32e..f4441faad17 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -578,8 +578,12 @@ public class FunctionCodegen { int flags = getVisibilityAccessFlag(functionDescriptor) | getDeprecatedAccessFlag(functionDescriptor) | - ACC_SYNTHETIC | - (functionDescriptor instanceof ConstructorDescriptor ? 0 : ACC_STATIC); + ACC_SYNTHETIC; + if (!(functionDescriptor instanceof ConstructorDescriptor)) { + flags |= ACC_STATIC; + } + // $default methods are never private to be accessible from other class files (e.g. inner) without the need of synthetic accessors + flags &= ~ACC_PRIVATE; Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind, owner); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index f1a4d325713..a10beb0823b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1050,7 +1050,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) { ExpressionCodegen codegen = createOrGetClInitCodegen(); - FunctionDescriptor constructor = codegen.accessibleFunctionDescriptor(KotlinPackage.single(companionObject.getConstructors())); + FunctionDescriptor constructor = context.accessibleFunctionDescriptor(KotlinPackage.single(companionObject.getConstructors())); generateMethodCallTo(constructor, codegen.v); codegen.v.dup(); StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject)); diff --git a/compiler/testData/codegen/box/defaultArguments/private/memberExtensionFunction.kt b/compiler/testData/codegen/box/defaultArguments/private/memberExtensionFunction.kt new file mode 100644 index 00000000000..01167805ef4 --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/private/memberExtensionFunction.kt @@ -0,0 +1,9 @@ +class A { + private fun Int.foo(other: Int = 5): Int = this + other + + inner class B { + fun bar() = 37.foo() + } +} + +fun box() = if (A().B().bar() == 42) "OK" else "Fail" diff --git a/compiler/testData/codegen/box/defaultArguments/private/memberFunction.kt b/compiler/testData/codegen/box/defaultArguments/private/memberFunction.kt new file mode 100644 index 00000000000..64fe7c2de65 --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/private/memberFunction.kt @@ -0,0 +1,11 @@ +// KT-5786 NoSuchMethodError: no accessor for private fun with default arguments + +class A { + private fun foo(result: String = "OK"): String = result + + companion object { + fun bar() = A().foo() + } +} + +fun box() = A.bar() diff --git a/compiler/testData/codegen/box/defaultArguments/private/primaryConstructor.kt b/compiler/testData/codegen/box/defaultArguments/private/primaryConstructor.kt new file mode 100644 index 00000000000..51c45f4b8fd --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/private/primaryConstructor.kt @@ -0,0 +1,16 @@ +var state: String = "Fail" + +class A private(x: String = "OK") { + init { + state = x + } + + companion object { + fun foo() = A() + } +} + +fun box(): String { + A.foo() + return state +} diff --git a/compiler/testData/codegen/box/defaultArguments/private/secondaryConstructor.kt b/compiler/testData/codegen/box/defaultArguments/private/secondaryConstructor.kt new file mode 100644 index 00000000000..ea7569669e5 --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/private/secondaryConstructor.kt @@ -0,0 +1,16 @@ +var state: String = "Fail" + +class A { + private constructor(x: String = "OK") { + state = x + } + + companion object { + fun foo() = A() + } +} + +fun box(): String { + A.foo() + return state +} diff --git a/compiler/testData/codegen/boxWithStdlib/regressions/kt5786_privateWithDefault.kt b/compiler/testData/codegen/boxWithStdlib/regressions/kt5786_privateWithDefault.kt new file mode 100644 index 00000000000..c0984e29da3 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/regressions/kt5786_privateWithDefault.kt @@ -0,0 +1,12 @@ +fun box(): String { + run { + test("ok") + test("ok", 200) + } + test("ok") + test("ok", 300) + + return "OK" +} + +private fun test(arg1: String, default: Int = 0) = Unit diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 5854b4e16f0..973c395ec55 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -2391,6 +2391,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } } + + @TestMetadata("compiler/testData/codegen/box/defaultArguments/private") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Private extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInPrivate() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/defaultArguments/private"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("memberExtensionFunction.kt") + public void testMemberExtensionFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/private/memberExtensionFunction.kt"); + doTest(fileName); + } + + @TestMetadata("memberFunction.kt") + public void testMemberFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/private/memberFunction.kt"); + doTest(fileName); + } + + @TestMetadata("primaryConstructor.kt") + public void testPrimaryConstructor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/private/primaryConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructor.kt") + public void testSecondaryConstructor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/defaultArguments/private/secondaryConstructor.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/delegatedProperty") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index d391ea2affb..b021ee76072 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3250,6 +3250,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("kt5786_privateWithDefault.kt") + public void testKt5786_privateWithDefault() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/regressions/kt5786_privateWithDefault.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("kt5953.kt") public void testKt5953() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/regressions/kt5953.kt");