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:
@@ -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) {}
|
||||
|
||||
|
||||
+6
@@ -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");
|
||||
|
||||
@@ -25,7 +25,7 @@ public final class JvmAbi {
|
||||
* This constant is used to identify binary format (class file) versions
|
||||
* If you change class file metadata format and/or naming conventions, please increase this number
|
||||
*/
|
||||
public static final int VERSION = 20;
|
||||
public static final int VERSION = 21;
|
||||
|
||||
public static final String TRAIT_IMPL_CLASS_NAME = "$TImpl";
|
||||
public static final String TRAIT_IMPL_SUFFIX = "$" + TRAIT_IMPL_CLASS_NAME;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlin.jvm.internal;
|
||||
|
||||
final class DefaultConstructorMarker {
|
||||
private DefaultConstructorMarker() {}
|
||||
}
|
||||
Reference in New Issue
Block a user