Introduce JavaTypeEnhancement component
It's necessary to allow using language version settings in type enancement
This commit is contained in:
+11
-6
@@ -18,7 +18,10 @@ package org.jetbrains.kotlin.load.java.typeEnhancement
|
||||
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
@@ -31,7 +34,6 @@ import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DEPRECATED_FUNCTION_KEY
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isSourceAnnotation
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
@@ -46,7 +48,8 @@ data class NullabilityQualifierWithMigrationStatus(
|
||||
|
||||
class SignatureEnhancement(
|
||||
private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver,
|
||||
private val jsr305State: Jsr305State
|
||||
private val jsr305State: Jsr305State,
|
||||
private val typeEnhancement: JavaTypeEnhancement
|
||||
) {
|
||||
|
||||
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
|
||||
@@ -241,9 +244,11 @@ class SignatureEnhancement(
|
||||
classifier.fqNameOrNull() == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME
|
||||
}
|
||||
|
||||
return fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let { enhanced ->
|
||||
PartEnhancementResult(enhanced, wereChanges = true, containsFunctionN = containsFunctionN)
|
||||
} ?: PartEnhancementResult(fromOverride, wereChanges = false, containsFunctionN = containsFunctionN)
|
||||
return with(typeEnhancement) {
|
||||
fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let { enhanced ->
|
||||
PartEnhancementResult(enhanced, wereChanges = true, containsFunctionN = containsFunctionN)
|
||||
} ?: PartEnhancementResult(fromOverride, wereChanges = false, containsFunctionN = containsFunctionN)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.extractQualifiers(): JavaTypeQualifiers {
|
||||
|
||||
+88
-85
@@ -39,12 +39,6 @@ import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
|
||||
// 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 KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhancePossiblyFlexible(qualifiers, 0).typeIfChanged
|
||||
|
||||
fun KotlinType.hasEnhancedNullability(): Boolean =
|
||||
SimpleClassicTypeSystemContext.hasEnhancedNullability(this)
|
||||
|
||||
@@ -57,96 +51,105 @@ enum class TypeComponentPosition {
|
||||
INFLEXIBLE
|
||||
}
|
||||
|
||||
private open class Result(open val type: KotlinType, val subtreeSize: Int, val wereChanges: Boolean) {
|
||||
val typeIfChanged: KotlinType? get() = type.takeIf { wereChanges }
|
||||
}
|
||||
class JavaTypeEnhancement {
|
||||
|
||||
private class SimpleResult(override val type: SimpleType, subtreeSize: Int, wereChanges: Boolean) : Result(type, subtreeSize, wereChanges)
|
||||
private open class Result(open val type: KotlinType, val subtreeSize: Int, val wereChanges: Boolean) {
|
||||
val typeIfChanged: KotlinType? get() = type.takeIf { wereChanges }
|
||||
}
|
||||
|
||||
private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result {
|
||||
if (isError) return Result(this, 1, false)
|
||||
return when (this) {
|
||||
is FlexibleType -> {
|
||||
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})"
|
||||
private class SimpleResult(override val type: SimpleType, subtreeSize: Int, wereChanges: Boolean) : Result(type, subtreeSize, wereChanges)
|
||||
|
||||
// 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 KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhancePossiblyFlexible(qualifiers, 0).typeIfChanged
|
||||
|
||||
private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result {
|
||||
if (isError) return Result(this, 1, false)
|
||||
return when (this) {
|
||||
is FlexibleType -> {
|
||||
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})"
|
||||
}
|
||||
|
||||
val wereChanges = lowerResult.wereChanges || upperResult.wereChanges
|
||||
val enhancement = lowerResult.type.getEnhancement() ?: upperResult.type.getEnhancement()
|
||||
val type = if (!wereChanges) this@enhancePossiblyFlexible
|
||||
else when {
|
||||
this is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type)
|
||||
else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type)
|
||||
}.wrapEnhancement(enhancement)
|
||||
|
||||
Result(
|
||||
type,
|
||||
lowerResult.subtreeSize,
|
||||
wereChanges
|
||||
)
|
||||
}
|
||||
|
||||
val wereChanges = lowerResult.wereChanges || upperResult.wereChanges
|
||||
val enhancement = lowerResult.type.getEnhancement() ?: upperResult.type.getEnhancement()
|
||||
val type = if (!wereChanges) this@enhancePossiblyFlexible
|
||||
else when {
|
||||
this is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type)
|
||||
else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type)
|
||||
}.wrapEnhancement(enhancement)
|
||||
|
||||
Result(
|
||||
type,
|
||||
lowerResult.subtreeSize,
|
||||
wereChanges
|
||||
)
|
||||
}
|
||||
is SimpleType -> enhanceInflexible(qualifiers, index, TypeComponentPosition.INFLEXIBLE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleType.enhanceInflexible(
|
||||
qualifiers: (Int) -> JavaTypeQualifiers,
|
||||
index: Int,
|
||||
position: TypeComponentPosition
|
||||
): SimpleResult {
|
||||
val shouldEnhance = position.shouldEnhance()
|
||||
if (!shouldEnhance && arguments.isEmpty()) return SimpleResult(this, 1, false)
|
||||
|
||||
val originalClass = constructor.declarationDescriptor
|
||||
?: return SimpleResult(this, 1, false)
|
||||
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
val typeConstructor = enhancedClassifier.typeConstructor
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
var wereChanges = enhancedMutabilityAnnotations != null
|
||||
val enhancedArguments = arguments.mapIndexed { localArgIndex, arg ->
|
||||
if (arg.isStarProjection) {
|
||||
globalArgIndex++
|
||||
TypeUtils.makeStarProjection(enhancedClassifier.typeConstructor.parameters[localArgIndex])
|
||||
} else {
|
||||
val enhanced = arg.type.unwrap().enhancePossiblyFlexible(qualifiers, globalArgIndex)
|
||||
wereChanges = wereChanges || enhanced.wereChanges
|
||||
globalArgIndex += enhanced.subtreeSize
|
||||
createProjection(enhanced.type, arg.projectionKind, typeParameterDescriptor = typeConstructor.parameters[localArgIndex])
|
||||
is SimpleType -> enhanceInflexible(qualifiers, index, TypeComponentPosition.INFLEXIBLE)
|
||||
}
|
||||
}
|
||||
|
||||
val (enhancedNullability, enhancedNullabilityAnnotations) = this.getEnhancedNullability(effectiveQualifiers, position)
|
||||
wereChanges = wereChanges || enhancedNullabilityAnnotations != null
|
||||
private fun SimpleType.enhanceInflexible(
|
||||
qualifiers: (Int) -> JavaTypeQualifiers,
|
||||
index: Int,
|
||||
position: TypeComponentPosition
|
||||
): SimpleResult {
|
||||
val shouldEnhance = position.shouldEnhance()
|
||||
if (!shouldEnhance && arguments.isEmpty()) return SimpleResult(this, 1, false)
|
||||
|
||||
val subtreeSize = globalArgIndex - index
|
||||
if (!wereChanges) return SimpleResult(this, subtreeSize, wereChanges = false)
|
||||
val originalClass = constructor.declarationDescriptor
|
||||
?: return SimpleResult(this, 1, false)
|
||||
|
||||
val newAnnotations = listOfNotNull(
|
||||
annotations,
|
||||
enhancedMutabilityAnnotations,
|
||||
enhancedNullabilityAnnotations
|
||||
).compositeAnnotationsOrSingle()
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
val enhancedType = KotlinTypeFactory.simpleType(
|
||||
newAnnotations,
|
||||
typeConstructor,
|
||||
enhancedArguments,
|
||||
enhancedNullability
|
||||
)
|
||||
val typeConstructor = enhancedClassifier.typeConstructor
|
||||
|
||||
val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType
|
||||
val nullabilityForWarning = enhancedNullabilityAnnotations != null && effectiveQualifiers.isNullabilityQualifierForWarning
|
||||
val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement
|
||||
var globalArgIndex = index + 1
|
||||
var wereChanges = enhancedMutabilityAnnotations != null
|
||||
val enhancedArguments = arguments.mapIndexed { localArgIndex, arg ->
|
||||
if (arg.isStarProjection) {
|
||||
globalArgIndex++
|
||||
TypeUtils.makeStarProjection(enhancedClassifier.typeConstructor.parameters[localArgIndex])
|
||||
} else {
|
||||
val enhanced = arg.type.unwrap().enhancePossiblyFlexible(qualifiers, globalArgIndex)
|
||||
wereChanges = wereChanges || enhanced.wereChanges
|
||||
globalArgIndex += enhanced.subtreeSize
|
||||
createProjection(enhanced.type, arg.projectionKind, typeParameterDescriptor = typeConstructor.parameters[localArgIndex])
|
||||
}
|
||||
}
|
||||
|
||||
return SimpleResult(result as SimpleType, subtreeSize, wereChanges = true)
|
||||
val (enhancedNullability, enhancedNullabilityAnnotations) = this.getEnhancedNullability(effectiveQualifiers, position)
|
||||
wereChanges = wereChanges || enhancedNullabilityAnnotations != null
|
||||
|
||||
val subtreeSize = globalArgIndex - index
|
||||
if (!wereChanges) return SimpleResult(this, subtreeSize, wereChanges = false)
|
||||
|
||||
val newAnnotations = listOfNotNull(
|
||||
annotations,
|
||||
enhancedMutabilityAnnotations,
|
||||
enhancedNullabilityAnnotations
|
||||
).compositeAnnotationsOrSingle()
|
||||
|
||||
val enhancedType = KotlinTypeFactory.simpleType(
|
||||
newAnnotations,
|
||||
typeConstructor,
|
||||
enhancedArguments,
|
||||
enhancedNullability
|
||||
)
|
||||
|
||||
val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType
|
||||
val nullabilityForWarning = enhancedNullabilityAnnotations != null && effectiveQualifiers.isNullabilityQualifierForWarning
|
||||
val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement
|
||||
|
||||
return SimpleResult(result as SimpleType, subtreeSize, wereChanges = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Annotations>.compositeAnnotationsOrSingle() = when (size) {
|
||||
|
||||
Reference in New Issue
Block a user