Fix VerifyError for enum constructor with default arguments

This commit is contained in:
Natalia.Ukhorskaya
2012-12-26 19:46:55 +04:00
parent beec5a843e
commit e9d1171d6d
21 changed files with 381 additions and 38 deletions
@@ -536,7 +536,7 @@ public class FunctionCodegen extends GenerationStateAware {
@NotNull ClassBuilder classBuilder
) {
if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
return;
return;
}
int flags = getVisibilityAccessFlag(constructorDescriptor);
MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null, null);
@@ -651,6 +651,9 @@ public class FunctionCodegen extends GenerationStateAware {
) {
mv.visitCode();
boolean isEnumConstructor = functionDescriptor instanceof ConstructorDescriptor &&
DescriptorUtils.isEnumClass(functionDescriptor.getContainingDeclaration());
FrameMap frameMap = owner.prepareFrame(state.getTypeMapper());
if (kind instanceof OwnerKind.StaticDelegateKind) {
@@ -661,58 +664,40 @@ public class FunctionCodegen extends GenerationStateAware {
frameMap.enterTemp(OBJECT_TYPE);
}
if (isEnumConstructor) {
frameMap.enterTemp(OBJECT_TYPE);
frameMap.enterTemp(Type.INT_TYPE);
}
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state);
int var = 0;
if (!aStatic) {
var++;
}
if (hasOuter) {
var++;
}
Type receiverType;
Type receiverType = null;
if (hasReceiver) {
receiverType = state.getTypeMapper().mapType(receiverParameter.getType());
var += receiverType.getSize();
}
else {
receiverType = Type.DOUBLE_TYPE;
}
final int extraInLocalVariablesTable = getSizeOfExplicitArgumentsInLocalVariablesTable(aStatic, hasOuter, isEnumConstructor, receiverType);
final int countOfExtraVarsInMethodArgs = getCountOfExplicitArgumentsInMethodArguments(hasOuter, hasReceiver, isEnumConstructor);
Type[] argTypes = jvmSignature.getArgumentTypes();
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
int paramSizeInLocalVariablesTable = 0;
for (int i = 0; i < paramDescrs.size(); i++) {
Type argType = argTypes[i + ((hasReceiver || hasOuter) ? 1 : 0)];
Type argType = argTypes[i + countOfExtraVarsInMethodArgs];
int size = argType.getSize();
frameMap.enter(paramDescrs.get(i), argType);
var += size;
paramSizeInLocalVariablesTable += size;
}
int maskIndex = var;
final int maskIndex = extraInLocalVariablesTable + paramSizeInLocalVariablesTable;
var = 0;
if (!aStatic) {
mv.visitVarInsn(ALOAD, var++);
}
if (hasOuter) {
iv.load(var, ownerInternalName.getAsmType());
var++;
}
if (hasReceiver) {
iv.load(var, receiverType);
var += receiverType.getSize();
}
int extra = (hasReceiver || hasOuter) ? 1 : 0;
loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, receiverType, ownerInternalName.getAsmType(), aStatic, hasOuter, isEnumConstructor);
int indexInLocalVariablesTable = extraInLocalVariablesTable;
for (int index = 0; index < paramDescrs.size(); index++) {
ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
Type t = argTypes[extra + index];
Type t = argTypes[countOfExtraVarsInMethodArgs + index];
if (frameMap.getIndex(parameterDescriptor) < 0) {
frameMap.enter(parameterDescriptor, t);
@@ -733,8 +718,8 @@ public class FunctionCodegen extends GenerationStateAware {
iv.mark(loadArg);
}
iv.load(var, t);
var += t.getSize();
iv.load(indexInLocalVariablesTable, t);
indexInLocalVariablesTable += t.getSize();
}
final String internalName = ownerInternalName.getInternalName();
@@ -763,6 +748,54 @@ public class FunctionCodegen extends GenerationStateAware {
mv.visitEnd();
}
private static int getSizeOfExplicitArgumentsInLocalVariablesTable(
boolean isStatic,
boolean hasOuter,
boolean isEnumConstructor,
@Nullable Type receiverType
) {
int result = 0;
if (!isStatic) result++;
if (receiverType != null) result += receiverType.getSize();
if (hasOuter) result++;
if (isEnumConstructor) result += 2;
return result;
}
private static int getCountOfExplicitArgumentsInMethodArguments(
boolean hasOuter,
boolean hasReceiver,
boolean isEnumConstructor
) {
int result = 0;
if (hasReceiver) result++;
if (hasOuter) result++;
if (isEnumConstructor) result += 2;
return result;
}
private static void loadExplicitArgumentsOnStack(@NotNull InstructionAdapter iv,
@NotNull Type ownerType, @Nullable Type receiverType, @NotNull Type outerType,
boolean isStatic, boolean hasOuter, boolean isEnumConstructor) {
int var = 0;
if (!isStatic) {
iv.load(var++, ownerType);
}
if (hasOuter) {
iv.load(var++, outerType);
}
if (isEnumConstructor) {
iv.load(var++, OBJECT_TYPE);
iv.load(var++, Type.INT_TYPE);
}
if (receiverType != null) {
iv.load(var, receiverType);
}
}
private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
boolean needed = false;
if (functionDescriptor != null) {
@@ -258,6 +258,11 @@ public class DescriptorUtils {
&& ((ClassDescriptor) descriptor).getKind() == ClassKind.ENUM_ENTRY;
}
public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) {
return descriptor instanceof ClassDescriptor
&& ((ClassDescriptor) descriptor).getKind() == ClassKind.ENUM_CLASS;
}
@NotNull
public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
@@ -0,0 +1,11 @@
annotation class A(val a: Int = 0)
A fun test1() = 1
A(2) fun test2() = 1
fun box(): String {
if ((test1() + test2()) == 2) {
return "OK"
}
return "fail"
}
@@ -0,0 +1,14 @@
class A {
class B(val a: Double = 1.0, val b: Int = 55, val c: String = "c")
}
fun box(): String {
val bDefault = A().B()
val b = A().B(2.0, 66, "cc")
if (bDefault.a == 1.0 && bDefault.b == 55 && bDefault.c == "c") {
if (b.a == 2.0 && b.b == 66 && b.c == "cc") {
return "OK"
}
}
return "fail"
}
@@ -0,0 +1,11 @@
enum class A(val a: Int = 1) {
FIRST: A()
SECOND: A(2)
}
fun box(): String {
if (A.FIRST.a == 1 && A.SECOND.a == 2) {
return "OK"
}
return "fail"
}
@@ -0,0 +1,10 @@
enum class Foo(val a: Int = 1, val b: String) {
B: Foo(2, "b")
C: Foo(b = "b")
}
fun box(): String {
if (Foo.B.a != 2 || Foo.B.b != "b") return "fail"
if (Foo.C.a != 1 || Foo.C.b != "b") return "fail"
return "OK"
}
@@ -0,0 +1,14 @@
enum class Foo(val a: Int = 1, val b: String = "a") {
A: Foo()
B: Foo(2, "b")
C: Foo(b = "b")
D: Foo(a = 2)
}
fun box(): String {
if (Foo.A.a != 1 || Foo.A.b != "a") return "fail"
if (Foo.B.a != 2 || Foo.B.b != "b") return "fail"
if (Foo.C.a != 1 || Foo.C.b != "b") return "fail"
if (Foo.D.a != 2 || Foo.D.b != "a") return "fail"
return "OK"
}
@@ -0,0 +1,14 @@
enum class Foo(val a: Double = 1.0, val b: Double = 1.0) {
A: Foo()
B: Foo(2.0, 2.0)
C: Foo(b = 2.0)
D: Foo(a = 2.0)
}
fun box(): String {
if (Foo.A.a != 1.0 || Foo.A.b != 1.0) return "fail"
if (Foo.B.a != 2.0 || Foo.B.b != 2.0) return "fail"
if (Foo.C.a != 1.0 || Foo.C.b != 2.0) return "fail"
if (Foo.D.a != 2.0 || Foo.D.b != 1.0) return "fail"
return "OK"
}
@@ -0,0 +1,9 @@
fun Int.foo(a: Int = 1): Int {
return a
}
fun box(): String {
if (1.foo() != 1) return "fail"
if (1.foo(2) != 2) return "fail"
return "OK"
}
@@ -0,0 +1,9 @@
fun Double.foo(a: Double = 1.0): Double {
return a
}
fun box(): String {
if (1.0.foo() != 1.0) return "fail"
if (1.0.foo(2.0) != 2.0) return "fail"
return "OK"
}
@@ -0,0 +1,11 @@
fun Double.foo(a: Double = 1.0, b: Double = 1.0): Double {
return a + b
}
fun box(): String {
if (1.0.foo() != 2.0) return "fail"
if (1.0.foo(2.0, 2.0) != 4.0) return "fail"
if (1.0.foo(a = 2.0) != 3.0) return "fail"
if (1.0.foo(b = 2.0) != 3.0) return "fail"
return "OK"
}
@@ -0,0 +1,17 @@
class A {
class object {
fun Int.foo(a: Int = 1): Int {
return a
}
fun test(): String {
if (1.foo() != 1) return "fail"
if (1.foo(2) != 2) return "fail"
return "OK"
}
}
}
fun box(): String {
return A.test()
}
@@ -0,0 +1,15 @@
object A {
fun Int.foo(a: Int = 1): Int {
return a
}
fun test(): String {
if (1.foo() != 1) return "fail"
if (1.foo(2) != 2) return "fail"
return "OK"
}
}
fun box(): String {
return A.test()
}
@@ -0,0 +1,9 @@
fun Int.foo(a: Int = 1, b: String): Int {
return a
}
fun box(): String {
if (1.foo(b = "b") != 1) return "fail"
if (1.foo(2, "b") != 2) return "fail"
return "OK"
}
@@ -0,0 +1,14 @@
trait Foo {
fun foo(a: Double = 1.0): Double
}
class FooImpl : Foo {
override fun foo(a: Double): Double {
return a
}
}
fun box(): String {
if (FooImpl().foo() != 1.0) return "fail"
if (FooImpl().foo(2.0) != 2.0) return "fail"
return "OK"
}
@@ -0,0 +1,15 @@
class A {
fun Int.foo(a: Int = 1): Int {
return a
}
fun test(): String {
if (1.foo() != 1) return "fail"
if (1.foo(2) != 2) return "fail"
return "OK"
}
}
fun box(): String {
return A().test()
}
@@ -0,0 +1,15 @@
class A {
fun Double.foo(a: Double = 1.0): Double {
return a
}
fun test(): String {
if (1.0.foo() != 1.0) return "fail"
if (1.0.foo(2.0) != 2.0) return "fail"
return "OK"
}
}
fun box(): String {
return A().test()
}
@@ -0,0 +1,17 @@
class A {
fun Double.foo(a: Double = 1.0, b: Double = 1.0): Double {
return a + b
}
fun test(): String {
if (1.0.foo() != 2.0) return "fail"
if (1.0.foo(2.0, 2.0) != 4.0) return "fail"
if (1.0.foo(a = 2.0) != 3.0) return "fail"
if (1.0.foo(b = 2.0) != 3.0) return "fail"
return "OK"
}
}
fun box(): String {
return A().test()
}
@@ -0,0 +1,6 @@
enum class Foo(val a: Int = 1) {
A: Foo()
}
// CLASS: Foo
// HAS_DEFAULT_CONSTRUCTOR: false
@@ -53,6 +53,11 @@ public class DefaultArgumentsReflectionTestGenerated extends AbstractDefaultCons
doTest("compiler/testData/codegen/defaultArguments/reflection/classWithVararg.kt");
}
@TestMetadata("enum.kt")
public void testEnum() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/reflection/enum.kt");
}
@TestMetadata("internalClass.kt")
public void testInternalClass() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/reflection/internalClass.kt");
@@ -28,7 +28,7 @@ import org.jetbrains.jet.codegen.generated.AbstractCodegenTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
@TestMetadata("compiler/testData/codegen/defaultArguments/blackBox")
@InnerTestClasses({DefaultArgumentsBlackBoxTestGenerated.Constructor.class})
@InnerTestClasses({DefaultArgumentsBlackBoxTestGenerated.Constructor.class, DefaultArgumentsBlackBoxTestGenerated.Function.class})
public class DefaultArgumentsBlackBoxTestGenerated extends AbstractCodegenTest {
public void testAllFilesPresentInBlackBox() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/defaultArguments/blackBox"), "kt", true);
@@ -40,6 +40,11 @@ public class DefaultArgumentsBlackBoxTestGenerated extends AbstractCodegenTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/defaultArguments/blackBox/constructor"), "kt", true);
}
@TestMetadata("annotation.kt")
public void testAnnotation() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/annotation.kt");
}
@TestMetadata("defArgs1.kt")
public void testDefArgs1() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/defArgs1.kt");
@@ -55,6 +60,31 @@ public class DefaultArgumentsBlackBoxTestGenerated extends AbstractCodegenTest {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/defArgs2.kt");
}
@TestMetadata("doubleDefArgs1InnerClass.kt")
public void testDoubleDefArgs1InnerClass() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/doubleDefArgs1InnerClass.kt");
}
@TestMetadata("enum.kt")
public void testEnum() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/enum.kt");
}
@TestMetadata("enumWithOneDefArg.kt")
public void testEnumWithOneDefArg() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/enumWithOneDefArg.kt");
}
@TestMetadata("enumWithTwoDefArgs.kt")
public void testEnumWithTwoDefArgs() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/enumWithTwoDefArgs.kt");
}
@TestMetadata("enumWithTwoDoubleDefArgs.kt")
public void testEnumWithTwoDoubleDefArgs() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/enumWithTwoDoubleDefArgs.kt");
}
@TestMetadata("kt2852.kt")
public void testKt2852() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/constructor/kt2852.kt");
@@ -62,10 +92,69 @@ public class DefaultArgumentsBlackBoxTestGenerated extends AbstractCodegenTest {
}
@TestMetadata("compiler/testData/codegen/defaultArguments/blackBox/function")
public static class Function extends AbstractCodegenTest {
public void testAllFilesPresentInFunction() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/defaultArguments/blackBox/function"), "kt", true);
}
@TestMetadata("extentionFunction.kt")
public void testExtentionFunction() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/extentionFunction.kt");
}
@TestMetadata("extentionFunctionDouble.kt")
public void testExtentionFunctionDouble() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/extentionFunctionDouble.kt");
}
@TestMetadata("extentionFunctionDoubleTwoArgs.kt")
public void testExtentionFunctionDoubleTwoArgs() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/extentionFunctionDoubleTwoArgs.kt");
}
@TestMetadata("extentionFunctionInClassObject.kt")
public void testExtentionFunctionInClassObject() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/extentionFunctionInClassObject.kt");
}
@TestMetadata("extentionFunctionInObject.kt")
public void testExtentionFunctionInObject() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/extentionFunctionInObject.kt");
}
@TestMetadata("extentionFunctionWithOneDefArg.kt")
public void testExtentionFunctionWithOneDefArg() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/extentionFunctionWithOneDefArg.kt");
}
@TestMetadata("funInTrait.kt")
public void testFunInTrait() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/funInTrait.kt");
}
@TestMetadata("innerExtentionFunction.kt")
public void testInnerExtentionFunction() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/innerExtentionFunction.kt");
}
@TestMetadata("innerExtentionFunctionDouble.kt")
public void testInnerExtentionFunctionDouble() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/innerExtentionFunctionDouble.kt");
}
@TestMetadata("innerExtentionFunctionDoubleTwoArgs.kt")
public void testInnerExtentionFunctionDoubleTwoArgs() throws Exception {
doTest("compiler/testData/codegen/defaultArguments/blackBox/function/innerExtentionFunctionDoubleTwoArgs.kt");
}
}
public static Test suite() {
TestSuite suite = new TestSuite("DefaultArgumentsBlackBoxTestGenerated");
suite.addTestSuite(DefaultArgumentsBlackBoxTestGenerated.class);
suite.addTestSuite(Constructor.class);
suite.addTestSuite(Function.class);
return suite;
}
}