Fix primitive override problem in Kotlin-Java inheritance

See the comment in JetTypeMapper
This commit is contained in:
Alexander Udalov
2013-12-25 19:39:57 +04:00
parent 2ea62bde23
commit 713c6f13ae
26 changed files with 358 additions and 2 deletions
@@ -606,13 +606,38 @@ public class JetTypeMapper extends BindingTraceAware {
}
sw.writeReturnType();
mapReturnType(f, sw);
if (forceBoxedReturnType(f)) {
// TYPE_PARAMETER is a hack to automatically box the return type
//noinspection ConstantConditions
mapType(f.getReturnType(), sw, JetTypeMapperMode.TYPE_PARAMETER);
}
else {
mapReturnType(f, sw);
}
sw.writeReturnTypeEnd();
}
return sw.makeJvmMethodSignature(mapFunctionName(f));
}
/**
* @return true iff a given function descriptor should be compiled to a method with boxed return type regardless of whether return type
* of that descriptor is nullable or not. This happens when a function returning a value of a primitive type overrides another function
* with a non-primitive return type. In that case the generated method's return type should be boxed: otherwise it's not possible to use
* this class from Java since javac issues errors when loading the class (incompatible return types)
*/
private static boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) {
//noinspection ConstantConditions
if (!KotlinBuiltIns.getInstance().isPrimitiveType(descriptor.getReturnType())) return false;
for (FunctionDescriptor overridden : descriptor.getOverriddenDescriptors()) {
//noinspection ConstantConditions
if (!KotlinBuiltIns.getInstance().isPrimitiveType(overridden.getOriginal().getReturnType())) return true;
}
return false;
}
private static void writeVoidReturn(@NotNull BothSignatureWriter sw) {
sw.writeReturnType();
sw.writeAsmType(Type.VOID_TYPE);
@@ -0,0 +1,10 @@
class A {
fun foo(): Int = 42
}
fun bar() = A().foo()
// Test that for a simple final method in a final class we don't generate a bridge returning wrapper type
// (we only generate the method returning a primitive int)
// 0 foo\(\)Ljava/lang/Integer;
@@ -0,0 +1,18 @@
class ExtendsB extends B {
void test() {
byte x = foo();
Byte y = foo();
Object z = foo();
}
}
class ExtendsC extends C {
void test() {
byte x = foo();
Byte y = foo();
Object z = foo();
}
@Override
public Byte foo() { return 42; }
}
@@ -0,0 +1,9 @@
trait A<T> {
fun foo(): T
}
open class B : A<Byte> {
override fun foo(): Byte = 42
}
abstract class C : A<Byte>
@@ -0,0 +1,13 @@
class Test {
void test() {
A<Integer> a = new B();
int ax = a.foo();
Integer ay = a.foo();
Object az = a.foo();
B b = new B();
int bx = b.foo();
Integer by = b.foo();
Object bz = b.foo();
}
}
@@ -0,0 +1,7 @@
trait A<T> {
fun foo(): T
}
class B : A<Int> {
override final fun foo(): Int = 42
}
@@ -0,0 +1,13 @@
class Test {
void test() {
A<Integer> a = new B();
int ax = a.foo();
Integer ay = a.foo();
Object az = a.foo();
B b = new B();
int bx = b.foo();
Integer by = b.foo();
Object bz = b.foo();
}
}
@@ -0,0 +1,7 @@
trait A<T> {
fun foo(): T
}
class B : A<Int> {
override fun foo(): Int = 42
}
@@ -0,0 +1,7 @@
class Test extends B {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
}
@@ -0,0 +1,7 @@
trait A {
fun foo(): Any
}
open class B : A {
override fun foo(): Int = 42
}
@@ -0,0 +1,13 @@
class Test extends B {
void test() {
A<Integer> a = new B();
int ax = a.foo();
Integer ay = a.foo();
Object az = a.foo();
B b = new B();
int bx = b.foo();
Integer by = b.foo();
Object bz = b.foo();
}
}
@@ -0,0 +1,7 @@
trait A<T> {
fun foo(): T
}
open class B : A<Int> {
override final fun foo(): Int = 42
}
@@ -0,0 +1,18 @@
class ExtendsB extends B {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
}
class ExtendsC extends C {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
@Override
public Integer foo() { return 42; }
}
@@ -0,0 +1,9 @@
trait A<T : Comparable<T>> {
fun foo(): T
}
open class B : A<Int> {
override fun foo(): Int = 42
}
abstract class C : A<Int>
@@ -0,0 +1,18 @@
class ExtendsB extends B {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
}
class ExtendsC extends C {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
@Override
public Integer foo() { return 42; }
}
@@ -0,0 +1,9 @@
trait A<T : Number> {
fun foo(): T
}
open class B : A<Int> {
override fun foo(): Int = 42
}
abstract class C : A<Int>
@@ -0,0 +1,18 @@
class ExtendsB extends B {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
}
class ExtendsC extends C {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
@Override
public Integer foo() { return 42; }
}
@@ -0,0 +1,9 @@
trait A<T> {
fun foo(): T
}
open class B : A<Int> {
override fun foo(): Int = 42
}
abstract class C : A<Int>
@@ -0,0 +1,7 @@
class ExtendsD extends D {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
}
@@ -0,0 +1,11 @@
trait A<T> {
fun foo(): T
}
trait B : A
abstract class C : B
open class D : C() {
override fun foo(): Int = 42
}
@@ -0,0 +1,18 @@
class ExtendsB extends B {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
}
class ExtendsC extends C {
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
@Override
public Integer foo() { return 42; }
}
@@ -0,0 +1,9 @@
trait A<T> {
fun foo(): T
}
open class B : A<Int?> {
override fun foo(): Int? = 42
}
abstract class C : A<Int?>
@@ -0,0 +1,12 @@
class ExtendsB extends B {
@Override
public Integer foo() {
return 239;
}
void test() {
int x = foo();
Integer y = foo();
Object z = foo();
}
}
@@ -0,0 +1,7 @@
trait A<T> {
fun foo(): T
}
abstract class B : A<Int> {
override abstract fun foo(): Int
}
@@ -92,6 +92,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest("compiler/testData/codegen/bytecodeText/noVolatileAnnotation.kt");
}
@TestMetadata("noWrapperForMethodReturningPrimitive.kt")
public void testNoWrapperForMethodReturningPrimitive() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/noWrapperForMethodReturningPrimitive.kt");
}
@TestMetadata("privateDefaultArgs.kt")
public void testPrivateDefaultArgs() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt");
@@ -91,6 +91,7 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
}
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method")
@InnerTestClasses({Method.PrimitiveOverride.class})
public static class Method extends AbstractCompileJavaAgainstKotlinTest {
public void testAllFilesPresentInMethod() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/compileJavaAgainstKotlin/method"), Pattern.compile("^(.+)\\.kt$"), true);
@@ -186,6 +187,75 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
doTest("compiler/testData/compileJavaAgainstKotlin/method/Void.kt");
}
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride")
public static class PrimitiveOverride extends AbstractCompileJavaAgainstKotlinTest {
public void testAllFilesPresentInPrimitiveOverride() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("ByteOverridesObject.kt")
public void testByteOverridesObject() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/ByteOverridesObject.kt");
}
@TestMetadata("CallFinalNotInSubclass.kt")
public void testCallFinalNotInSubclass() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/CallFinalNotInSubclass.kt");
}
@TestMetadata("CallNotInSubclass.kt")
public void testCallNotInSubclass() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/CallNotInSubclass.kt");
}
@TestMetadata("CovariantReturnTypeOverride.kt")
public void testCovariantReturnTypeOverride() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/CovariantReturnTypeOverride.kt");
}
@TestMetadata("FinalOverride.kt")
public void testFinalOverride() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/FinalOverride.kt");
}
@TestMetadata("IntOverridesComparable.kt")
public void testIntOverridesComparable() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/IntOverridesComparable.kt");
}
@TestMetadata("IntOverridesNumber.kt")
public void testIntOverridesNumber() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/IntOverridesNumber.kt");
}
@TestMetadata("IntOverridesObject.kt")
public void testIntOverridesObject() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/IntOverridesObject.kt");
}
@TestMetadata("ManyClassesHierarchy.kt")
public void testManyClassesHierarchy() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/ManyClassesHierarchy.kt");
}
@TestMetadata("NullableIntOverridesObject.kt")
public void testNullableIntOverridesObject() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/NullableIntOverridesObject.kt");
}
@TestMetadata("OverrideInJava.kt")
public void testOverrideInJava() throws Exception {
doTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverride/OverrideInJava.kt");
}
}
public static Test innerSuite() {
TestSuite suite = new TestSuite("Method");
suite.addTestSuite(Method.class);
suite.addTestSuite(PrimitiveOverride.class);
return suite;
}
}
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/property")
@@ -238,7 +308,7 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
TestSuite suite = new TestSuite("CompileJavaAgainstKotlinTestGenerated");
suite.addTestSuite(CompileJavaAgainstKotlinTestGenerated.class);
suite.addTestSuite(Class.class);
suite.addTestSuite(Method.class);
suite.addTest(Method.innerSuite());
suite.addTestSuite(Property.class);
suite.addTestSuite(StaticFields.class);
return suite;