Make $default methods non-private, avoid generating accessors for them

#KT-5786 Fixed
This commit is contained in:
Alexander Udalov
2015-04-23 16:42:51 +03:00
parent dc05596ce0
commit 07c2442405
10 changed files with 132 additions and 19 deletions
@@ -2165,21 +2165,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> 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<StackValue, StackValue> 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<ResolvedValueArgument> 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<StackValue, StackValue> 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<StackValue, StackValue> implem
}
}
FunctionDescriptor accessibleFunctionDescriptor = accessibleFunctionDescriptor(fd);
Callable callable = resolveToCallable(accessibleFunctionDescriptor, superCall, resolvedCall);
Callable callable = resolveToCallable(fd, superCall, resolvedCall);
return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
}
@@ -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);
@@ -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));
@@ -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"
@@ -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()
@@ -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
}
@@ -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
}
@@ -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
@@ -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")
@@ -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");