Use wrappers around java.util.* to emulate kotlin.collection.* behaviour

Backend: If kotlin class extends kotlin.collection.List
    write it as it's super interface (light class mode only)
IDE: Provide wrapper classes to java resolve
    that try to emulate backend behaviour

For example if kotlin class implements kotlin.collections.Map,
    we provide a superinterface that has abstract 'getEntries' method
    and 'entrySet' method that is considered default.
In reality all those methods are generated in the class itself.

In IDE supporting this case without hacks is not feasible performance-wise
    since kotlin.collection.* may not be an immediate supertype and we need
    to compute all supertypes just to calculate own methods of the class
This commit is contained in:
Pavel V. Talanov
2017-05-03 14:34:32 +03:00
parent c56f74cc81
commit 798c80ed07
24 changed files with 1182 additions and 25 deletions
@@ -50,7 +50,7 @@ private fun String.method(name: String, parameters: String, returnType: String)
SignatureBuildingComponents.signature(this@method, "$name($parameters)$returnType"))
object BuiltinSpecialProperties {
private val PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP = mapOf(
val PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP = mapOf(
BUILTIN_NAMES._enum.childSafe("name") to Name.identifier("name"),
BUILTIN_NAMES._enum.childSafe("ordinal") to Name.identifier("ordinal"),
BUILTIN_NAMES.collection.child("size") to Name.identifier("size"),
@@ -99,6 +99,7 @@ object BuiltinMethodsWithSpecialGenericSignature {
).map { "java/util/Collection".method(it, "Ljava/util/Collection;", JvmPrimitiveType.BOOLEAN.desc) }
private val ERASED_COLLECTION_PARAMETER_SIGNATURES = ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES.map { it.signature }
val ERASED_COLLECTION_PARAMETER_NAMES = ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES.map { it.name.asString() }
enum class TypeSafeBarrierDescription(val defaultValue: Any?) {
NULL(null), INDEX(-1), FALSE(false),
@@ -144,7 +145,7 @@ object BuiltinMethodsWithSpecialGenericSignature {
private val SIGNATURE_TO_DEFAULT_VALUES_MAP = GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP.mapKeys { it.key.signature }
private val ERASED_VALUE_PARAMETERS_SHORT_NAMES: Set<Name>
private val ERASED_VALUE_PARAMETERS_SIGNATURES: Set<String>
val ERASED_VALUE_PARAMETERS_SIGNATURES: Set<String>
init {
val allMethods = GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP.keys + ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES
@@ -26,6 +26,7 @@ class TypeMappingMode private constructor(
val skipDeclarationSiteWildcards: Boolean = false,
val skipDeclarationSiteWildcardsIfPossible: Boolean = false,
private val genericArgumentMode: TypeMappingMode? = null,
val kotlinCollectionsToJavaCollections: Boolean = true,
private val genericContravariantArgumentMode: TypeMappingMode? = genericArgumentMode,
private val genericInvariantArgumentMode: TypeMappingMode? = genericArgumentMode
) {
@@ -49,6 +50,13 @@ class TypeMappingMode private constructor(
@JvmField
val SUPER_TYPE = TypeMappingMode(skipDeclarationSiteWildcards = true, genericArgumentMode = GENERIC_ARGUMENT)
@JvmField
val SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS = TypeMappingMode(
skipDeclarationSiteWildcards = true,
genericArgumentMode = GENERIC_ARGUMENT,
kotlinCollectionsToJavaCollections = false
)
/**
* kotlin.reflect.KClass mapped to java.lang.Class
* Other types mapped as DEFAULT
@@ -81,7 +81,7 @@ fun <T : Any> mapType(
)
}
mapBuiltInType(kotlinType, factory, typeMappingConfiguration)?.let { builtInType ->
mapBuiltInType(kotlinType, factory, mode, typeMappingConfiguration)?.let { builtInType ->
val jvmType = factory.boxTypeIfNeeded(builtInType, mode.needPrimitiveBoxing)
writeGenericType(kotlinType, jvmType, mode)
return jvmType
@@ -186,6 +186,7 @@ fun hasVoidReturnType(descriptor: CallableDescriptor): Boolean {
private fun <T : Any> mapBuiltInType(
type: KotlinType,
typeFactory: JvmTypeFactory<T>,
mode: TypeMappingMode,
typeMappingConfiguration: TypeMappingConfiguration<T>
): T? {
val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
@@ -211,6 +212,8 @@ private fun <T : Any> mapBuiltInType(
val classId = JavaToKotlinClassMap.mapKotlinToJava(fqName)
if (classId != null) {
if (!mode.kotlinCollectionsToJavaCollections && JavaToKotlinClassMap.mutabilityMappings.any { it.javaClass == classId }) return null
return typeFactory.createObjectType(JvmClassName.byClassId(classId, typeMappingConfiguration).internalName)
}