FIR: rearrange some stuff in Java type conversion code

This commit is contained in:
pyos
2021-08-20 17:59:34 +02:00
committed by teamcityserver
parent 090b90f62e
commit 8163acb964
2 changed files with 61 additions and 133 deletions
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
private fun ClassId.toLookupTag(): ConeClassLikeLookupTag = private fun ClassId.toLookupTag(): ConeClassLikeLookupTag =
ConeClassLikeLookupTagImpl(this) ConeClassLikeLookupTagImpl(this)
@@ -75,91 +74,75 @@ internal fun JavaType?.toFirResolvedTypeRef(
mode: FirJavaTypeConversionMode = FirJavaTypeConversionMode.DEFAULT mode: FirJavaTypeConversionMode = FirJavaTypeConversionMode.DEFAULT
): FirResolvedTypeRef { ): FirResolvedTypeRef {
return buildResolvedTypeRef { return buildResolvedTypeRef {
type = toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, mode) type = toConeKotlinType(session, javaTypeParameterStack, mode)
.let { if (mode == FirJavaTypeConversionMode.SUPERTYPE) it.lowerBoundIfFlexible() else it } .let { if (mode == FirJavaTypeConversionMode.SUPERTYPE) it.lowerBoundIfFlexible() else it }
annotations += type.attributes.customAnnotations annotations += type.attributes.customAnnotations
} }
} }
private fun JavaType?.toConeKotlinTypeWithoutEnhancement( private fun JavaType?.toConeKotlinType(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, session: FirSession, javaTypeParameterStack: JavaTypeParameterStack,
mode: FirJavaTypeConversionMode mode: FirJavaTypeConversionMode
): ConeKotlinType { ): ConeKotlinType =
toConeTypeProjection(session, javaTypeParameterStack, Variance.INVARIANT, mode).type
?: StandardClassIds.Any.toConeFlexibleType(emptyArray(), emptyArray(), ConeAttributes.Empty)
private fun JavaType?.toConeTypeProjection(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack,
parameterVariance: Variance, mode: FirJavaTypeConversionMode
): ConeTypeProjection {
val attributes = if (this != null && annotations.isNotEmpty()) val attributes = if (this != null && annotations.isNotEmpty())
ConeAttributes.create(listOf(CustomAnnotationTypeAttribute(convertAnnotationsToFir(session, javaTypeParameterStack)))) ConeAttributes.create(listOf(CustomAnnotationTypeAttribute(convertAnnotationsToFir(session, javaTypeParameterStack))))
else else
ConeAttributes.Empty ConeAttributes.Empty
return when (this) { return when (this) {
is JavaClassifierType -> is JavaClassifierType -> {
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, mode, attributes) val lowerBound = toConeKotlinTypeForFlexibleBound(session, javaTypeParameterStack, mode, attributes)
is JavaPrimitiveType -> { if (mode == FirJavaTypeConversionMode.ANNOTATION_MEMBER) {
val primitiveType = type return lowerBound // TODO: `KClass<Any>` is wrong for raw `Class`
val kotlinPrimitiveName = when (val javaName = primitiveType?.typeName?.asString()) {
null -> "Unit"
else -> javaName.capitalizeAsciiOnly()
} }
val upperBound = toConeKotlinTypeForFlexibleBound(session, javaTypeParameterStack, mode, attributes, lowerBound)
val classId = StandardClassIds.byName(kotlinPrimitiveName) if (isRaw) ConeRawType(lowerBound, upperBound) else ConeFlexibleType(lowerBound, upperBound)
classId.constructClassLikeType(emptyArray(), isNullable = false, attributes)
} }
is JavaArrayType ->
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, mode, attributes) is JavaArrayType -> {
is JavaWildcardType -> val (classId, arguments) = when (val componentType = componentType) {
bound?.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, mode) is JavaPrimitiveType ->
null -> null StandardClassIds.byName(componentType.type!!.arrayTypeName.identifier) to arrayOf()
else ->
StandardClassIds.Array to arrayOf(componentType.toConeKotlinType(session, javaTypeParameterStack, mode))
}
if (mode == FirJavaTypeConversionMode.ANNOTATION_MEMBER) {
classId.constructClassLikeType(arguments, isNullable = false, attributes)
} else {
val argumentsForUpper = Array(arguments.size) { ConeKotlinTypeProjectionOut(arguments[it]) }
classId.toConeFlexibleType(arguments, argumentsForUpper, attributes)
}
}
is JavaPrimitiveType ->
StandardClassIds.byName(type?.typeName?.identifier ?: "Unit")
.constructClassLikeType(emptyArray(), isNullable = false, attributes)
is JavaWildcardType -> {
// TODO: this discards annotations on wildcards, allowed since Java 8 - what do they mean?
// List<@NotNull ? extends @Nullable Object>
val bound = this.bound
val argumentVariance = if (isExtends) Variance.OUT_VARIANCE else Variance.IN_VARIANCE
if (bound == null || (parameterVariance != Variance.INVARIANT && parameterVariance != argumentVariance)) {
ConeStarProjection
} else {
val boundType = bound.toConeKotlinType(session, javaTypeParameterStack, mode)
if (isExtends) ConeKotlinTypeProjectionOut(boundType) else ConeKotlinTypeProjectionIn(boundType)
}
}
null -> ConeStarProjection
else -> error("Strange JavaType: ${this::class.java}") else -> error("Strange JavaType: ${this::class.java}")
} ?: StandardClassIds.Any.toConeFlexibleType(emptyArray(), emptyArray(), attributes = attributes)
}
private fun JavaArrayType.toConeKotlinTypeWithoutEnhancement(
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
mode: FirJavaTypeConversionMode,
attributes: ConeAttributes
): ConeKotlinType {
val componentType = componentType
return if (componentType !is JavaPrimitiveType) {
val classId = StandardClassIds.Array
val argumentType = componentType.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, mode)
if (mode == FirJavaTypeConversionMode.ANNOTATION_MEMBER) {
classId.constructClassLikeType(arrayOf(argumentType), isNullable = false, attributes = attributes)
} else {
classId.toConeFlexibleType(
arrayOf(argumentType),
typeArgumentsForUpper = arrayOf(ConeKotlinTypeProjectionOut(argumentType)),
attributes = attributes
)
}
} else {
val javaComponentName = componentType.type?.typeName?.asString()?.capitalizeAsciiOnly() ?: error("Array of voids")
val classId = StandardClassIds.byName(javaComponentName + "Array")
if (mode == FirJavaTypeConversionMode.ANNOTATION_MEMBER) {
classId.constructClassLikeType(emptyArray(), isNullable = false, attributes = attributes)
} else {
classId.toConeFlexibleType(emptyArray(), emptyArray(), attributes = attributes)
}
} }
} }
private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
mode: FirJavaTypeConversionMode,
attributes: ConeAttributes
): ConeKotlinType {
val lowerBound = toConeKotlinTypeForFlexibleBound(session, javaTypeParameterStack, mode, attributes)
if (mode == FirJavaTypeConversionMode.ANNOTATION_MEMBER) {
return lowerBound
}
val upperBound = toConeKotlinTypeForFlexibleBound(session, javaTypeParameterStack, mode, attributes, lowerBound)
return if (isRaw)
ConeRawType(lowerBound, upperBound)
else
ConeFlexibleType(lowerBound, upperBound)
}
private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound( private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
session: FirSession, session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack, javaTypeParameterStack: JavaTypeParameterStack,
@@ -192,9 +175,11 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
?: Array(classifier.typeParameters.size) { ConeStarProjection } ?: Array(classifier.typeParameters.size) { ConeStarProjection }
lookupTag != lowerBound?.lookupTag -> lookupTag != lowerBound?.lookupTag ->
Array(typeArguments.size) { index -> Array(typeArguments.size) { index ->
// TODO: check this
val newMode = if (mode == FirJavaTypeConversionMode.ANNOTATION_MEMBER) FirJavaTypeConversionMode.DEFAULT else mode
val argument = typeArguments[index] val argument = typeArguments[index]
val parameter = typeParameters?.getOrNull(index)?.symbol?.fir val variance = typeParameters?.getOrNull(index)?.symbol?.fir?.variance ?: Variance.INVARIANT
argument.toConeProjectionWithoutEnhancement(session, javaTypeParameterStack, parameter, mode) argument.toConeTypeProjection(session, javaTypeParameterStack, variance, newMode)
} }
else -> lowerBound.typeArguments else -> lowerBound.typeArguments
} }
@@ -266,32 +251,3 @@ private fun ConeKotlinType.eraseAsUpperBound(session: FirSession, cache: Mutable
original.eraseAsUpperBound(session, cache).makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext) original.eraseAsUpperBound(session, cache).makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext)
else -> error("unexpected Java type parameter upper bound kind: $this") else -> error("unexpected Java type parameter upper bound kind: $this")
} }
private fun JavaType?.toConeProjectionWithoutEnhancement(
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
boundTypeParameter: FirTypeParameter?,
mode: FirJavaTypeConversionMode
): ConeTypeProjection {
// TODO: check this
val newMode = mode.takeIf { it == FirJavaTypeConversionMode.SUPERTYPE } ?: FirJavaTypeConversionMode.DEFAULT
return when (this) {
null -> ConeStarProjection
is JavaWildcardType -> {
val bound = this.bound
val argumentVariance = if (isExtends) Variance.OUT_VARIANCE else Variance.IN_VARIANCE
val parameterVariance = boundTypeParameter?.variance ?: Variance.INVARIANT
if (bound == null || parameterVariance != Variance.INVARIANT && parameterVariance != argumentVariance) {
ConeStarProjection
} else {
val boundType = bound.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, newMode)
if (argumentVariance == Variance.OUT_VARIANCE) {
ConeKotlinTypeProjectionOut(boundType)
} else {
ConeKotlinTypeProjectionIn(boundType)
}
}
}
else -> toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, newMode)
}
}
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
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.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
@@ -30,7 +29,6 @@ import org.jetbrains.kotlin.load.java.typeEnhancement.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.utils.extractRadix import org.jetbrains.kotlin.utils.extractRadix
@@ -71,10 +69,7 @@ private fun ConeKotlinType.enhanceConeKotlinType(
when { when {
lowerResult == null && upperResult == null -> null lowerResult == null && upperResult == null -> null
this is ConeRawType -> ConeRawType(lowerResult ?: lowerBound, upperResult ?: upperBound) this is ConeRawType -> ConeRawType(lowerResult ?: lowerBound, upperResult ?: upperBound)
else -> coneFlexibleOrSimpleType( else -> coneFlexibleOrSimpleType(session.typeContext, lowerResult ?: lowerBound, upperResult ?: upperBound)
session, lowerResult ?: lowerBound, upperResult ?: upperBound,
isNotNullTypeParameter = qualifiers(index).isNotNullTypeParameter
)
} }
} }
is ConeSimpleKotlinType -> enhanceInflexibleType( is ConeSimpleKotlinType -> enhanceInflexibleType(
@@ -84,34 +79,6 @@ private fun ConeKotlinType.enhanceConeKotlinType(
} }
} }
private fun coneFlexibleOrSimpleType(
session: FirSession,
lowerBound: ConeKotlinType,
upperBound: ConeKotlinType,
isNotNullTypeParameter: Boolean
): ConeKotlinType {
if (AbstractStrictEqualityTypeChecker.strictEqualTypes(session.typeContext, lowerBound, upperBound)) {
val lookupTag = (lowerBound as? ConeLookupTagBasedType)?.lookupTag
if (isNotNullTypeParameter && lookupTag is ConeTypeParameterLookupTag && !lowerBound.isMarkedNullable) {
// TODO: we need enhancement for type parameter bounds for this code to work properly
// At this moment, this condition is always true
if (lookupTag.typeParameterSymbol.fir.bounds.any {
val type = it.coneType
type is ConeTypeParameterType || type.isNullable
}
) {
return ConeDefinitelyNotNullType.create(
lowerBound,
session.typeContext,
useCorrectedNullabilityForFlexibleTypeParameters = true
) ?: lowerBound
}
}
return lowerBound
}
return ConeFlexibleType(lowerBound, upperBound)
}
private val KOTLIN_COLLECTIONS = FqName("kotlin.collections") private val KOTLIN_COLLECTIONS = FqName("kotlin.collections")
private val KOTLIN_COLLECTIONS_PREFIX_LENGTH = KOTLIN_COLLECTIONS.asString().length + 1 private val KOTLIN_COLLECTIONS_PREFIX_LENGTH = KOTLIN_COLLECTIONS.asString().length + 1
@@ -174,7 +141,12 @@ private fun ConeKotlinType.enhanceInflexibleType(
// TODO: val nullabilityForWarning = enhancedNullabilityAttribute != null && effectiveQualifiers.isNullabilityQualifierForWarning // TODO: val nullabilityForWarning = enhancedNullabilityAttribute != null && effectiveQualifiers.isNullabilityQualifierForWarning
val mergedArguments = Array(typeArguments.size) { enhancedArguments[it] ?: typeArguments[it] } val mergedArguments = Array(typeArguments.size) { enhancedArguments[it] ?: typeArguments[it] }
val mergedAttributes = if (shouldAddAttribute) attributes + CompilerConeAttributes.EnhancedNullability else attributes val mergedAttributes = if (shouldAddAttribute) attributes + CompilerConeAttributes.EnhancedNullability else attributes
return enhancedTag.constructType(mergedArguments, enhancedNullability, mergedAttributes) val enhancedType = enhancedTag.constructType(mergedArguments, enhancedNullability, mergedAttributes)
return if (effectiveQualifiers.isNotNullTypeParameter)
ConeDefinitelyNotNullType.create(enhancedType, session.typeContext, useCorrectedNullabilityForFlexibleTypeParameters = true)
?: enhancedType
else
enhancedType
} }
private fun ConeClassifierLookupTag.enhanceMutability( private fun ConeClassifierLookupTag.enhanceMutability(