From bbbc910e026acf0704be7a03cedcfad9d2839138 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 14 Apr 2016 14:28:14 +0300 Subject: [PATCH] Load additional built-in classes constructors from JDK #KT-9194 In Progress #KT-5175 In Progress #KT-10370 In Progress #KT-7127 In Progress --- .../testData/builtin-classes/java6/kotlin.txt | 19 ++++++ .../testData/builtin-classes/java8/kotlin.txt | 20 ++++++ .../BuiltInClassesAreSerializableOnJvm.kt | 67 +++++++++++++++---- .../AdditionalClassPartsProvider.kt | 3 + .../DeserializedClassDescriptor.kt | 3 +- 5 files changed, 97 insertions(+), 15 deletions(-) diff --git a/compiler/testData/builtin-classes/java6/kotlin.txt b/compiler/testData/builtin-classes/java6/kotlin.txt index 957a9d5fe3b..afc2e125dd8 100644 --- a/compiler/testData/builtin-classes/java6/kotlin.txt +++ b/compiler/testData/builtin-classes/java6/kotlin.txt @@ -33,6 +33,7 @@ public final class Array : kotlin.Cloneable, java.io.Serializable { public final class Boolean : kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Boolean() + public constructor Boolean(/*0*/ p0: kotlin.String!) public final infix fun and(/*0*/ other: kotlin.Boolean): kotlin.Boolean public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Boolean): kotlin.Int public final operator fun not(): kotlin.Boolean @@ -53,6 +54,7 @@ public final class BooleanArray : kotlin.Cloneable, java.io.Serializable { public final class Byte : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Byte() + public constructor Byte(/*0*/ p0: kotlin.String!) public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -219,6 +221,7 @@ public final enum class DeprecationLevel : kotlin.Enum public final class Double : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Double() + public constructor Double(/*0*/ p0: kotlin.String!) public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -315,6 +318,8 @@ public abstract class Enum> : kotlin.Comparable, jav public final class Float : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Float() + public constructor Float(/*0*/ p0: kotlin.Double) + public constructor Float(/*0*/ p0: kotlin.String!) public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -394,6 +399,7 @@ public interface Function { public final class Int : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Int() + public constructor Int(/*0*/ p0: kotlin.String!) public final infix fun and(/*0*/ other: kotlin.Int): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int @@ -475,6 +481,7 @@ public final class IntArray : kotlin.Cloneable, java.io.Serializable { public final class Long : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Long() + public constructor Long(/*0*/ p0: kotlin.String!) public final infix fun and(/*0*/ other: kotlin.Long): kotlin.Long public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int @@ -579,6 +586,7 @@ public abstract class Number : kotlin.Any, java.io.Serializable { public final class Short : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Short() + public constructor Short(/*0*/ p0: kotlin.String!) public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -653,6 +661,17 @@ public final class ShortArray : kotlin.Cloneable, java.io.Serializable { public final class String : kotlin.Comparable, kotlin.CharSequence, java.io.Serializable { /*primary*/ public constructor String() + public constructor String(/*0*/ p0: java.lang.StringBuffer!) + public constructor String(/*0*/ p0: java.lang.StringBuilder!) + public constructor String(/*0*/ p0: kotlin.ByteArray!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: java.nio.charset.Charset!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int, /*3*/ p3: java.nio.charset.Charset!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int, /*3*/ p3: kotlin.String!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.String!) + public constructor String(/*0*/ p0: kotlin.CharArray!) + public constructor String(/*0*/ p0: kotlin.CharArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int) + public constructor String(/*0*/ p0: kotlin.IntArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int) public open override /*1*/ val length: kotlin.Int public open override /*1*/ fun (): kotlin.Int public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int diff --git a/compiler/testData/builtin-classes/java8/kotlin.txt b/compiler/testData/builtin-classes/java8/kotlin.txt index 41da529a741..0c021114448 100644 --- a/compiler/testData/builtin-classes/java8/kotlin.txt +++ b/compiler/testData/builtin-classes/java8/kotlin.txt @@ -33,6 +33,7 @@ public final class Array : kotlin.Cloneable, java.io.Serializable { public final class Boolean : kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Boolean() + public constructor Boolean(/*0*/ p0: kotlin.String!) public final infix fun and(/*0*/ other: kotlin.Boolean): kotlin.Boolean public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Boolean): kotlin.Int public final operator fun not(): kotlin.Boolean @@ -53,6 +54,7 @@ public final class BooleanArray : kotlin.Cloneable, java.io.Serializable { public final class Byte : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Byte() + public constructor Byte(/*0*/ p0: kotlin.String!) public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -221,6 +223,7 @@ public final enum class DeprecationLevel : kotlin.Enum public final class Double : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Double() + public constructor Double(/*0*/ p0: kotlin.String!) public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -317,6 +320,8 @@ public abstract class Enum> : kotlin.Comparable, jav public final class Float : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Float() + public constructor Float(/*0*/ p0: kotlin.Double) + public constructor Float(/*0*/ p0: kotlin.String!) public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -396,6 +401,7 @@ public interface Function { public final class Int : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Int() + public constructor Int(/*0*/ p0: kotlin.String!) public final infix fun and(/*0*/ other: kotlin.Int): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int @@ -477,6 +483,7 @@ public final class IntArray : kotlin.Cloneable, java.io.Serializable { public final class Long : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Long() + public constructor Long(/*0*/ p0: kotlin.String!) public final infix fun and(/*0*/ other: kotlin.Long): kotlin.Long public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int @@ -581,6 +588,7 @@ public abstract class Number : kotlin.Any, java.io.Serializable { public final class Short : kotlin.Number, kotlin.Comparable, java.io.Serializable { /*primary*/ private constructor Short() + public constructor Short(/*0*/ p0: kotlin.String!) public final operator fun compareTo(/*0*/ other: kotlin.Byte): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Double): kotlin.Int public final operator fun compareTo(/*0*/ other: kotlin.Float): kotlin.Int @@ -655,6 +663,17 @@ public final class ShortArray : kotlin.Cloneable, java.io.Serializable { public final class String : kotlin.Comparable, kotlin.CharSequence, java.io.Serializable { /*primary*/ public constructor String() + public constructor String(/*0*/ p0: java.lang.StringBuffer!) + public constructor String(/*0*/ p0: java.lang.StringBuilder!) + public constructor String(/*0*/ p0: kotlin.ByteArray!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: java.nio.charset.Charset!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int, /*3*/ p3: java.nio.charset.Charset!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int, /*3*/ p3: kotlin.String!) + public constructor String(/*0*/ p0: kotlin.ByteArray!, /*1*/ p1: kotlin.String!) + public constructor String(/*0*/ p0: kotlin.CharArray!) + public constructor String(/*0*/ p0: kotlin.CharArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int) + public constructor String(/*0*/ p0: kotlin.IntArray!, /*1*/ p1: kotlin.Int, /*2*/ p2: kotlin.Int) public open override /*1*/ val length: kotlin.Int public open override /*1*/ fun (): kotlin.Int public open override /*1*/ /*fake_override*/ fun chars(): java.util.stream.IntStream! @@ -677,6 +696,7 @@ public final class String : kotlin.Comparable, kotlin.CharSequenc public open class Throwable : kotlin.Any, java.io.Serializable { public constructor Throwable() + protected/*protected and package*/ constructor Throwable(/*0*/ p0: kotlin.String!, /*1*/ p1: kotlin.Throwable!, /*2*/ p2: kotlin.Boolean, /*3*/ p3: kotlin.Boolean) public constructor Throwable(/*0*/ message: kotlin.String?) /*primary*/ public constructor Throwable(/*0*/ message: kotlin.String?, /*1*/ cause: kotlin.Throwable?) public constructor Throwable(/*0*/ cause: kotlin.Throwable?) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BuiltInClassesAreSerializableOnJvm.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BuiltInClassesAreSerializableOnJvm.kt index 886ba8cdfa1..800487bbca2 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BuiltInClassesAreSerializableOnJvm.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/BuiltInClassesAreSerializableOnJvm.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.load.kotlin +import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl @@ -31,6 +32,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution +import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType @@ -43,6 +45,7 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.kotlin.utils.addToStdlib.check +import org.jetbrains.kotlin.utils.sure import java.io.Serializable import java.util.* @@ -50,6 +53,7 @@ open class BuiltInClassesAreSerializableOnJvm( private val moduleDescriptor: ModuleDescriptor, deferredOwnerModuleDescriptor: () -> ModuleDescriptor ) : AdditionalClassPartsProvider { + private val j2kClassMap = JavaToKotlinClassMap.INSTANCE private val ownerModuleDescriptor: ModuleDescriptor by lazy(deferredOwnerModuleDescriptor) @@ -106,25 +110,14 @@ open class BuiltInClassesAreSerializableOnJvm( classDescriptor: DeserializedClassDescriptor, functionsByScope: (MemberScope) -> Collection ): Collection { - // Prevents recursive dependency: memberScope(Any) -> memberScope(Object) -> memberScope(Any) - // No additional members should be added to Any - if (classDescriptor.isAny) return emptyList() - - val fqName = classDescriptor.fqNameUnsafe.check { it.isSafe }?.toSafe() ?: return emptyList() - - val j2kClassMap = JavaToKotlinClassMap.INSTANCE - val javaAnalogueFqName = j2kClassMap.mapKotlinToJava(fqName.toUnsafe())?.asSingleFqName() ?: return emptyList() - - if (javaAnalogueFqName in IGNORE_BY_DEFAULT_CLASS_FQ_NAMES) return emptyList() - - val javaAnalogueDescriptor = - ownerModuleDescriptor.resolveClassByFqName(javaAnalogueFqName, NoLookupLocation.FROM_BUILTINS) as? LazyJavaClassDescriptor - ?: return emptyList() + val javaAnalogueDescriptor = classDescriptor.getJavaAnalogue() ?: return emptyList() val platformClassDescriptors = j2kClassMap.mapPlatformClass(javaAnalogueDescriptor.fqNameSafe, DefaultBuiltIns.Instance) val kotlinMutableClassIfContainer = platformClassDescriptors.lastOrNull() ?: return emptyList() val platformVersions = SmartSet.create(platformClassDescriptors.map { it.fqNameSafe }) + if (javaAnalogueDescriptor.fqNameSafe in IGNORE_BY_DEFAULT_CLASS_FQ_NAMES) return emptyList() + val isMutable = j2kClassMap.isMutable(classDescriptor) val fakeJavaClassDescriptor = @@ -150,6 +143,52 @@ open class BuiltInClassesAreSerializableOnJvm( } } + private fun ClassDescriptor.getJavaAnalogue(): LazyJavaClassDescriptor? { + // Prevents recursive dependency: memberScope(Any) -> memberScope(Object) -> memberScope(Any) + // No additional members should be added to Any + if (isAny) return null + + val fqName = fqNameUnsafe.check { it.isSafe }?.toSafe() ?: return null + val javaAnalogueFqName = j2kClassMap.mapKotlinToJava(fqName.toUnsafe())?.asSingleFqName() ?: return null + + return ownerModuleDescriptor.resolveClassByFqName(javaAnalogueFqName, NoLookupLocation.FROM_BUILTINS) as? LazyJavaClassDescriptor + } + + override fun getConstructors(classDescriptor: DeserializedClassDescriptor): Collection { + if (classDescriptor.kind != ClassKind.CLASS) return emptyList() + + val javaAnalogueDescriptor = classDescriptor.getJavaAnalogue() ?: return emptyList() + + val defaultKotlinVersion = + j2kClassMap.mapJavaToKotlin(javaAnalogueDescriptor.fqNameSafe, DefaultBuiltIns.Instance) ?: return emptyList() + + val substitutor = createMappedTypeParametersSubstitution(defaultKotlinVersion, javaAnalogueDescriptor).buildSubstitutor() + + fun ConstructorDescriptor.isEffectivelyTheSameAs(javaConstructor: ConstructorDescriptor) = + OverridingUtil.getBothWaysOverridability(this, javaConstructor.substitute(substitutor)) == + OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE + + return javaAnalogueDescriptor.constructors.filter { + javaConstructor -> + javaConstructor.visibility.isPublicAPI && + defaultKotlinVersion.constructors.none { it.isEffectivelyTheSameAs(javaConstructor) } && + !javaConstructor.isTrivialCopyConstructorFor(classDescriptor) && + !KotlinBuiltIns.isDeprecated(javaConstructor) + }.map { + javaConstructor -> + javaConstructor.newCopyBuilder().apply { + setOwner(classDescriptor) + setReturnType(classDescriptor.defaultType) + setPreserveSourceElement() + setSubstitution(substitutor.substitution) + }.build() as ConstructorDescriptor + } + } + + private fun ConstructorDescriptor.isTrivialCopyConstructorFor(classDescriptor: DeserializedClassDescriptor): Boolean + = valueParameters.size == 1 && + valueParameters.single().type.constructor.declarationDescriptor?.fqNameUnsafe == classDescriptor.fqNameUnsafe + companion object { fun isSerializableInJava(classFqName: FqName): Boolean { val fqNameUnsafe = classFqName.toUnsafe() diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AdditionalClassPartsProvider.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AdditionalClassPartsProvider.kt index a843c53c561..ceb15d4506d 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AdditionalClassPartsProvider.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AdditionalClassPartsProvider.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.serialization.deserialization +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor @@ -24,11 +25,13 @@ import org.jetbrains.kotlin.types.KotlinType interface AdditionalClassPartsProvider { fun getSupertypes(classDescriptor: DeserializedClassDescriptor): Collection fun getFunctions(name: Name, classDescriptor: DeserializedClassDescriptor): Collection + fun getConstructors(classDescriptor: DeserializedClassDescriptor): Collection fun getFunctionsNames(classDescriptor: DeserializedClassDescriptor): Collection object None : AdditionalClassPartsProvider { override fun getSupertypes(classDescriptor: DeserializedClassDescriptor): Collection = emptyList() override fun getFunctions(name: Name, classDescriptor: DeserializedClassDescriptor): Collection = emptyList() override fun getFunctionsNames(classDescriptor: DeserializedClassDescriptor): Collection = emptyList() + override fun getConstructors(classDescriptor: DeserializedClassDescriptor): Collection = emptyList() } } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt index cfd18790a78..6ed255ea64f 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt @@ -116,7 +116,8 @@ class DeserializedClassDescriptor( override fun getUnsubstitutedPrimaryConstructor(): ConstructorDescriptor? = primaryConstructor() private fun computeConstructors(): Collection = - computeSecondaryConstructors() + getUnsubstitutedPrimaryConstructor().singletonOrEmptyList() + computeSecondaryConstructors() + unsubstitutedPrimaryConstructor.singletonOrEmptyList() + + c.components.additionalClassPartsProvider.getConstructors(this) private fun computeSecondaryConstructors(): List = classProto.constructorList.filter { Flags.IS_SECONDARY.get(it.flags) }.map {