Fix primitive override problem in Kotlin-Java inheritance
See the comment in JetTypeMapper
This commit is contained in:
@@ -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;
|
||||
+18
@@ -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; }
|
||||
}
|
||||
+9
@@ -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>
|
||||
+13
@@ -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();
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
trait A<T> {
|
||||
fun foo(): T
|
||||
}
|
||||
|
||||
class B : A<Int> {
|
||||
override final fun foo(): Int = 42
|
||||
}
|
||||
+13
@@ -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();
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
trait A<T> {
|
||||
fun foo(): T
|
||||
}
|
||||
|
||||
class B : A<Int> {
|
||||
override fun foo(): Int = 42
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class Test extends B {
|
||||
void test() {
|
||||
int x = foo();
|
||||
Integer y = foo();
|
||||
Object z = foo();
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
trait A {
|
||||
fun foo(): Any
|
||||
}
|
||||
|
||||
open class B : A {
|
||||
override fun foo(): Int = 42
|
||||
}
|
||||
+13
@@ -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
|
||||
}
|
||||
+18
@@ -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; }
|
||||
}
|
||||
+9
@@ -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>
|
||||
+18
@@ -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; }
|
||||
}
|
||||
+9
@@ -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>
|
||||
+18
@@ -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; }
|
||||
}
|
||||
+9
@@ -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>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class ExtendsD extends D {
|
||||
void test() {
|
||||
int x = foo();
|
||||
Integer y = foo();
|
||||
Object z = foo();
|
||||
}
|
||||
}
|
||||
+11
@@ -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
|
||||
}
|
||||
+18
@@ -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; }
|
||||
}
|
||||
+9
@@ -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?>
|
||||
+12
@@ -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");
|
||||
|
||||
+71
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user