Drop Cloneable in JS, synthesize it at compile-time on JVM

Use the same approach that is used for creating function type classes
(Function{0,1,...}) + add Cloneable to supertypes of Array and primitive arrays

 #KT-5537 Fixed
This commit is contained in:
Alexander Udalov
2016-10-13 11:53:18 +03:00
parent 0f4b10d37d
commit 035d6156a7
24 changed files with 376 additions and 173 deletions
+1 -6
View File
@@ -23,7 +23,7 @@ package kotlin
* See [Kotlin language documentation](http://kotlinlang.org/docs/reference/basic-types.html#arrays)
* for more information on arrays.
*/
public class Array<T> : Cloneable {
public class Array<T> {
/**
* Creates a new array with the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -57,9 +57,4 @@ public class Array<T> : Cloneable {
* Creates an iterator for iterating over the elements of the array.
*/
public operator fun iterator(): Iterator<T>
/**
* Creates a shallow copy of the array.
*/
public override fun clone(): Array<T>
}
+8 -24
View File
@@ -22,7 +22,7 @@ package kotlin
* An array of bytes. When targeting the JVM, instances of this class are represented as `byte[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
*/
public class ByteArray(size: Int) : Cloneable {
public class ByteArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -39,15 +39,13 @@ public class ByteArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): ByteIterator
public override fun clone(): ByteArray
}
/**
* An array of chars. When targeting the JVM, instances of this class are represented as `char[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
*/
public class CharArray(size: Int) : Cloneable {
public class CharArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -64,15 +62,13 @@ public class CharArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): CharIterator
public override fun clone(): CharArray
}
/**
* An array of shorts. When targeting the JVM, instances of this class are represented as `short[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
*/
public class ShortArray(size: Int) : Cloneable {
public class ShortArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -89,15 +85,13 @@ public class ShortArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): ShortIterator
public override fun clone(): ShortArray
}
/**
* An array of ints. When targeting the JVM, instances of this class are represented as `int[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
*/
public class IntArray(size: Int) : Cloneable {
public class IntArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -114,15 +108,13 @@ public class IntArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): IntIterator
public override fun clone(): IntArray
}
/**
* An array of longs. When targeting the JVM, instances of this class are represented as `long[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
*/
public class LongArray(size: Int) : Cloneable {
public class LongArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -139,15 +131,13 @@ public class LongArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): LongIterator
public override fun clone(): LongArray
}
/**
* An array of floats. When targeting the JVM, instances of this class are represented as `float[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
*/
public class FloatArray(size: Int) : Cloneable {
public class FloatArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -164,15 +154,13 @@ public class FloatArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): FloatIterator
public override fun clone(): FloatArray
}
/**
* An array of doubles. When targeting the JVM, instances of this class are represented as `double[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
*/
public class DoubleArray(size: Int) : Cloneable {
public class DoubleArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -189,15 +177,13 @@ public class DoubleArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): DoubleIterator
public override fun clone(): DoubleArray
}
/**
* An array of booleans. When targeting the JVM, instances of this class are represented as `boolean[]`.
* @constructor Creates a new array of the specified [size], with all elements initialized to false.
*/
public class BooleanArray(size: Int) : Cloneable {
public class BooleanArray(size: Int) {
/**
* Creates a new array of the specified [size], where each element is calculated by calling the specified
* [init] function. The [init] function returns an array element given its index.
@@ -214,7 +200,5 @@ public class BooleanArray(size: Int) : Cloneable {
/** Creates an iterator over the elements of the array. */
public operator fun iterator(): BooleanIterator
public override fun clone(): BooleanArray
}
-27
View File
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin
/**
* Classes that inherit from this interface support creating field-by-field copies of their instances.
*/
public interface Cloneable {
/**
* Creates and returns a field-by-field copy of this object.
*/
protected fun clone(): Any { /* intrinsic */ }
}
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.builtins
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.Printer
import java.util.*
class CloneableClassScope(storageManager: StorageManager, private val classDescriptor: ClassDescriptor) : MemberScopeImpl() {
private val allDescriptors by storageManager.createLazyValue {
val cloneFunction =
SimpleFunctionDescriptorImpl.create(classDescriptor, Annotations.EMPTY, CLONE_NAME, DECLARATION, SourceElement.NO_SOURCE)
cloneFunction.initialize(null, classDescriptor.thisAsReceiverParameter, emptyList(), emptyList(), classDescriptor.builtIns.anyType,
Modality.OPEN, Visibilities.PROTECTED)
listOf(cloneFunction) + createFakeOverrides()
}
private val functionNames = setOf(CLONE_NAME) + classDescriptor.builtIns.anyType.memberScope.getFunctionNames()
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> =
if (name in functionNames) allDescriptors.filter { it.name == name } else emptySet()
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> = allDescriptors
override fun getFunctionNames(): Set<Name> = functionNames
private fun createFakeOverrides(): List<SimpleFunctionDescriptor> {
val result = ArrayList<SimpleFunctionDescriptor>(3)
val allSuperDescriptors = classDescriptor.typeConstructor.supertypes
.flatMap { it.memberScope.getContributedDescriptors() }
.filterIsInstance<SimpleFunctionDescriptor>()
for ((name, descriptors) in allSuperDescriptors.groupBy { it.name }) {
OverridingUtil.generateOverridesInFunctionGroup(
name,
/* membersFromSupertypes = */ descriptors,
/* membersFromCurrent = */ emptyList(),
classDescriptor,
object : NonReportingOverrideStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, null)
result.add(fakeOverride as SimpleFunctionDescriptor)
}
override fun conflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
error("Conflict in scope of $classDescriptor: $fromSuper vs $fromCurrent")
}
}
)
}
return result
}
override fun printScopeStructure(p: Printer) {
p.println("kotlin.Cloneable member scope")
}
companion object {
internal val CLONE_NAME = Name.identifier("clone")
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.builtins
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.ClassDescriptorFactory
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
class JvmBuiltInClassDescriptorFactory(
storageManager: StorageManager,
private val moduleDescriptor: ModuleDescriptor
) : ClassDescriptorFactory {
private val cloneable by storageManager.createLazyValue {
ClassDescriptorImpl(
moduleDescriptor.getPackage(KOTLIN_FQ_NAME).fragments.single(),
CLONEABLE_NAME, Modality.ABSTRACT, ClassKind.INTERFACE, listOf(moduleDescriptor.builtIns.anyType),
SourceElement.NO_SOURCE
).apply {
initialize(CloneableClassScope(storageManager, this), emptySet(), null)
}
}
override fun shouldCreateClass(packageFqName: FqName, name: Name): Boolean =
name == CLONEABLE_NAME && packageFqName == KOTLIN_FQ_NAME
override fun createClass(classId: ClassId): ClassDescriptor? =
when (classId) {
CLONEABLE_CLASS_ID -> cloneable
else -> null
}
override fun getAllContributedClassesIfPossible(packageFqName: FqName): Collection<ClassDescriptor> =
when (packageFqName) {
KOTLIN_FQ_NAME -> setOf(cloneable)
else -> emptySet()
}
companion object {
private val KOTLIN_FQ_NAME = KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME
private val CLONEABLE_NAME = KotlinBuiltIns.FQ_NAMES.cloneable.shortName()
val CLONEABLE_CLASS_ID = ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.cloneable.toSafe())
}
}
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.builtins.BuiltInsInitializer
import org.jetbrains.kotlin.builtins.CloneableClassScope
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
@@ -28,6 +30,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.components.JavaResolverCache
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution
@@ -65,6 +68,9 @@ open class JvmBuiltInsSettings(
private val isAdditionalBuiltInsFeatureSupported: Boolean by lazy(isAdditionalBuiltInsFeatureSupported)
private val mockSerializableType = storageManager.createMockJavaIoSerializableType()
private val cloneableType by storageManager.createLazyValue {
moduleDescriptor.builtIns.getBuiltInClassByName(JvmBuiltInClassDescriptorFactory.CLONEABLE_CLASS_ID.shortClassName).defaultType
}
private val javaAnalogueClassesWithCustomSupertypeCache = storageManager.createCacheWithNotNullValues<FqName, ClassDescriptor>()
@@ -114,58 +120,66 @@ open class JvmBuiltInsSettings(
}
override fun getSupertypes(classDescriptor: DeserializedClassDescriptor): Collection<KotlinType> {
if (isSerializableInJava(classDescriptor.fqNameSafe)) {
return listOf(mockSerializableType)
val fqName = classDescriptor.fqNameUnsafe
return when {
isArrayOrPrimitiveArray(fqName) -> listOf(cloneableType, mockSerializableType)
isSerializableInJava(fqName) -> listOf(mockSerializableType)
else -> listOf()
}
else return listOf()
}
override fun getFunctions(name: Name, classDescriptor: DeserializedClassDescriptor): Collection<SimpleFunctionDescriptor> =
getAdditionalFunctions(classDescriptor) {
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
}
.mapNotNull {
additionalMember ->
val substitutedWithKotlinTypeParameters =
additionalMember.substitute(
createMappedTypeParametersSubstitution(
additionalMember.containingDeclaration as ClassDescriptor, classDescriptor).buildSubstitutor()
) as SimpleFunctionDescriptor
override fun getFunctions(name: Name, classDescriptor: DeserializedClassDescriptor): Collection<SimpleFunctionDescriptor> {
if (name == CloneableClassScope.CLONE_NAME && KotlinBuiltIns.isArrayOrPrimitiveArray(classDescriptor)) {
return listOf(createCloneForArray(
classDescriptor, cloneableType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
))
}
substitutedWithKotlinTypeParameters.newCopyBuilder().apply {
setOwner(classDescriptor)
setDispatchReceiverParameter(classDescriptor.thisAsReceiverParameter)
setPreserveSourceElement()
setSubstitution(UnsafeVarianceTypeSubstitution(moduleDescriptor.builtIns))
return getAdditionalFunctions(classDescriptor) {
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
}.mapNotNull {
additionalMember ->
val substitutedWithKotlinTypeParameters =
additionalMember.substitute(
createMappedTypeParametersSubstitution(
additionalMember.containingDeclaration as ClassDescriptor, classDescriptor).buildSubstitutor()
) as SimpleFunctionDescriptor
val memberStatus = additionalMember.getJdkMethodStatus()
when (memberStatus) {
JDKMemberStatus.BLACK_LIST -> {
// Black list methods in final class can't be overridden or called with 'super'
if (classDescriptor.isFinalClass) return@mapNotNull null
setHiddenForResolutionEverywhereBesideSupercalls()
substitutedWithKotlinTypeParameters.newCopyBuilder().apply {
setOwner(classDescriptor)
setDispatchReceiverParameter(classDescriptor.thisAsReceiverParameter)
setPreserveSourceElement()
setSubstitution(UnsafeVarianceTypeSubstitution(moduleDescriptor.builtIns))
val memberStatus = additionalMember.getJdkMethodStatus()
when (memberStatus) {
JDKMemberStatus.BLACK_LIST -> {
// Black list methods in final class can't be overridden or called with 'super'
if (classDescriptor.isFinalClass) return@mapNotNull null
setHiddenForResolutionEverywhereBesideSupercalls()
}
JDKMemberStatus.NOT_CONSIDERED -> {
if (!isAdditionalBuiltInsFeatureSupported) {
setAdditionalAnnotations(notSupportedDeprecation)
}
JDKMemberStatus.NOT_CONSIDERED -> {
if (!isAdditionalBuiltInsFeatureSupported) {
setAdditionalAnnotations(notSupportedDeprecation)
}
else {
setAdditionalAnnotations(notConsideredDeprecation)
}
}
JDKMemberStatus.DROP -> return@mapNotNull null
JDKMemberStatus.WHITE_LIST -> {
if (!isAdditionalBuiltInsFeatureSupported) {
setAdditionalAnnotations(notSupportedDeprecation)
}
else {
setAdditionalAnnotations(notConsideredDeprecation)
}
}
}.build()!!
}
JDKMemberStatus.DROP -> return@mapNotNull null
JDKMemberStatus.WHITE_LIST -> {
if (!isAdditionalBuiltInsFeatureSupported) {
setAdditionalAnnotations(notSupportedDeprecation)
}
}
}
}.build()!!
}
}
override fun getFunctionsNames(classDescriptor: DeserializedClassDescriptor): Set<Name> =
// NB: It's just an approximation that could be calculated relatively fast
@@ -206,6 +220,15 @@ open class JvmBuiltInsSettings(
}
}
private fun createCloneForArray(
arrayClassDescriptor: DeserializedClassDescriptor,
cloneFromCloneable: SimpleFunctionDescriptor
): SimpleFunctionDescriptor = cloneFromCloneable.newCopyBuilder().apply {
setOwner(arrayClassDescriptor)
setVisibility(Visibilities.PUBLIC)
setReturnType(arrayClassDescriptor.defaultType)
}.build()!!
private fun SimpleFunctionDescriptor.isMutabilityViolation(isMutable: Boolean): Boolean {
val owner = containingDeclaration as ClassDescriptor
val jvmDescriptor = computeJvmDescriptor()
@@ -323,12 +346,11 @@ open class JvmBuiltInsSettings(
valueParameters.single().type.constructor.declarationDescriptor?.fqNameUnsafe == classDescriptor.fqNameUnsafe
companion object {
fun isSerializableInJava(classFqName: FqName): Boolean {
val fqNameUnsafe = classFqName.toUnsafe()
if (fqNameUnsafe == KotlinBuiltIns.FQ_NAMES.array || KotlinBuiltIns.isPrimitiveArray(fqNameUnsafe)) {
fun isSerializableInJava(fqName: FqNameUnsafe): Boolean {
if (isArrayOrPrimitiveArray(fqName)) {
return true
}
val javaClassId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqNameUnsafe) ?: return false
val javaClassId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName) ?: return false
val classViaReflection = try {
Class.forName(javaClassId.asSingleFqName().asString())
}
@@ -338,6 +360,10 @@ open class JvmBuiltInsSettings(
return Serializable::class.java.isAssignableFrom(classViaReflection)
}
private fun isArrayOrPrimitiveArray(fqName: FqNameUnsafe): Boolean {
return fqName == KotlinBuiltIns.FQ_NAMES.array || KotlinBuiltIns.isPrimitiveArray(fqName)
}
val DROP_LIST_METHOD_SIGNATURES: Set<String> =
SignatureBuildingComponents.inJavaUtil(
"Collection",
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.platform
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.load.kotlin.JvmBuiltInsSettings
@@ -49,4 +50,7 @@ class JvmBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManage
}
override fun getAdditionalClassPartsProvider() = settings
override fun getClassDescriptorFactories() =
super.getClassDescriptorFactories() + JvmBuiltInClassDescriptorFactory(storageManager, builtInsModule)
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.serialization.deserialization.AdditionalClassPartsProvider;
import org.jetbrains.kotlin.serialization.deserialization.ClassDescriptorFactory;
import org.jetbrains.kotlin.serialization.deserialization.PlatformDependentDeclarationFilter;
import org.jetbrains.kotlin.storage.StorageManager;
import org.jetbrains.kotlin.types.*;
@@ -86,7 +87,7 @@ public abstract class KotlinBuiltIns {
PackageFragmentProvider packageFragmentProvider = BuiltInsPackageFragmentProviderKt.createBuiltInPackageFragmentProvider(
storageManager, builtInsModule, BUILT_INS_PACKAGE_FQ_NAMES,
Collections.singletonList(new BuiltInFictitiousFunctionClassFactory(storageManager, builtInsModule)),
getClassDescriptorFactories(),
getPlatformDependentDeclarationFilter(),
getAdditionalClassPartsProvider(),
new Function1<String, InputStream>() {
@@ -129,6 +130,11 @@ public abstract class KotlinBuiltIns {
return PlatformDependentDeclarationFilter.NoPlatformDependent.INSTANCE;
}
@NotNull
protected Iterable<ClassDescriptorFactory> getClassDescriptorFactories() {
return Collections.<ClassDescriptorFactory>singletonList(new BuiltInFictitiousFunctionClassFactory(storageManager, builtInsModule));
}
private void makePrimitive(@NotNull PrimitiveType primitiveType) {
SimpleType type = getBuiltInTypeByClassName(primitiveType.getTypeName().asString());
SimpleType arrayType = getBuiltInTypeByClassName(primitiveType.getArrayTypeName().asString());
@@ -443,11 +449,6 @@ public abstract class KotlinBuiltIns {
return getBuiltInClassByName("Throwable");
}
@NotNull
public ClassDescriptor getCloneable() {
return getBuiltInClassByName("Cloneable");
}
@NotNull
public ClassDescriptor getDeprecatedAnnotation() {
return getBuiltInClassByName(FQ_NAMES.deprecated.shortName());