FIR: enhance in/out-variant type arguments
This commit is contained in:
@@ -55,7 +55,7 @@ internal fun FirJavaTypeRef.enhance(
|
||||
): FirResolvedTypeRef =
|
||||
buildResolvedTypeRef {
|
||||
val subtreeSizes = mutableListOf<Int>().apply { typeWithoutEnhancement.computeSubtreeSizes(this) }
|
||||
type = typeWithoutEnhancement.enhanceConeKotlinType(session, qualifiers, 0, subtreeSizes)
|
||||
type = typeWithoutEnhancement.enhanceConeKotlinType(session, qualifiers, 0, subtreeSizes) ?: typeWithoutEnhancement
|
||||
annotations += this@enhance.annotations
|
||||
}
|
||||
|
||||
@@ -79,30 +79,29 @@ private fun ConeKotlinType.enhanceConeKotlinType(
|
||||
qualifiers: IndexedJavaTypeQualifiers,
|
||||
index: Int,
|
||||
subtreeSizes: List<Int>
|
||||
): ConeKotlinType {
|
||||
): ConeKotlinType? {
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> {
|
||||
val isRawType = this is ConeRawType
|
||||
|
||||
val lowerResult = lowerBound.enhanceInflexibleType(
|
||||
session, TypeComponentPosition.FLEXIBLE_LOWER, qualifiers, index, subtreeSizes, isRawType
|
||||
session, TypeComponentPosition.FLEXIBLE_LOWER, qualifiers, index, subtreeSizes
|
||||
)
|
||||
val upperResult = upperBound.enhanceInflexibleType(
|
||||
session, TypeComponentPosition.FLEXIBLE_UPPER, qualifiers, index, subtreeSizes, isRawType
|
||||
session, TypeComponentPosition.FLEXIBLE_UPPER, qualifiers, index, subtreeSizes
|
||||
)
|
||||
|
||||
when {
|
||||
lowerResult === lowerBound && upperResult === upperBound -> this
|
||||
this is ConeRawType -> ConeRawType(lowerResult, upperResult)
|
||||
lowerResult == null && upperResult == null -> null
|
||||
this is ConeRawType -> ConeRawType(lowerResult ?: lowerBound, upperResult ?: upperBound)
|
||||
else -> coneFlexibleOrSimpleType(
|
||||
session, lowerResult, upperResult, isNotNullTypeParameter = qualifiers(index).isNotNullTypeParameter
|
||||
session, lowerResult ?: lowerBound, upperResult ?: upperBound,
|
||||
isNotNullTypeParameter = qualifiers(index).isNotNullTypeParameter
|
||||
)
|
||||
}
|
||||
}
|
||||
is ConeSimpleKotlinType -> enhanceInflexibleType(
|
||||
session, TypeComponentPosition.INFLEXIBLE, qualifiers, index, subtreeSizes, isBoundOfRawType = false
|
||||
session, TypeComponentPosition.INFLEXIBLE, qualifiers, index, subtreeSizes
|
||||
)
|
||||
else -> this
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,69 +157,45 @@ private fun ConeKotlinType.enhanceInflexibleType(
|
||||
qualifiers: IndexedJavaTypeQualifiers,
|
||||
index: Int,
|
||||
subtreeSizes: List<Int>,
|
||||
@Suppress("UNUSED_PARAMETER") isBoundOfRawType: Boolean,
|
||||
): ConeKotlinType {
|
||||
): ConeKotlinType? {
|
||||
require(this !is ConeFlexibleType) { "$this should not be flexible" }
|
||||
val shouldEnhance = position.shouldEnhance()
|
||||
if (!shouldEnhance && typeArguments.isEmpty() || this !is ConeLookupTagBasedType) {
|
||||
return this
|
||||
if ((!shouldEnhance && typeArguments.isEmpty()) || this !is ConeLookupTagBasedType) {
|
||||
return null
|
||||
}
|
||||
|
||||
val originalTag = lookupTag
|
||||
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val enhancedTag = originalTag.enhanceMutability(effectiveQualifiers, position)
|
||||
val enhancedTag = lookupTag.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
var wereChangesInArgs = false
|
||||
val nullabilityFromQualifiers = effectiveQualifiers.nullability.takeIf { shouldEnhance }
|
||||
val enhancedNullability = when (nullabilityFromQualifiers) {
|
||||
NullabilityQualifier.NULLABLE -> true
|
||||
NullabilityQualifier.NOT_NULL -> false
|
||||
else -> isNullable
|
||||
}
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
val enhancedArguments = typeArguments.map { arg ->
|
||||
if (arg.kind != ProjectionKind.INVARIANT) {
|
||||
globalArgIndex++
|
||||
arg
|
||||
} else {
|
||||
require(arg is ConeKotlinType) { "Should be invariant type: $arg" }
|
||||
val enhanced = arg.enhanceConeKotlinType(session, qualifiers, globalArgIndex, subtreeSizes)
|
||||
globalArgIndex += subtreeSizes[globalArgIndex]
|
||||
wereChangesInArgs = wereChangesInArgs || enhanced !== arg
|
||||
enhanced.type
|
||||
val argIndex = globalArgIndex.also { globalArgIndex += subtreeSizes[it] }
|
||||
arg.type?.enhanceConeKotlinType(session, qualifiers, argIndex, subtreeSizes)?.let {
|
||||
when (arg.kind) {
|
||||
ProjectionKind.IN -> ConeKotlinTypeProjectionIn(it)
|
||||
ProjectionKind.OUT -> ConeKotlinTypeProjectionOut(it)
|
||||
ProjectionKind.STAR -> ConeStarProjection
|
||||
ProjectionKind.INVARIANT -> it
|
||||
}
|
||||
}
|
||||
}.toTypedArray()
|
||||
|
||||
val (enhancedNullability, enhancedNullabilityAttribute) = getEnhancedNullability(effectiveQualifiers, position)
|
||||
wereChangesInArgs = wereChangesInArgs || (enhancedNullabilityAttribute != null && !this.hasEnhancedNullability)
|
||||
|
||||
if (!wereChangesInArgs && originalTag == enhancedTag && enhancedNullability == isNullable) {
|
||||
return this
|
||||
}
|
||||
|
||||
var attributes = this.attributes
|
||||
enhancedNullabilityAttribute?.let { attributes += it }
|
||||
|
||||
// TODO: why all of these is needed
|
||||
// val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType
|
||||
// val nullabilityForWarning = nullabilityChanged && effectiveQualifiers.isNullabilityQualifierForWarning
|
||||
// val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement
|
||||
|
||||
return enhancedTag.constructType(enhancedArguments, enhancedNullability, attributes)
|
||||
}
|
||||
|
||||
private data class EnhancementResult<out T>(val result: T, val enhancementAttribute: ConeAttribute<*>?)
|
||||
|
||||
private fun <T> T.noChange(): EnhancementResult<T> = EnhancementResult(this, null)
|
||||
private fun <T> T.enhancedNullability(): EnhancementResult<T> = EnhancementResult(this, CompilerConeAttributes.EnhancedNullability)
|
||||
|
||||
private fun ConeKotlinType.getEnhancedNullability(
|
||||
qualifiers: JavaTypeQualifiers,
|
||||
position: TypeComponentPosition
|
||||
): EnhancementResult<Boolean> {
|
||||
if (!position.shouldEnhance()) return this.isMarkedNullable.noChange()
|
||||
|
||||
return when (qualifiers.nullability) {
|
||||
NullabilityQualifier.NULLABLE -> true.noChange()
|
||||
NullabilityQualifier.NOT_NULL -> false.enhancedNullability()
|
||||
else -> this.isMarkedNullable.noChange()
|
||||
val shouldAddAttribute = nullabilityFromQualifiers == NullabilityQualifier.NOT_NULL && !hasEnhancedNullability
|
||||
if (lookupTag == enhancedTag && enhancedNullability == isNullable && !shouldAddAttribute && enhancedArguments.all { it == null }) {
|
||||
return null // absolutely no changes
|
||||
}
|
||||
|
||||
// TODO: val nullabilityForWarning = enhancedNullabilityAttribute != null && effectiveQualifiers.isNullabilityQualifierForWarning
|
||||
val mergedArguments = Array(typeArguments.size) { enhancedArguments[it] ?: typeArguments[it] }
|
||||
val mergedAttributes = if (shouldAddAttribute) attributes + CompilerConeAttributes.EnhancedNullability else attributes
|
||||
return enhancedTag.constructType(mergedArguments, enhancedNullability, mergedAttributes)
|
||||
}
|
||||
|
||||
private fun ConeClassifierLookupTag.enhanceMutability(
|
||||
|
||||
Reference in New Issue
Block a user