Propagating annotations into type arguments

This commit is contained in:
Andrey Breslav
2015-04-23 16:24:32 +03:00
committed by Denis Zharkov
parent 4248654f5f
commit 9644eeb047
4 changed files with 136 additions and 48 deletions
@@ -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()
)
}
@@ -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())
)
}
@@ -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()