Propagating annotations into type arguments
This commit is contained in:
committed by
Denis Zharkov
parent
4248654f5f
commit
9644eeb047
+5
-7
@@ -16,14 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.components
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
|
||||
fun <D : CallableMemberDescriptor> enhanceSignatures(platformSignatures: Collection<D>): Collection<D> {
|
||||
@@ -79,7 +77,7 @@ fun <D : CallableMemberDescriptor> D.enhance(): D {
|
||||
}
|
||||
|
||||
fun <T, P : SignaturePart<T>> SignatureParts<T, P>.enhance(): T {
|
||||
val qualifiers = fromOverride.type.computeQualifiersForOverride(this.fromOverridden.map { it.type }, fromOverride.isCovariant)
|
||||
val qualifiers = fromOverride.type.computeIndexedQualifiersForOverride(this.fromOverridden.map { it.type }, fromOverride.isCovariant)
|
||||
return fromOverride.replaceType(fromOverride.type.enhance(qualifiers))
|
||||
}
|
||||
|
||||
@@ -98,13 +96,13 @@ interface SignaturePart<out T> {
|
||||
}
|
||||
|
||||
fun ReceiverParameterDescriptor.toPart() = object : SignaturePart<JetType> {
|
||||
override val type = getType()
|
||||
override val type = this@toPart.getType() // workaround for KT-7557
|
||||
|
||||
override fun replaceType(newType: JetType) = newType
|
||||
}
|
||||
|
||||
fun ValueParameterDescriptor.toPart() = object : SignaturePart<ValueParameterDescriptor> {
|
||||
override val type = getType()
|
||||
override val type = this@toPart.getType() // workaround for KT-7557
|
||||
|
||||
override fun replaceType(newType: JetType) = ValueParameterDescriptorImpl(
|
||||
getContainingDeclaration(),
|
||||
@@ -114,7 +112,7 @@ fun ValueParameterDescriptor.toPart() = object : SignaturePart<ValueParameterDes
|
||||
getName(),
|
||||
newType,
|
||||
declaresDefaultValue(),
|
||||
if (getVarargElementType() != null) newType.getArguments()[0].getType() else null,
|
||||
if (getVarargElementType() != null) KotlinBuiltIns.getInstance().getArrayElementType(newType) else null,
|
||||
getSource()
|
||||
)
|
||||
}
|
||||
|
||||
+90
-39
@@ -24,55 +24,106 @@ import org.jetbrains.kotlin.load.java.components.NullabilityQualifier.NULLABLE
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
// The index in the lambda is the position of the type component:
|
||||
// Example: for `A<B, C<D, E>>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C<D, E>, 3 - D, 4 - E`,
|
||||
// which corresponds to the left-to-right breadth-first walk of the tree representation of the type.
|
||||
// For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`.
|
||||
fun JetType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = this.enhancePossiblyFlexible(qualifiers, 0).type
|
||||
|
||||
fun JetType.enhance(qualifiers: JavaTypeQualifiers): JetType {
|
||||
val mutabilityEnhanced =
|
||||
if (this.isFlexible())
|
||||
this.flexibility().enhanceMutability(qualifiers.mutability)
|
||||
else this
|
||||
return mutabilityEnhanced.enhanceNullability(qualifiers.nullability)
|
||||
|
||||
private enum class TypeComponentPosition {
|
||||
FLEXIBLE_LOWER,
|
||||
FLEXIBLE_UPPER,
|
||||
INFLEXIBLE
|
||||
}
|
||||
|
||||
private fun Flexibility.enhanceMutability(qualifier: MutabilityQualifier?): JetType {
|
||||
data class Result(val type: JetType, val subtreeSize: Int)
|
||||
|
||||
private fun JetType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result {
|
||||
if (this.isError()) return Result(this, 1)
|
||||
return if (this.isFlexible()) {
|
||||
with(this.flexibility()) {
|
||||
val lowerResult = lowerBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_LOWER)
|
||||
val upperResult = upperBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_UPPER)
|
||||
assert(lowerResult.subtreeSize == upperResult.subtreeSize) {
|
||||
"Different tree sizes of bounds: " +
|
||||
"lower = ($lowerBound, ${lowerResult.subtreeSize}), " +
|
||||
"upper = ($upperBound, ${upperResult.subtreeSize})"
|
||||
}
|
||||
Result(
|
||||
DelegatingFlexibleType.create(lowerResult.type, upperResult.type, extraCapabilities), lowerResult.subtreeSize
|
||||
)
|
||||
}
|
||||
}
|
||||
else this.enhanceInflexible(qualifiers, index, TypeComponentPosition.INFLEXIBLE)
|
||||
}
|
||||
|
||||
private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int, position: TypeComponentPosition): Result {
|
||||
val shouldEnhance = position.shouldEnhance()
|
||||
if (!shouldEnhance && getArguments().isEmpty()) return Result(this, 1)
|
||||
|
||||
val originalClass = getConstructor().getDeclarationDescriptor() as? ClassDescriptor
|
||||
?: return Result(this, 1)
|
||||
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val enhancedClass = originalClass.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
val enhancedArguments = getArguments().mapIndexed {
|
||||
localArgIndex, arg ->
|
||||
if (arg.isStarProjection()) {
|
||||
globalArgIndex++
|
||||
TypeUtils.makeStarProjection(enhancedClass.getTypeConstructor().getParameters()[localArgIndex])
|
||||
}
|
||||
else {
|
||||
val (enhancedType, subtreeSize) = arg.getType().enhancePossiblyFlexible(qualifiers, globalArgIndex)
|
||||
globalArgIndex += subtreeSize
|
||||
TypeProjectionImpl(
|
||||
arg.getProjectionKind(),
|
||||
enhancedType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val enhancedType = JetTypeImpl(
|
||||
getAnnotations(),
|
||||
enhancedClass.getTypeConstructor(),
|
||||
this.getEnhancedNullability(effectiveQualifiers, position),
|
||||
enhancedArguments,
|
||||
enhancedClass.getMemberScope(enhancedArguments)
|
||||
)
|
||||
return Result(enhancedType, globalArgIndex - index)
|
||||
}
|
||||
|
||||
private fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
|
||||
|
||||
private fun ClassDescriptor.enhanceMutability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): ClassDescriptor {
|
||||
if (!position.shouldEnhance()) return this
|
||||
|
||||
val mapping = JavaToKotlinClassMap.INSTANCE
|
||||
|
||||
val (newLower, newUpper) = run {
|
||||
when (qualifier) {
|
||||
READ_ONLY -> {
|
||||
val lowerClass = TypeUtils.getClassDescriptor(lowerBound)
|
||||
if (lowerClass != null && mapping.isMutable(lowerClass)) {
|
||||
return@run Pair(lowerBound.replaceClass(mapping.convertMutableToReadOnly(lowerClass)), upperBound)
|
||||
}
|
||||
}
|
||||
MUTABLE -> {
|
||||
val upperClass = TypeUtils.getClassDescriptor(upperBound)
|
||||
if (upperClass != null && mapping.isReadOnly(upperClass) ) {
|
||||
return@run Pair(lowerBound, upperBound.replaceClass(mapping.convertReadOnlyToMutable(upperClass)))
|
||||
}
|
||||
when (qualifiers.mutability) {
|
||||
READ_ONLY -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_LOWER && mapping.isMutable(this)) {
|
||||
return mapping.convertMutableToReadOnly(this)
|
||||
}
|
||||
}
|
||||
MUTABLE -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_UPPER && mapping.isReadOnly(this) ) {
|
||||
return mapping.convertReadOnlyToMutable(this)
|
||||
}
|
||||
}
|
||||
return@run Pair(lowerBound, upperBound)
|
||||
}
|
||||
|
||||
return DelegatingFlexibleType.create(newLower, newUpper, extraCapabilities)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun JetType.enhanceNullability(qualifier: NullabilityQualifier?): JetType {
|
||||
return when (qualifier) {
|
||||
NULLABLE -> TypeUtils.makeNullable(this)
|
||||
NOT_NULL -> TypeUtils.makeNotNullable(this)
|
||||
else -> this
|
||||
private fun JetType.getEnhancedNullability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): Boolean {
|
||||
if (!position.shouldEnhance()) return this.isMarkedNullable()
|
||||
|
||||
return when (qualifiers.nullability) {
|
||||
NULLABLE -> true
|
||||
NOT_NULL -> false
|
||||
else -> this.isMarkedNullable()
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetType.replaceClass(newClass: ClassDescriptor): JetType {
|
||||
assert(newClass.getTypeConstructor().getParameters().size() == getArguments().size(),
|
||||
{"Can't replace type constructor ${getConstructor()} by ${newClass}: type parameter count does not match"})
|
||||
return JetTypeImpl(
|
||||
getAnnotations(),
|
||||
newClass.getTypeConstructor(),
|
||||
isMarkedNullable(),
|
||||
getArguments(),
|
||||
newClass.getMemberScope(getArguments())
|
||||
)
|
||||
}
|
||||
+39
-2
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.java.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.components.MutabilityQualifier.MUTABLE
|
||||
@@ -27,6 +28,8 @@ import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.flexibility
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
import org.jetbrains.kotlin.utils.getOrDefault
|
||||
import java.util.ArrayList
|
||||
|
||||
enum class NullabilityQualifier {
|
||||
NULLABLE,
|
||||
@@ -57,7 +60,11 @@ val MUTABLE_ANNOTATIONS = listOf(
|
||||
class JavaTypeQualifiers(
|
||||
val nullability: NullabilityQualifier?,
|
||||
val mutability: MutabilityQualifier?
|
||||
)
|
||||
) {
|
||||
companion object {
|
||||
val NONE = JavaTypeQualifiers(null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetType.extractQualifiers(): JavaTypeQualifiers {
|
||||
val (lower, upper) =
|
||||
@@ -82,7 +89,37 @@ private fun Annotations.extractQualifiers(): JavaTypeQualifiers {
|
||||
)
|
||||
}
|
||||
|
||||
fun JetType.computeQualifiersForOverride(fromSupertypes: Collection<JetType>, isCovariant: Boolean): JavaTypeQualifiers {
|
||||
fun JetType.computeIndexedQualifiersForOverride(fromSupertypes: Collection<JetType>, isCovariant: Boolean): (Int) -> JavaTypeQualifiers {
|
||||
fun JetType.toIndexed(): List<JetType> {
|
||||
val list = ArrayList<JetType>(1)
|
||||
|
||||
fun add(type: JetType) {
|
||||
list.add(type)
|
||||
for (arg in type.getArguments()) {
|
||||
if (arg.isStarProjection()) {
|
||||
list.add(arg.getType())
|
||||
}
|
||||
else {
|
||||
add(arg.getType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add(this)
|
||||
return list
|
||||
}
|
||||
|
||||
val indexedFromSupertypes = fromSupertypes.map { it.toIndexed() }
|
||||
val indexedThisType = this.toIndexed()
|
||||
|
||||
return _r@ fun(index: Int): JavaTypeQualifiers {
|
||||
val qualifiers = indexedThisType.getOrDefault(index, { return JavaTypeQualifiers.NONE })
|
||||
val verticalSlice = indexedFromSupertypes.map { it.getOrDefault(index, { null }) }.filterNotNull()
|
||||
return qualifiers.computeQualifiersForOverride(verticalSlice, isCovariant)
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetType.computeQualifiersForOverride(fromSupertypes: Collection<JetType>, isCovariant: Boolean): JavaTypeQualifiers {
|
||||
val nullabilityFromSupertypes = fromSupertypes.map { it.extractQualifiers().nullability }.filterNotNull().toSet()
|
||||
val mutabilityFromSupertypes = fromSupertypes.map { it.extractQualifiers().mutability }.filterNotNull().toSet()
|
||||
val own = getAnnotations().extractQualifiers()
|
||||
|
||||
Reference in New Issue
Block a user