Use TypeConstructor equality instead of ClassDescriptor in CollectionStubMethodGenerator
Equals/hashCode are meaningful for TypeConstructor instances (see AbstractClassTypeConstructor.java) in contrast to ClassDescriptor where equality is referential
This commit is contained in:
+29
-29
@@ -93,7 +93,7 @@ class CollectionStubMethodGenerator(
|
|||||||
// to construct the needed MutableCollection type. Since getAllSupertypes() may return several types which correspond to the
|
// to construct the needed MutableCollection type. Since getAllSupertypes() may return several types which correspond to the
|
||||||
// Collection class descriptor, we find the most specific one (which is guaranteed to exist by front-end)
|
// Collection class descriptor, we find the most specific one (which is guaranteed to exist by front-end)
|
||||||
val readOnlyCollectionType = TypeUtils.getAllSupertypes(parentType).findMostSpecificTypeForClass(readOnlyClass)
|
val readOnlyCollectionType = TypeUtils.getAllSupertypes(parentType).findMostSpecificTypeForClass(readOnlyClass)
|
||||||
val mutableCollectionType = newType(mutableClass, readOnlyCollectionType.arguments)
|
val mutableCollectionType = newType(mutableClass.declarationDescriptor as ClassDescriptor, readOnlyCollectionType.arguments)
|
||||||
|
|
||||||
child.addSupertype(parentType)
|
child.addSupertype(parentType)
|
||||||
child.addSupertype(mutableCollectionType)
|
child.addSupertype(mutableCollectionType)
|
||||||
@@ -105,7 +105,7 @@ class CollectionStubMethodGenerator(
|
|||||||
if (method.modality == Modality.ABSTRACT || isDefaultInJdk(method)) {
|
if (method.modality == Modality.ABSTRACT || isDefaultInJdk(method)) {
|
||||||
// If the fake override is abstract and it's _declared_ as abstract in the class, skip it because the method is already
|
// If the fake override is abstract and it's _declared_ as abstract in the class, skip it because the method is already
|
||||||
// present in the bytecode (abstract) and we don't want a duplicate signature error
|
// present in the bytecode (abstract) and we don't want a duplicate signature error
|
||||||
if (method.findOverriddenFromDirectSuperClass(descriptor)?.kind == DECLARATION) continue
|
if (method.findOverriddenFromDirectSuperClass(descriptor.typeConstructor)?.kind == DECLARATION) continue
|
||||||
|
|
||||||
// If the substituted signature differs from the original one in MutableCollection, we should also generate a stub with
|
// If the substituted signature differs from the original one in MutableCollection, we should also generate a stub with
|
||||||
// the original (erased) signature. It doesn't really matter if this is a bridge method delegating to the first stub or
|
// the original (erased) signature. It doesn't really matter if this is a bridge method delegating to the first stub or
|
||||||
@@ -195,53 +195,52 @@ class CollectionStubMethodGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private data class CollectionClassPair(
|
private data class CollectionClassPair(
|
||||||
val readOnlyClass: ClassDescriptor,
|
val readOnlyClass: TypeConstructor,
|
||||||
val mutableClass: ClassDescriptor
|
val mutableClass: TypeConstructor
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun findRelevantSuperCollectionClasses(): Collection<CollectionClassPair> {
|
private fun findRelevantSuperCollectionClasses(): Collection<CollectionClassPair> {
|
||||||
fun pair(readOnlyClass: ClassDescriptor, mutableClass: ClassDescriptor) = CollectionClassPair(readOnlyClass, mutableClass)
|
fun pair(readOnlyClass: TypeConstructor, mutableClass: TypeConstructor) = CollectionClassPair(readOnlyClass, mutableClass)
|
||||||
|
|
||||||
val collectionClasses = with(descriptor.builtIns) {
|
val collectionClasses = with(descriptor.builtIns) {
|
||||||
listOf(
|
listOf(
|
||||||
pair(collection, mutableCollection),
|
collection to mutableCollection,
|
||||||
pair(set, mutableSet),
|
set to mutableSet,
|
||||||
pair(list, mutableList),
|
list to mutableList,
|
||||||
pair(map, mutableMap),
|
map to mutableMap,
|
||||||
pair(mapEntry, mutableMapEntry),
|
mapEntry to mutableMapEntry,
|
||||||
pair(iterable, mutableIterable),
|
iterable to mutableIterable,
|
||||||
pair(iterator, mutableIterator),
|
iterator to mutableIterator,
|
||||||
pair(listIterator, mutableListIterator)
|
listIterator to mutableListIterator
|
||||||
)
|
).map { (readOnly, mutable) ->
|
||||||
|
pair(readOnly.typeConstructor, mutable.typeConstructor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val allSuperClasses = TypeUtils.getAllSupertypes(descriptor.defaultType).classes().toHashSet()
|
val allSuperClasses = TypeUtils.getAllSupertypes(descriptor.defaultType).mapTo(HashSet(), KotlinType::constructor)
|
||||||
|
|
||||||
val ourSuperCollectionClasses = collectionClasses.filter { (readOnlyClass, mutableClass) ->
|
val ourSuperCollectionClasses = collectionClasses.filter { (readOnlyClass, mutableClass) ->
|
||||||
readOnlyClass in allSuperClasses && mutableClass !in allSuperClasses
|
readOnlyClass in allSuperClasses && mutableClass !in allSuperClasses
|
||||||
}
|
}
|
||||||
if (ourSuperCollectionClasses.isEmpty()) return listOf()
|
if (ourSuperCollectionClasses.isEmpty()) return emptySet()
|
||||||
|
|
||||||
// Filter out built-in classes which are overridden by other built-in classes in the list, to avoid duplicating methods.
|
// Filter out built-in classes which are overridden by other built-in classes in the list, to avoid duplicating methods.
|
||||||
val redundantClasses = ourSuperCollectionClasses.flatMapTo(HashSet<ClassDescriptor>()) { (readOnlyClass) ->
|
val redundantClasses = ourSuperCollectionClasses.flatMapTo(HashSet()) { (readOnlyClass) ->
|
||||||
readOnlyClass.typeConstructor.supertypes.classes()
|
readOnlyClass.supertypes.map(KotlinType::constructor)
|
||||||
}
|
}
|
||||||
return ourSuperCollectionClasses.filter { (readOnlyClass) -> readOnlyClass !in redundantClasses }
|
return ourSuperCollectionClasses.filter { (readOnlyClass) -> readOnlyClass !in redundantClasses }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Collection<KotlinType>.classes(): Collection<ClassDescriptor> =
|
|
||||||
this.map { it.constructor.declarationDescriptor as ClassDescriptor }
|
|
||||||
|
|
||||||
private fun findFakeOverridesForMethodsFromMutableCollection(
|
private fun findFakeOverridesForMethodsFromMutableCollection(
|
||||||
klass: ClassDescriptor,
|
klass: ClassDescriptor,
|
||||||
mutableCollectionClass: ClassDescriptor
|
mutableCollectionTypeConstructor: TypeConstructor
|
||||||
): List<FunctionDescriptor> {
|
): List<FunctionDescriptor> {
|
||||||
val result = ArrayList<FunctionDescriptor>()
|
val result = ArrayList<FunctionDescriptor>()
|
||||||
|
|
||||||
generateOverridesInAClass(klass, object : NonReportingOverrideStrategy() {
|
generateOverridesInAClass(klass, object : NonReportingOverrideStrategy() {
|
||||||
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
|
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
|
||||||
if (fakeOverride !is FunctionDescriptor) return
|
if (fakeOverride !is FunctionDescriptor) return
|
||||||
val foundOverriddenFromDirectSuperClass = fakeOverride.findOverriddenFromDirectSuperClass(mutableCollectionClass) ?: return
|
val foundOverriddenFromDirectSuperClass = fakeOverride.findOverriddenFromDirectSuperClass(mutableCollectionTypeConstructor) ?: return
|
||||||
if (foundOverriddenFromDirectSuperClass.kind == DECLARATION) {
|
if (foundOverriddenFromDirectSuperClass.kind == DECLARATION) {
|
||||||
// For regular classes there should no be fake overrides having return types incompatible with return types of their
|
// For regular classes there should no be fake overrides having return types incompatible with return types of their
|
||||||
// overridden, while here it's possible to create declaration like `fun remove(e: E): ImmutableCollection<E>`
|
// overridden, while here it's possible to create declaration like `fun remove(e: E): ImmutableCollection<E>`
|
||||||
@@ -284,9 +283,9 @@ class CollectionStubMethodGenerator(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Collection<KotlinType>.findMostSpecificTypeForClass(klass: ClassDescriptor): KotlinType {
|
private fun Collection<KotlinType>.findMostSpecificTypeForClass(typeConstructor: TypeConstructor): KotlinType {
|
||||||
val types = this.filter { it.constructor.declarationDescriptor == klass }
|
val types = this.filter { it.constructor == typeConstructor }
|
||||||
if (types.isEmpty()) error("No supertype of $klass in $this")
|
if (types.isEmpty()) error("No supertype of $typeConstructor in $this")
|
||||||
if (types.size == 1) return types.first()
|
if (types.size == 1) return types.first()
|
||||||
// Find the first type in the list such that it's a subtype of every other type in that list
|
// Find the first type in the list such that it's a subtype of every other type in that list
|
||||||
return types.first { type ->
|
return types.first { type ->
|
||||||
@@ -320,9 +319,10 @@ class CollectionStubMethodGenerator(
|
|||||||
return Pair(child, newTypeParameters)
|
return Pair(child, newTypeParameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FunctionDescriptor.findOverriddenFromDirectSuperClass(classDescriptor: ClassDescriptor): FunctionDescriptor? {
|
private fun FunctionDescriptor.findOverriddenFromDirectSuperClass(typeConstructor: TypeConstructor): FunctionDescriptor? =
|
||||||
return this.overriddenDescriptors.firstOrNull { it.containingDeclaration == classDescriptor }
|
this.overriddenDescriptors.firstOrNull {
|
||||||
}
|
(it.containingDeclaration as? ClassDescriptor)?.typeConstructor == typeConstructor
|
||||||
|
}
|
||||||
|
|
||||||
private fun newType(classDescriptor: ClassDescriptor, typeArguments: List<TypeProjection>): KotlinType {
|
private fun newType(classDescriptor: ClassDescriptor, typeArguments: List<TypeProjection>): KotlinType {
|
||||||
return KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, classDescriptor, typeArguments)
|
return KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, classDescriptor, typeArguments)
|
||||||
|
|||||||
Reference in New Issue
Block a user