Add synthetic argument to default constructors

It's need to add synthetic argument (of type that user can't use)
to constructors with default arguments to avoid clashing with
real user's constructor having the same set of parameters
and additional int's arguments.
This commit is contained in:
Denis Zharkov
2015-02-27 19:07:24 +03:00
parent 67f97fea42
commit 4022982760
8 changed files with 80 additions and 5 deletions
@@ -138,6 +138,7 @@ public class CallableMethod implements Callable {
Method method = getAsmMethod();
String desc = JetTypeMapper.getDefaultDescriptor(method, receiverParameterType != null);
if ("<init>".equals(method.getName())) {
v.aconst(null);
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "<init>", desc, false);
}
else {
@@ -585,6 +585,10 @@ public class FunctionCodegen {
for (int m : masks) {
v.iconst(m);
}
// constructors with default arguments has last synthetic argument of specific type
v.aconst(null);
String desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false);
v.invokespecial(methodOwner.getInternalName(), "<init>", desc, false);
v.areturn(Type.VOID_TYPE);
@@ -77,6 +77,7 @@ import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
public class JetTypeMapper {
private static final String DEFAULT_CONSTRUCTOR_MARKER_INTERNAL_CLASS_NAME = "kotlin/jvm/internal/DefaultConstructorMarker";
private final BindingContext bindingContext;
private final ClassBuilderMode classBuilderMode;
@@ -713,8 +714,15 @@ public class JetTypeMapper {
argumentsCount--;
}
int maskArgumentsCount = (argumentsCount + Integer.SIZE - 1) / Integer.SIZE;
String maskArguments = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount);
return descriptor.replace(")", maskArguments + ")");
String additionalArgs = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount);
if (isConstructor(method)) {
additionalArgs += Type.getObjectType(DEFAULT_CONSTRUCTOR_MARKER_INTERNAL_CLASS_NAME).getDescriptor();
}
return descriptor.replace(")", additionalArgs + ")");
}
private static boolean isConstructor(@NotNull Method method) {
return "<init>".equals(method.getName());
}
@NotNull
@@ -722,7 +730,7 @@ public class JetTypeMapper {
Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod();
Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context, getOutDirectory()));
String descriptor = getDefaultDescriptor(jvmSignature, functionDescriptor.getExtensionReceiverParameter() != null);
boolean isConstructor = "<init>".equals(jvmSignature.getName());
boolean isConstructor = isConstructor(jvmSignature);
if (!isStaticMethod(kind, functionDescriptor) && !isConstructor) {
descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
}
@@ -0,0 +1,35 @@
open class A(val x: String = "abc", val y: String = "efg") {
constructor(x: String, y: String, z: Int): this(x, y + "#" + z.toString()) {}
override fun toString() = "$x#$y"
}
class B : A {
constructor(x: String, y: String, z: Int): super(x, y + z.toString()) {}
constructor(x: String = "xyz", y: String = "123") : super(x, y) {}
constructor(x: Double): super(x.toString()) {}
}
fun box(): String {
val a1 = A().toString()
if (a1 != "abc#efg") return "fail1: $a1"
val a2 = A("hij", "klm", 1).toString()
if (a2 != "hij#klm#1") return "fail2: $a2"
val a3 = A(x="xyz").toString()
if (a3 != "xyz#efg") return "fail3: $a3"
val b1 = B().toString()
if (b1 != "xyz#123") return "fail4: $b1"
val b2 = B("hij", "klm", 2).toString()
if (b2 != "hij#klm2") return "fail5: $b2"
val b3 = B(123.0).toString()
if (b3 != "123.0#efg") return "fail6: $b3"
val b4 = B(x="test").toString()
if (b4 != "test#123") return "fail7: $b4"
return "OK"
}
@@ -8,7 +8,7 @@ class JavaClass {
catch (E1 e) {}
try {
new One(1, 0);
new One(1, 0, null);
}
catch (E1 e) {}
@@ -6303,6 +6303,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("clashingDefaultConstructors.kt")
public void testClashingDefaultConstructors() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/secondaryConstructors/clashingDefaultConstructors.kt");
doTest(fileName);
}
@TestMetadata("dataClasses.kt")
public void testDataClasses() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/secondaryConstructors/dataClasses.kt");