[FIR] Partially support raw types
This commit is contained in:
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
|
||||
import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
@@ -88,7 +89,10 @@ private fun JavaType?.enhancePossiblyFlexible(
|
||||
session, javaTypeParameterStack, annotations, arguments, TypeComponentPosition.FLEXIBLE_UPPER, qualifiers, index
|
||||
)
|
||||
|
||||
coneFlexibleOrSimpleType(session, lowerResult, upperResult)
|
||||
when {
|
||||
type.isRaw -> ConeRawType(lowerResult, upperResult)
|
||||
else -> coneFlexibleOrSimpleType(session, lowerResult, upperResult)
|
||||
}
|
||||
}
|
||||
is JavaArrayType -> {
|
||||
val baseEnhanced = type.toNotNullConeKotlinType(session, javaTypeParameterStack)
|
||||
@@ -160,6 +164,77 @@ private fun ClassId.mutableToReadOnly(): ClassId? {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Definition:
|
||||
// ErasedUpperBound(T : G<t>) = G<*> // UpperBound(T) is a type G<t> with arguments
|
||||
// ErasedUpperBound(T : A) = A // UpperBound(T) is a type A without arguments
|
||||
// ErasedUpperBound(T : F) = UpperBound(F) // UB(T) is another type parameter F
|
||||
private fun FirTypeParameter.getErasedUpperBound(
|
||||
// Calculation of `potentiallyRecursiveTypeParameter.upperBounds` may recursively depend on `this.getErasedUpperBound`
|
||||
// E.g. `class A<T extends A, F extends A>`
|
||||
// To prevent recursive calls return defaultValue() instead
|
||||
potentiallyRecursiveTypeParameter: FirTypeParameter? = null,
|
||||
defaultValue: (() -> ConeKotlinType) = { ConeKotlinErrorType("Can't compute erased upper bound of type parameter `$this`") }
|
||||
): ConeKotlinType {
|
||||
if (this === potentiallyRecursiveTypeParameter) return defaultValue()
|
||||
|
||||
val firstUpperBound = this.bounds.first().coneTypeUnsafe<ConeKotlinType>()
|
||||
|
||||
val firstUpperBoundClassifier = firstUpperBound
|
||||
if (firstUpperBoundClassifier is ConeClassLikeType) {
|
||||
return firstUpperBound.withArguments(firstUpperBound.typeArguments.map { ConeStarProjection }.toTypedArray())
|
||||
}
|
||||
|
||||
val stopAt = potentiallyRecursiveTypeParameter ?: this
|
||||
var current = (firstUpperBound as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir
|
||||
|
||||
while (current != stopAt) {
|
||||
|
||||
val nextUpperBound = current.bounds.first().coneTypeUnsafe<ConeKotlinType>()
|
||||
if (nextUpperBound is ConeClassLikeType) {
|
||||
return nextUpperBound.withArguments(nextUpperBound.typeArguments.map { ConeStarProjection }.toTypedArray())
|
||||
}
|
||||
|
||||
current = (nextUpperBound as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir
|
||||
}
|
||||
|
||||
return defaultValue()
|
||||
}
|
||||
|
||||
|
||||
fun computeProjection(
|
||||
session: FirSession,
|
||||
parameter: FirTypeParameter,
|
||||
attr: TypeComponentPosition,
|
||||
erasedUpperBound: ConeKotlinType = parameter.getErasedUpperBound()
|
||||
) = when (attr) {
|
||||
// Raw(List<T>) => (List<Any?>..List<*>)
|
||||
// Raw(Enum<T>) => (Enum<Enum<*>>..Enum<out Enum<*>>)
|
||||
// In the last case upper bound is equal to star projection `Enum<*>`,
|
||||
// but we want to keep matching tree structure of flexible bounds (at least they should have the same size)
|
||||
TypeComponentPosition.FLEXIBLE_LOWER -> {
|
||||
// T : String -> String
|
||||
// in T : String -> String
|
||||
// T : Enum<T> -> Enum<*>
|
||||
erasedUpperBound
|
||||
}
|
||||
TypeComponentPosition.FLEXIBLE_UPPER, TypeComponentPosition.INFLEXIBLE -> {
|
||||
if (!parameter.variance.allowsOutPosition)
|
||||
// in T -> Comparable<Nothing>
|
||||
session.builtinTypes.nothingType.type
|
||||
else if (erasedUpperBound is ConeClassLikeType &&
|
||||
erasedUpperBound.lookupTag.toSymbol(session)!!.firUnsafe<FirRegularClass>().typeParameters.isNotEmpty())
|
||||
// T : Enum<E> -> out Enum<*>
|
||||
ConeKotlinTypeProjectionOut(erasedUpperBound)
|
||||
else
|
||||
// T : String -> *
|
||||
ConeStarProjection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun JavaClassifierType.enhanceInflexibleType(
|
||||
session: FirSession,
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
@@ -169,7 +244,8 @@ private fun JavaClassifierType.enhanceInflexibleType(
|
||||
qualifiers: IndexedJavaTypeQualifiers,
|
||||
index: Int
|
||||
): ConeLookupTagBasedType {
|
||||
val originalTag = when (val classifier = classifier) {
|
||||
val classifier = classifier
|
||||
val originalTag = when (classifier) {
|
||||
is JavaClass -> {
|
||||
val classId = classifier.classId!!
|
||||
var mappedId = JavaToKotlinClassMap.mapJavaToKotlin(classId.asSingleFqName())
|
||||
@@ -188,20 +264,32 @@ private fun JavaClassifierType.enhanceInflexibleType(
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val enhancedTag = originalTag.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
val enhancedArguments = arguments.mapIndexed { localArgIndex, arg ->
|
||||
if (arg is JavaWildcardType) {
|
||||
globalArgIndex++
|
||||
arg.toConeProjection(
|
||||
session,
|
||||
javaTypeParameterStack,
|
||||
((originalTag as? FirBasedSymbol<*>)?.fir as? FirCallableMemberDeclaration<*>)?.typeParameters?.getOrNull(localArgIndex)
|
||||
)
|
||||
} else {
|
||||
val argEnhancedTypeRef = arg.enhancePossiblyFlexible(session, javaTypeParameterStack, annotations, qualifiers, globalArgIndex)
|
||||
globalArgIndex += arg.subtreeSize()
|
||||
// For arg == null (raw type) we take <out Any> to match everything
|
||||
argEnhancedTypeRef.type.type.toTypeProjection(if (arg == null) Variance.OUT_VARIANCE else Variance.INVARIANT)
|
||||
val enhancedArguments = if (isRaw) {
|
||||
val firClassifier = originalTag.toSymbol(session)!!.firUnsafe<FirRegularClass>()
|
||||
firClassifier.typeParameters.map {
|
||||
val fir = it
|
||||
val erasedUpperBound = fir.getErasedUpperBound {
|
||||
firClassifier.defaultType().withArguments(firClassifier.typeParameters.map { ConeStarProjection }.toTypedArray())
|
||||
}
|
||||
computeProjection(session, fir, position, erasedUpperBound)
|
||||
}
|
||||
} else {
|
||||
var globalArgIndex = index + 1
|
||||
arguments.mapIndexed { localArgIndex, arg ->
|
||||
if (arg is JavaWildcardType) {
|
||||
globalArgIndex++
|
||||
arg.toConeProjection(
|
||||
session,
|
||||
javaTypeParameterStack,
|
||||
((originalTag as? FirBasedSymbol<*>)?.fir as? FirCallableMemberDeclaration<*>)?.typeParameters?.getOrNull(localArgIndex)
|
||||
)
|
||||
} else {
|
||||
val argEnhancedTypeRef =
|
||||
arg.enhancePossiblyFlexible(session, javaTypeParameterStack, annotations, qualifiers, globalArgIndex)
|
||||
globalArgIndex += arg.subtreeSize()
|
||||
|
||||
argEnhancedTypeRef.type.type.toTypeProjection(Variance.INVARIANT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user