[FIR] Partially support raw types
This commit is contained in:
@@ -119,7 +119,7 @@ abstract class ConeAbbreviatedType : ConeClassLikeType() {
|
|||||||
abstract val abbreviationLookupTag: ConeClassLikeLookupTag
|
abstract val abbreviationLookupTag: ConeClassLikeLookupTag
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ConeFlexibleType(val lowerBound: ConeKotlinType, val upperBound: ConeKotlinType) : ConeKotlinType(),
|
open class ConeFlexibleType(val lowerBound: ConeKotlinType, val upperBound: ConeKotlinType) : ConeKotlinType(),
|
||||||
FlexibleTypeMarker {
|
FlexibleTypeMarker {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -133,6 +133,25 @@ data class ConeFlexibleType(val lowerBound: ConeKotlinType, val upperBound: Cone
|
|||||||
|
|
||||||
override val nullability: ConeNullability
|
override val nullability: ConeNullability
|
||||||
get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN
|
get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as ConeFlexibleType
|
||||||
|
|
||||||
|
if (lowerBound != other.lowerBound) return false
|
||||||
|
if (upperBound != other.upperBound) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = lowerBound.hashCode()
|
||||||
|
result = 31 * result + upperBound.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ConeKotlinType.upperBoundIfFlexible() = (this as? ConeFlexibleType)?.upperBound ?: this
|
fun ConeKotlinType.upperBoundIfFlexible() = (this as? ConeFlexibleType)?.upperBound ?: this
|
||||||
@@ -182,6 +201,8 @@ class ConeDefinitelyNotNullType private constructor(val original: ConeKotlinType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConeRawType(lowerBound: ConeKotlinType, upperBound: ConeKotlinType) : ConeFlexibleType(lowerBound, upperBound), RawTypeMarker
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Contract of the intersection type: it is flat. It means that
|
* Contract of the intersection type: it is flat. It means that
|
||||||
* intersection type can not contains another intersection types
|
* intersection type can not contains another intersection types
|
||||||
|
|||||||
@@ -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.FirResolvedNamedReferenceImpl
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
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.ConeClassLikeLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||||
@@ -88,7 +89,10 @@ private fun JavaType?.enhancePossiblyFlexible(
|
|||||||
session, javaTypeParameterStack, annotations, arguments, TypeComponentPosition.FLEXIBLE_UPPER, qualifiers, index
|
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 -> {
|
is JavaArrayType -> {
|
||||||
val baseEnhanced = type.toNotNullConeKotlinType(session, javaTypeParameterStack)
|
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(
|
private fun JavaClassifierType.enhanceInflexibleType(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
javaTypeParameterStack: JavaTypeParameterStack,
|
javaTypeParameterStack: JavaTypeParameterStack,
|
||||||
@@ -169,7 +244,8 @@ private fun JavaClassifierType.enhanceInflexibleType(
|
|||||||
qualifiers: IndexedJavaTypeQualifiers,
|
qualifiers: IndexedJavaTypeQualifiers,
|
||||||
index: Int
|
index: Int
|
||||||
): ConeLookupTagBasedType {
|
): ConeLookupTagBasedType {
|
||||||
val originalTag = when (val classifier = classifier) {
|
val classifier = classifier
|
||||||
|
val originalTag = when (classifier) {
|
||||||
is JavaClass -> {
|
is JavaClass -> {
|
||||||
val classId = classifier.classId!!
|
val classId = classifier.classId!!
|
||||||
var mappedId = JavaToKotlinClassMap.mapJavaToKotlin(classId.asSingleFqName())
|
var mappedId = JavaToKotlinClassMap.mapJavaToKotlin(classId.asSingleFqName())
|
||||||
@@ -188,20 +264,32 @@ private fun JavaClassifierType.enhanceInflexibleType(
|
|||||||
val effectiveQualifiers = qualifiers(index)
|
val effectiveQualifiers = qualifiers(index)
|
||||||
val enhancedTag = originalTag.enhanceMutability(effectiveQualifiers, position)
|
val enhancedTag = originalTag.enhanceMutability(effectiveQualifiers, position)
|
||||||
|
|
||||||
var globalArgIndex = index + 1
|
val enhancedArguments = if (isRaw) {
|
||||||
val enhancedArguments = arguments.mapIndexed { localArgIndex, arg ->
|
val firClassifier = originalTag.toSymbol(session)!!.firUnsafe<FirRegularClass>()
|
||||||
if (arg is JavaWildcardType) {
|
firClassifier.typeParameters.map {
|
||||||
globalArgIndex++
|
val fir = it
|
||||||
arg.toConeProjection(
|
val erasedUpperBound = fir.getErasedUpperBound {
|
||||||
session,
|
firClassifier.defaultType().withArguments(firClassifier.typeParameters.map { ConeStarProjection }.toTypedArray())
|
||||||
javaTypeParameterStack,
|
}
|
||||||
((originalTag as? FirBasedSymbol<*>)?.fir as? FirCallableMemberDeclaration<*>)?.typeParameters?.getOrNull(localArgIndex)
|
computeProjection(session, fir, position, erasedUpperBound)
|
||||||
)
|
}
|
||||||
} else {
|
} else {
|
||||||
val argEnhancedTypeRef = arg.enhancePossiblyFlexible(session, javaTypeParameterStack, annotations, qualifiers, globalArgIndex)
|
var globalArgIndex = index + 1
|
||||||
globalArgIndex += arg.subtreeSize()
|
arguments.mapIndexed { localArgIndex, arg ->
|
||||||
// For arg == null (raw type) we take <out Any> to match everything
|
if (arg is JavaWildcardType) {
|
||||||
argEnhancedTypeRef.type.type.toTypeProjection(if (arg == null) Variance.OUT_VARIANCE else Variance.INVARIANT)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession)
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is ConeRawType -> lowerBound.scope(useSiteSession, scopeSession)
|
||||||
is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession)
|
is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession)
|
||||||
is ConeIntersectionType -> FirCompositeScope(
|
is ConeIntersectionType -> FirCompositeScope(
|
||||||
intersectedTypes.mapNotNullTo(mutableListOf()) {
|
intersectedTypes.mapNotNullTo(mutableListOf()) {
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun FlexibleTypeMarker.asRawType(): RawTypeMarker? {
|
override fun FlexibleTypeMarker.asRawType(): RawTypeMarker? {
|
||||||
assert(this is ConeKotlinType)
|
require(this is ConeFlexibleType)
|
||||||
return null // TODO
|
return this as? ConeRawType
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker {
|
override fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker {
|
||||||
|
|||||||
Reference in New Issue
Block a user