diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 4a2714b33a1..92bf9d6199b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -529,8 +529,11 @@ public class FunctionCodegen { ); if (!bridgesToGenerate.isEmpty()) { PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; + boolean isSpecialBridge = + BuiltinsPropertiesUtilKt.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null; + for (Bridge bridge : bridgesToGenerate) { - generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), false, false); + generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), isSpecialBridge, false); } } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index 6e46a0ec99a..37a510e5119 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider; import org.jetbrains.kotlin.load.java.BuiltinsPropertiesUtilKt; import org.jetbrains.kotlin.load.java.JvmAbi; +import org.jetbrains.kotlin.load.java.SpecialSignatureInfo; import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageScope; @@ -941,7 +942,19 @@ public class JetTypeMapper { sw.writeReturnTypeEnd(); } - return sw.makeJvmMethodSignature(mapFunctionName(f)); + JvmMethodSignature signature = sw.makeJvmMethodSignature(mapFunctionName(f)); + + + if (kind != OwnerKind.DEFAULT_IMPLS) { + SpecialSignatureInfo specialSignatureInfo = BuiltinsPropertiesUtilKt.getSpecialSignatureInfo(f); + + if (specialSignatureInfo != null) { + return new JvmMethodSignature( + signature.getAsmMethod(), specialSignatureInfo.getSignature(), signature.getValueParameters()); + } + } + + return signature; } @NotNull diff --git a/compiler/testData/codegen/boxWithJava/collections/mutableList/J.java b/compiler/testData/codegen/boxWithJava/collections/mutableList/J.java new file mode 100644 index 00000000000..cfc22995761 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/collections/mutableList/J.java @@ -0,0 +1,13 @@ +import java.util.*; + +public class J { + + private static class MyList extends KList {} + + public static String foo() { + Collection collection = new MyList(); + if (!collection.contains("ABCDE")) return "fail 1"; + if (!collection.containsAll(Arrays.asList(1, 2, 3))) return "fail 2"; + return "OK"; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/collections/mutableList/mutableList.kt b/compiler/testData/codegen/boxWithJava/collections/mutableList/mutableList.kt new file mode 100644 index 00000000000..e01cf058ed9 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/collections/mutableList/mutableList.kt @@ -0,0 +1,81 @@ +open class KList : MutableList { + override fun add(e: E): Boolean { + throw UnsupportedOperationException() + } + + override fun remove(o: Any?): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(index: Int, c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun removeAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun retainAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun clear() { + throw UnsupportedOperationException() + } + + override fun set(index: Int, element: E): E { + throw UnsupportedOperationException() + } + + override fun add(index: Int, element: E) { + throw UnsupportedOperationException() + } + + override fun remove(index: Int): E { + throw UnsupportedOperationException() + } + + override fun listIterator(): MutableListIterator { + throw UnsupportedOperationException() + } + + override fun listIterator(index: Int): MutableListIterator { + throw UnsupportedOperationException() + } + + override fun subList(fromIndex: Int, toIndex: Int): MutableList { + throw UnsupportedOperationException() + } + + override fun iterator(): MutableIterator { + throw UnsupportedOperationException() + } + + override val size: Int + get() = throw UnsupportedOperationException() + + override fun isEmpty(): Boolean { + throw UnsupportedOperationException() + } + + override fun contains(o: E) = true + override fun containsAll(c: Collection) = true + + override fun get(index: Int): E { + throw UnsupportedOperationException() + } + + override fun indexOf(o: Any?): Int { + throw UnsupportedOperationException() + } + + override fun lastIndexOf(o: Any?): Int { + throw UnsupportedOperationException() + } +} + +fun box() = J.foo() diff --git a/compiler/testData/codegen/boxWithJava/collections/strList/J.java b/compiler/testData/codegen/boxWithJava/collections/strList/J.java new file mode 100644 index 00000000000..9c9ed7d421a --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/collections/strList/J.java @@ -0,0 +1,13 @@ +import java.util.*; + +public class J { + + private static class MyList extends KList {} + + public static String foo() { + Collection collection = new MyList(); + if (!collection.contains("ABCDE")) return "fail 1"; + if (!collection.containsAll(Arrays.asList(1, 2, 3))) return "fail 2"; + return "OK"; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/collections/strList/strList.kt b/compiler/testData/codegen/boxWithJava/collections/strList/strList.kt new file mode 100644 index 00000000000..0d16bb3034c --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/collections/strList/strList.kt @@ -0,0 +1,81 @@ +open class KList : MutableList { + override val size: Int + get() = throw UnsupportedOperationException() + + override fun isEmpty(): Boolean { + throw UnsupportedOperationException() + } + + override fun contains(o: String) = true + override fun containsAll(c: Collection) = true + + override fun get(index: Int): String { + throw UnsupportedOperationException() + } + + override fun indexOf(o: Any?): Int { + throw UnsupportedOperationException() + } + + override fun lastIndexOf(o: Any?): Int { + throw UnsupportedOperationException() + } + + override fun iterator(): MutableIterator { + throw UnsupportedOperationException() + } + + override fun add(e: String): Boolean { + throw UnsupportedOperationException() + } + + override fun remove(o: Any?): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun addAll(index: Int, c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun removeAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun retainAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun clear() { + throw UnsupportedOperationException() + } + + override fun set(index: Int, element: String): String { + throw UnsupportedOperationException() + } + + override fun add(index: Int, element: String) { + throw UnsupportedOperationException() + } + + override fun remove(index: Int): String { + throw UnsupportedOperationException() + } + + override fun listIterator(): MutableListIterator { + throw UnsupportedOperationException() + } + + override fun listIterator(index: Int): MutableListIterator { + throw UnsupportedOperationException() + } + + override fun subList(fromIndex: Int, toIndex: Int): MutableList { + throw UnsupportedOperationException() + } + +} +fun box() = J.foo() diff --git a/compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt b/compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt new file mode 100644 index 00000000000..8848e878fdb --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt @@ -0,0 +1,110 @@ +abstract class A1 : MutableCollection { + override fun contains(o: Q): Boolean { + throw UnsupportedOperationException() + } + + override fun containsAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } +} + +abstract class A2 : MutableCollection { + override fun contains(o: String): Boolean { + throw UnsupportedOperationException() + } + + override fun containsAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } +} + +abstract class A3 : java.util.AbstractList() +abstract class A4 : java.util.AbstractList() { + override fun contains(o: W): Boolean { + throw UnsupportedOperationException() + } + + override fun containsAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } +} + +abstract class A5 : java.util.AbstractList() +abstract class A6 : java.util.AbstractList() { + override fun contains(o: String): Boolean { + throw UnsupportedOperationException() + } + + override fun containsAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } +} + +interface I1 : MutableSet { + override fun contains(o: R): Boolean { + throw UnsupportedOperationException() + } + + override fun containsAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } +} + +interface I2 : MutableSet { + override fun contains(o: String): Boolean { + throw UnsupportedOperationException() + } + + override fun containsAll(c: Collection): Boolean { + throw UnsupportedOperationException() + } +} + +abstract class A7 : MutableCollection { + override fun contains(o: Int): Boolean { + throw UnsupportedOperationException() + } +} + +abstract class A8 : MutableCollection { + override fun contains(o: Any?): Boolean { + throw UnsupportedOperationException() + } +} + + +fun foo( + a1: A1, + a2: A2, + a3: A3, + a4: A4, + a5: A5, + a6: A6, + a7: A7, + i1: I1, + i2: I2, + c: Collection +) { + a1.contains("") + a2.contains("") + a3.contains("") + a4.contains("") + a5.contains("") + a6.contains("") + a7.contains(1) + i1.contains("") + i2.contains("") + c.contains("") +} + +// 0 signature \(TQ;\)Z +// 0 signature \(TW;\)Z +// 0 signature \(TR;\)Z +// 6 signature \(Ljava/util/Collection<\+Ljava/lang/Object;>;\)Z +// 3 public final bridge contains\(Ljava/lang/Object;\)Z +// 4 INVOKEVIRTUAL A[0-9]\.contains \(Ljava/lang/String;\)Z +// 4 INVOKEVIRTUAL A[0-9]\.contains \(Ljava/lang/Object;\)Z +// 2 INVOKEVIRTUAL A7\.contains \(I\)Z +// 1 INVOKEINTERFACE java/util/Collection.contains \(Ljava/lang/Object;\)Z +// 1 INVOKEINTERFACE I1.contains \(Ljava/lang/Object;\)Z +// 1 INVOKEINTERFACE I2.contains \(Ljava/lang/String;\)Z \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 33a2d893379..64556859050 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -367,6 +367,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/builtinFunctions"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("contains.kt") + public void testContains() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/builtinFunctions/contains.kt"); + doTest(fileName); + } + @TestMetadata("size.kt") public void testSize() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/builtinFunctions/size.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 6305562ced5..22d60410167 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -165,6 +165,28 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege } + @TestMetadata("compiler/testData/codegen/boxWithJava/collections") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Collections extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInCollections() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithJava/collections"), Pattern.compile("^([^\\.]+)$"), true); + } + + @TestMetadata("mutableList") + public void testMutableList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/collections/mutableList/"); + doTestWithJava(fileName); + } + + @TestMetadata("strList") + public void testStrList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/collections/strList/"); + doTestWithJava(fileName); + } + + } + @TestMetadata("compiler/testData/codegen/boxWithJava/fileClasses") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/builtinsPropertiesUtil.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/builtinsPropertiesUtil.kt index 48d8636dcfb..902ac655526 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/builtinsPropertiesUtil.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/builtinsPropertiesUtil.kt @@ -126,3 +126,20 @@ private fun CallableMemberDescriptor.firstOverridden( val Name.sameAsBuiltinMethodWithErasedValueParameters: Boolean get () = this in BUILTIN_METHODS_ERASED_VALUE_PARAMETERS_SHORT_NAMES + +enum class SpecialSignatureInfo(val signature: String?) { + ONE_COLLECTION_PARAMETER("(Ljava/util/Collection<+Ljava/lang/Object;>;)Z"), + GENERIC_PARAMETER(null) +} + +val CallableMemberDescriptor.specialSignatureInfo: SpecialSignatureInfo? + get() { + val builtinFqName = firstOverridden { it is FunctionDescriptor && it.hasErasedValueParametersInJava }?.fqNameOrNull() + ?: return null + + return when (builtinFqName) { + in BUILTIN_METHODS_ERASED_COLLECTION_PARAMETER_FQ_NAMES -> SpecialSignatureInfo.ONE_COLLECTION_PARAMETER + in BUILTIN_METHODS_GENERIC_PARAMETERS_FQ_NAMES -> SpecialSignatureInfo.GENERIC_PARAMETER + else -> error("Unexpected kind of special builtin: $builtinFqName") + } + }