Setup default values for type-safe bridges
#KT-9973 In Progress
This commit is contained in:
@@ -883,7 +883,9 @@ public class FunctionCodegen {
|
||||
@NotNull Method bridge,
|
||||
@NotNull final Method delegateTo
|
||||
) {
|
||||
if (BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) == null) return;
|
||||
BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue =
|
||||
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
|
||||
if (defaultValue == null) return;
|
||||
|
||||
assert descriptor.getValueParameters().size() == 1 : "Should be descriptor with one value parameter, but found: " + descriptor;
|
||||
|
||||
@@ -904,12 +906,10 @@ public class FunctionCodegen {
|
||||
|
||||
iv.ifne(afterBarrier);
|
||||
|
||||
String shortName = getFqName(descriptor).shortName().asString();
|
||||
StackValue returnValue =
|
||||
("indexOf".equals(shortName) || "lastIndexOf".equals(shortName)) ? StackValue.constant(-1, Type.INT_TYPE) : StackValue.none();
|
||||
Type returnType = bridge.getReturnType();
|
||||
|
||||
returnValue.put(bridge.getReturnType(), iv);
|
||||
iv.areturn(bridge.getReturnType());
|
||||
StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv);
|
||||
iv.areturn(returnType);
|
||||
|
||||
iv.visitLabel(afterBarrier);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
private object EmptyList : List<Nothing> {
|
||||
override fun contains(element: Nothing): Boolean = false
|
||||
override fun containsAll(elements: Collection<Nothing>): Boolean = elements.isEmpty()
|
||||
override fun indexOf(element: Nothing): Int = -2
|
||||
override fun lastIndexOf(element: Nothing): Int = -2
|
||||
|
||||
override val size: Int get() = 0
|
||||
override fun isEmpty(): Boolean = true
|
||||
|
||||
override fun iterator(): Iterator<Nothing> = throw UnsupportedOperationException()
|
||||
override fun get(index: Int): Nothing = throw UnsupportedOperationException()
|
||||
override fun listIterator(): ListIterator<Nothing> = throw UnsupportedOperationException()
|
||||
override fun listIterator(index: Int): ListIterator<Nothing> = throw UnsupportedOperationException()
|
||||
override fun subList(fromIndex: Int, toIndex: Int): List<Nothing> = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val n = EmptyList as List<Any?>
|
||||
|
||||
if (n.contains(null)) return "fail 1"
|
||||
if (n.indexOf(null) != -1) return "fail 2"
|
||||
if (n.lastIndexOf(null) != -1) return "fail 3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
private object EmptyMap : Map<Any, Nothing> {
|
||||
override val size: Int get() = 0
|
||||
override fun isEmpty(): Boolean = true
|
||||
|
||||
override fun containsKey(key: Any): Boolean = false
|
||||
override fun containsValue(value: Nothing): Boolean = false
|
||||
override fun get(key: Any): Nothing? = null
|
||||
override val entries: Set<Map.Entry<String, Nothing>> get() = null!!
|
||||
override val keys: Set<String> get() = null!!
|
||||
override val values: Collection<Nothing> get() = null!!
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
val n = EmptyMap as Map<Any?, Any?>
|
||||
|
||||
if (n.get(null) != null) return "fail 1"
|
||||
if (n.containsKey(null)) return "fail 2"
|
||||
if (n.containsValue(null)) return "fail 3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
private object EmptyStringMap : Map<String, Nothing> {
|
||||
override val size: Int get() = 0
|
||||
override fun isEmpty(): Boolean = true
|
||||
|
||||
override fun containsKey(key: String): Boolean = false
|
||||
override fun containsValue(value: Nothing): Boolean = false
|
||||
override fun get(key: String): Nothing? = null
|
||||
override val entries: Set<Map.Entry<String, Nothing>> get() = null!!
|
||||
override val keys: Set<String> get() = null!!
|
||||
override val values: Collection<Nothing> get() = null!!
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val n = EmptyStringMap as Map<Any?, Any?>
|
||||
|
||||
if (n.get(null) != null) return "fail 1"
|
||||
if (n.containsKey(null)) return "fail 2"
|
||||
if (n.containsValue(null)) return "fail 3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+18
@@ -7327,6 +7327,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyList.kt")
|
||||
public void testEmptyList() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/emptyList.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyMap.kt")
|
||||
public void testEmptyMap() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/emptyMap.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyStringMap.kt")
|
||||
public void testEmptyStringMap() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/emptyStringMap.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("enumAsOrdinaled.kt")
|
||||
public void testEnumAsOrdinaled() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/enumAsOrdinaled.kt");
|
||||
|
||||
+28
-13
@@ -59,8 +59,8 @@ object BuiltinSpecialProperties {
|
||||
return callableMemberDescriptor.hasBuiltinSpecialPropertyFqNameImpl()
|
||||
}
|
||||
|
||||
fun CallableMemberDescriptor.hasBuiltinSpecialPropertyFqNameImpl(): Boolean {
|
||||
if (fqNameOrNull() in FQ_NAMES) return true
|
||||
private fun CallableMemberDescriptor.hasBuiltinSpecialPropertyFqNameImpl(): Boolean {
|
||||
if (FQ_NAMES.containsRaw(fqNameOrNull())) return true
|
||||
if (!isFromBuiltins()) return false
|
||||
|
||||
return overriddenDescriptors.any { hasBuiltinSpecialPropertyFqName(it) }
|
||||
@@ -83,19 +83,26 @@ object BuiltinMethodsWithSpecialGenericSignature {
|
||||
FqName("kotlin.MutableCollection.removeAll"),
|
||||
FqName("kotlin.MutableCollection.retainAll")
|
||||
)
|
||||
private val GENERIC_PARAMETERS_FQ_NAMES = setOf(
|
||||
FqName("kotlin.Collection.contains"),
|
||||
FqName("kotlin.MutableCollection.remove"),
|
||||
FqName("kotlin.Map.containsKey"),
|
||||
FqName("kotlin.Map.containsValue"),
|
||||
FqName("kotlin.Map.get"),
|
||||
FqName("kotlin.MutableMap.remove"),
|
||||
FqName("kotlin.List.indexOf"),
|
||||
FqName("kotlin.List.lastIndexOf")
|
||||
|
||||
public enum class DefaultValue(val value: Any?) {
|
||||
NULL(null), INDEX(-1), FALSE(false)
|
||||
}
|
||||
|
||||
private val GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP = mapOf(
|
||||
FqName("kotlin.Collection.contains") to DefaultValue.FALSE,
|
||||
FqName("kotlin.MutableCollection.remove") to DefaultValue.FALSE,
|
||||
FqName("kotlin.Map.containsKey") to DefaultValue.FALSE,
|
||||
FqName("kotlin.Map.containsValue") to DefaultValue.FALSE,
|
||||
|
||||
FqName("kotlin.Map.get") to DefaultValue.NULL,
|
||||
FqName("kotlin.MutableMap.remove") to DefaultValue.NULL,
|
||||
|
||||
FqName("kotlin.List.indexOf") to DefaultValue.INDEX,
|
||||
FqName("kotlin.List.lastIndexOf") to DefaultValue.INDEX
|
||||
)
|
||||
|
||||
private val ERASED_VALUE_PARAMETERS_FQ_NAMES =
|
||||
GENERIC_PARAMETERS_FQ_NAMES + ERASED_COLLECTION_PARAMETER_FQ_NAMES
|
||||
GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP.keys + ERASED_COLLECTION_PARAMETER_FQ_NAMES
|
||||
|
||||
private val ERASED_VALUE_PARAMETERS_SHORT_NAMES =
|
||||
ERASED_VALUE_PARAMETERS_FQ_NAMES.map { it.shortName() }.toSet()
|
||||
@@ -111,6 +118,14 @@ object BuiltinMethodsWithSpecialGenericSignature {
|
||||
return functionDescriptor.firstOverridden { it.hasErasedValueParametersInJava } as FunctionDescriptor?
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDefaultValueForOverriddenBuiltinFunction(functionDescriptor: FunctionDescriptor): DefaultValue? {
|
||||
if (functionDescriptor.name !in ERASED_VALUE_PARAMETERS_SHORT_NAMES) return null
|
||||
return functionDescriptor.firstOverridden {
|
||||
GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP.keys.containsRaw(it.fqNameOrNull())
|
||||
}?.let { GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP[it.fqNameSafe] }
|
||||
}
|
||||
|
||||
val Name.sameAsBuiltinMethodWithErasedValueParameters: Boolean
|
||||
get () = this in ERASED_VALUE_PARAMETERS_SHORT_NAMES
|
||||
|
||||
@@ -131,7 +146,7 @@ object BuiltinMethodsWithSpecialGenericSignature {
|
||||
|
||||
return when (builtinFqName) {
|
||||
in ERASED_COLLECTION_PARAMETER_FQ_NAMES -> SpecialSignatureInfo.ONE_COLLECTION_PARAMETER
|
||||
in GENERIC_PARAMETERS_FQ_NAMES -> SpecialSignatureInfo.GENERIC_PARAMETER
|
||||
in GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP -> SpecialSignatureInfo.GENERIC_PARAMETER
|
||||
else -> error("Unexpected kind of special builtin: $builtinFqName")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user