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();
|
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();
|
sw.writeReturnTypeEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
return sw.makeJvmMethodSignature(mapFunctionName(f));
|
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) {
|
private static void writeVoidReturn(@NotNull BothSignatureWriter sw) {
|
||||||
sw.writeReturnType();
|
sw.writeReturnType();
|
||||||
sw.writeAsmType(Type.VOID_TYPE);
|
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");
|
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")
|
@TestMetadata("privateDefaultArgs.kt")
|
||||||
public void testPrivateDefaultArgs() throws Exception {
|
public void testPrivateDefaultArgs() throws Exception {
|
||||||
doTest("compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt");
|
doTest("compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt");
|
||||||
|
|||||||
+71
-1
@@ -91,6 +91,7 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method")
|
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method")
|
||||||
|
@InnerTestClasses({Method.PrimitiveOverride.class})
|
||||||
public static class Method extends AbstractCompileJavaAgainstKotlinTest {
|
public static class Method extends AbstractCompileJavaAgainstKotlinTest {
|
||||||
public void testAllFilesPresentInMethod() throws Exception {
|
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);
|
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");
|
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")
|
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/property")
|
||||||
@@ -238,7 +308,7 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
|
|||||||
TestSuite suite = new TestSuite("CompileJavaAgainstKotlinTestGenerated");
|
TestSuite suite = new TestSuite("CompileJavaAgainstKotlinTestGenerated");
|
||||||
suite.addTestSuite(CompileJavaAgainstKotlinTestGenerated.class);
|
suite.addTestSuite(CompileJavaAgainstKotlinTestGenerated.class);
|
||||||
suite.addTestSuite(Class.class);
|
suite.addTestSuite(Class.class);
|
||||||
suite.addTestSuite(Method.class);
|
suite.addTest(Method.innerSuite());
|
||||||
suite.addTestSuite(Property.class);
|
suite.addTestSuite(Property.class);
|
||||||
suite.addTestSuite(StaticFields.class);
|
suite.addTestSuite(StaticFields.class);
|
||||||
return suite;
|
return suite;
|
||||||
|
|||||||
Reference in New Issue
Block a user