Keep track of synthetic accessor parameter types

Accessor parameter types may be different from callee parameter types
in case of generic methods specialized by primitive types:

  open class Base<T> {
    protected fun foo(x: T) {}
  }

  // in different package
  class Derived : Base<Long> {
    inner class Inner {
      fun bar() { foo(42L) }
    }
  }

Synthetic accessor for 'Base.foo' in 'Derived' has signature '(J)V'
(not '(Ljava.lang.Object;)V' or '(Ljava.lang.Long;)V'),
and should box its parameter.

Note that in Java the corresponding synthetic accessor has signature
'(Ljava.lang.Long;)V' with auto-boxing at call site.

 #KT-20491 Fixed
This commit is contained in:
Dmitry Petrov
2017-09-28 10:32:28 +03:00
parent 73724bcdc7
commit 3994034f46
9 changed files with 168 additions and 8 deletions
@@ -813,27 +813,37 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
);
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor) && !isNonDefaultInterfaceMember(functionDescriptor, state);
int reg = hasDispatchReceiver ? 1 : 0;
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
int accessorParam = (hasDispatchReceiver && !accessorIsConstructor) ? 1 : 0;
int reg = hasDispatchReceiver ? 1 : 0;
if (!accessorIsConstructor && functionDescriptor instanceof ConstructorDescriptor) {
iv.anew(callableMethod.getOwner());
iv.dup();
reg = 0;
accessorParam = 0;
}
else if (accessorIsConstructor || (accessorDescriptor != null && KotlinTypeMapper.isAccessor(accessorDescriptor) && hasDispatchReceiver)) {
else if (KotlinTypeMapper.isAccessor(accessorDescriptor) && (hasDispatchReceiver || accessorIsConstructor)) {
if (!CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor)) {
iv.load(0, OBJECT_TYPE);
}
}
for (Type argType : callableMethod.getParameterTypes()) {
if (AsmTypes.DEFAULT_CONSTRUCTOR_MARKER.equals(argType)) {
Type[] calleeParameterTypes = callableMethod.getParameterTypes();
Type[] accessorParameterTypes = accessorDescriptor != null
? typeMapper.mapToCallableMethod(accessorDescriptor, false).getParameterTypes()
: calleeParameterTypes;
for (Type calleeArgType: calleeParameterTypes) {
if (AsmTypes.DEFAULT_CONSTRUCTOR_MARKER.equals(calleeArgType)) {
iv.aconst(null);
}
else {
iv.load(reg, argType);
reg += argType.getSize();
Type accessorParameterType = accessorParameterTypes[accessorParam];
iv.load(reg, accessorParameterType);
StackValue.coerce(accessorParameterType, calleeArgType, iv);
reg += accessorParameterType.getSize();
}
accessorParam++;
}
callableMethod.genInvokeInstruction(iv);
@@ -831,11 +831,11 @@ public class KotlinTypeMapper {
JvmCodegenUtil.isJvm8InterfaceWithDefaults(ownerForDefault, isJvm8Target, isJvm8TargetWithDefaults);
}
public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
public static boolean isAccessor(@Nullable CallableMemberDescriptor descriptor) {
return descriptor instanceof AccessorForCallableDescriptor<?>;
}
public static boolean isStaticAccessor(@NotNull CallableMemberDescriptor descriptor) {
public static boolean isStaticAccessor(@Nullable CallableMemberDescriptor descriptor) {
if (descriptor instanceof AccessorForConstructorDescriptor) return false;
return isAccessor(descriptor);
}
@@ -0,0 +1,20 @@
fun box(): String {
A.Nested().nestedA()
A.Nested().Inner().innerA()
A.companionA()
return "OK"
}
class A<T> private constructor(val x: T, val y: Int = 0) {
class Nested {
fun nestedA() = A<Long>(1L)
inner class Inner {
fun innerA() = A<Long>(1L)
}
}
companion object {
fun companionA() = A<Long>(1L)
}
}
@@ -0,0 +1,29 @@
// FILE: test.kt
import b.B
fun box() =
B().getOK()
// FILE: a.kt
package a
open class A<T> {
protected fun getO(x: T) = "O"
protected fun getK(x: T) = "K"
}
// FILE: b.kt
package b
import a.A
class B : A<Long>() {
inner class Inner {
fun innerGetO() = getO(0L)
}
fun lambdaGetK() = { -> getK(0L) }
fun getOK() =
Inner().innerGetO() + lambdaGetK().invoke()
}
@@ -0,0 +1,29 @@
// FILE: test.kt
import b.B
fun box() =
B().getOK()
// FILE: a.kt
package a
open class A<T> {
protected fun getO(x: T, z: String = "") = "O" + z
protected fun getK(x: T, z: String = "") = "K" + z
}
// FILE: b.kt
package b
import a.A
class B : A<Long>() {
inner class Inner {
fun innerGetO() = getO(0L)
}
fun lambdaGetK() = { -> getK(0L) }
fun getOK() =
Inner().innerGetO() + lambdaGetK().invoke()
}
@@ -18967,6 +18967,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SyntheticAccessors extends AbstractIrBlackBoxCodegenTest {
@TestMetadata("accessorForGenericConstructor.kt")
public void testAccessorForGenericConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericConstructor.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethod.kt")
public void testAccessorForGenericMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethod.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethodWithDefaults.kt")
public void testAccessorForGenericMethodWithDefaults() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethodWithDefaults.kt");
doTest(fileName);
}
@TestMetadata("accessorForProtected.kt")
public void testAccessorForProtected() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForProtected.kt");
@@ -18967,6 +18967,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SyntheticAccessors extends AbstractBlackBoxCodegenTest {
@TestMetadata("accessorForGenericConstructor.kt")
public void testAccessorForGenericConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericConstructor.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethod.kt")
public void testAccessorForGenericMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethod.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethodWithDefaults.kt")
public void testAccessorForGenericMethodWithDefaults() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethodWithDefaults.kt");
doTest(fileName);
}
@TestMetadata("accessorForProtected.kt")
public void testAccessorForProtected() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForProtected.kt");
@@ -18967,6 +18967,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SyntheticAccessors extends AbstractLightAnalysisModeTest {
@TestMetadata("accessorForGenericConstructor.kt")
public void testAccessorForGenericConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericConstructor.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethod.kt")
public void testAccessorForGenericMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethod.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethodWithDefaults.kt")
public void testAccessorForGenericMethodWithDefaults() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethodWithDefaults.kt");
doTest(fileName);
}
@TestMetadata("accessorForProtected.kt")
public void testAccessorForProtected() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForProtected.kt");
@@ -22849,6 +22849,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SyntheticAccessors extends AbstractJsCodegenBoxTest {
@TestMetadata("accessorForGenericConstructor.kt")
public void testAccessorForGenericConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericConstructor.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethod.kt")
public void testAccessorForGenericMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethod.kt");
doTest(fileName);
}
@TestMetadata("accessorForGenericMethodWithDefaults.kt")
public void testAccessorForGenericMethodWithDefaults() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForGenericMethodWithDefaults.kt");
doTest(fileName);
}
@TestMetadata("accessorForProtected.kt")
public void testAccessorForProtected() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/syntheticAccessors/accessorForProtected.kt");