[FIR] Java super-type arguments are now handled as flexible

This commit is contained in:
Mikhail Glukhikh
2020-01-31 12:57:29 +03:00
parent aeb6f35571
commit 91b432b4a1
32 changed files with 122 additions and 93 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeNullability
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.load.java.JavaClassFinder
@@ -95,7 +96,7 @@ class JavaSymbolProvider(
) {
require(this is FirTypeParameterImpl)
for (upperBound in javaTypeParameter.upperBounds) {
bounds += upperBound.toFirResolvedTypeRef(this@JavaSymbolProvider.session, stack, isNullable = true)
bounds += upperBound.toFirResolvedTypeRef(this@JavaSymbolProvider.session, stack, nullability = ConeNullability.NULLABLE)
}
addDefaultBoundIfNecessary()
}
@@ -155,7 +156,9 @@ class JavaSymbolProvider(
this.typeParameters += foundClass.typeParameters.convertTypeParameters(javaTypeParameterStack)
addAnnotationsFrom(this@JavaSymbolProvider.session, javaClass, javaTypeParameterStack)
for (supertype in javaClass.supertypes) {
superTypeRefs += supertype.toFirResolvedTypeRef(this@JavaSymbolProvider.session, javaTypeParameterStack)
superTypeRefs += supertype.toFirResolvedTypeRef(
this@JavaSymbolProvider.session, javaTypeParameterStack, typeParametersNullability = ConeNullability.UNKNOWN
)
}
// TODO: may be we can process fields & methods later.
// However, they should be built up to override resolve stage
@@ -78,8 +78,8 @@ internal fun FirTypeRef.toNotNullConeKotlinType(
internal fun JavaType?.toNotNullConeKotlinType(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack
): ConeLookupTagBasedType {
return toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable = false)
): ConeKotlinType {
return toConeKotlinTypeWithNullability(session, javaTypeParameterStack, ConeNullability.NOT_NULL)
}
internal fun JavaType.toFirJavaTypeRef(session: FirSession, javaTypeParameterStack: JavaTypeParameterStack): FirJavaTypeRef {
@@ -91,9 +91,12 @@ internal fun JavaType.toFirJavaTypeRef(session: FirSession, javaTypeParameterSta
}
internal fun JavaClassifierType.toFirResolvedTypeRef(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, isNullable: Boolean = false
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
nullability: ConeNullability = ConeNullability.NOT_NULL,
typeParametersNullability: ConeNullability = ConeNullability.NOT_NULL
): FirResolvedTypeRef {
val coneType = this.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable)
val coneType = this.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, nullability, typeParametersNullability)
return FirResolvedTypeRefImpl(
source = null, type = coneType
).apply {
@@ -102,11 +105,14 @@ internal fun JavaClassifierType.toFirResolvedTypeRef(
}
internal fun JavaType?.toConeKotlinTypeWithNullability(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, isNullable: Boolean
): ConeLookupTagBasedType {
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
nullability: ConeNullability,
typeParametersNullability: ConeNullability = ConeNullability.NOT_NULL
): ConeKotlinType {
return when (this) {
is JavaClassifierType -> {
toConeKotlinTypeWithNullability(session, isNullable, javaTypeParameterStack)
toConeKotlinTypeWithNullability(session, nullability, typeParametersNullability, javaTypeParameterStack)
}
is JavaPrimitiveType -> {
val primitiveType = type
@@ -115,38 +121,47 @@ internal fun JavaType?.toConeKotlinTypeWithNullability(
else -> javaName.capitalize()
}
val classId = StandardClassIds.byName(kotlinPrimitiveName)
classId.toConeKotlinType(emptyArray(), isNullable)
classId.toConeKotlinType(emptyArray(), nullability.isNullable)
}
is JavaArrayType -> {
val componentType = componentType
if (componentType !is JavaPrimitiveType) {
val classId = StandardClassIds.Array
val argumentType = ConeFlexibleType(
componentType.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable = false),
componentType.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable = true)
componentType.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, ConeNullability.NOT_NULL),
componentType.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, ConeNullability.NULLABLE)
)
classId.toConeKotlinType(arrayOf(argumentType), isNullable)
classId.toConeKotlinType(arrayOf(argumentType), nullability.isNullable)
} else {
val javaComponentName = componentType.type?.typeName?.asString()?.capitalize() ?: error("Array of voids")
val classId = StandardClassIds.byName(javaComponentName + "Array")
classId.toConeKotlinType(emptyArray(), isNullable)
classId.toConeKotlinType(emptyArray(), nullability.isNullable)
}
}
is JavaWildcardType -> bound?.toNotNullConeKotlinType(session, javaTypeParameterStack) ?: run {
val classId = StandardClassIds.Any
classId.toConeKotlinType(emptyArray(), isNullable)
classId.toConeKotlinType(emptyArray(), nullability.isNullable)
}
null -> {
val classId = StandardClassIds.Any
classId.toConeKotlinType(emptyArray(), isNullable)
classId.toConeKotlinType(emptyArray(), nullability.isNullable)
}
else -> error("Strange JavaType: ${this::class.java}")
}
}
internal fun JavaClassifierType.toConeKotlinTypeWithNullability(
session: FirSession, isNullable: Boolean, javaTypeParameterStack: JavaTypeParameterStack
): ConeLookupTagBasedType {
session: FirSession,
nullability: ConeNullability,
typeParametersNullability: ConeNullability,
javaTypeParameterStack: JavaTypeParameterStack
): ConeKotlinType {
if (nullability == ConeNullability.UNKNOWN) {
return ConeFlexibleType(
toConeKotlinTypeWithNullability(session, ConeNullability.NOT_NULL, typeParametersNullability, javaTypeParameterStack),
toConeKotlinTypeWithNullability(session, ConeNullability.NULLABLE, typeParametersNullability, javaTypeParameterStack)
)
}
return when (val classifier = classifier) {
is JavaClass -> {
//val classId = classifier.classId!!
@@ -155,17 +170,16 @@ internal fun JavaClassifierType.toConeKotlinTypeWithNullability(
val lookupTag = ConeClassLikeLookupTagImpl(classId)
lookupTag.constructClassType(
typeArguments.mapIndexed { index, argument ->
typeArguments.map { argument ->
argument.toConeProjection(
session, javaTypeParameterStack, null
//symbol.fir.typeParameters.getOrNull(index)
session, javaTypeParameterStack, boundTypeParameter = null, nullability = typeParametersNullability
)
}.toTypedArray(), isNullable
}.toTypedArray(), nullability.isNullable
)
}
is JavaTypeParameter -> {
val symbol = javaTypeParameterStack[classifier]
ConeTypeParameterTypeImpl(symbol.toLookupTag(), isNullable)
ConeTypeParameterTypeImpl(symbol.toLookupTag(), nullability.isNullable)
}
else -> ConeClassErrorType(reason = "Unexpected classifier: $classifier")
}
@@ -208,7 +222,10 @@ internal fun JavaValueParameter.toFirValueParameter(
}
internal fun JavaType?.toConeProjection(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, boundTypeParameter: FirTypeParameter?
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
boundTypeParameter: FirTypeParameter?,
nullability: ConeNullability = ConeNullability.NOT_NULL
): ConeKotlinTypeProjection {
return when (this) {
null -> ConeStarProjection
@@ -219,7 +236,7 @@ internal fun JavaType?.toConeProjection(
if (bound == null || parameterVariance != INVARIANT && parameterVariance != argumentVariance) {
ConeStarProjection
} else {
val boundType = bound.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable = false)
val boundType = bound.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, nullability)
if (argumentVariance == OUT_VARIANCE) {
ConeKotlinTypeProjectionOut(boundType)
} else {
@@ -227,7 +244,7 @@ internal fun JavaType?.toConeProjection(
}
}
}
is JavaClassifierType -> toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable = false)
is JavaClassifierType -> toConeKotlinTypeWithNullability(session, javaTypeParameterStack, nullability)
else -> ConeClassErrorType("Unexpected type argument: $this")
}
}
@@ -260,7 +277,9 @@ private fun JavaAnnotationArgument.toFirExpression(
null
}
this.calleeReference = calleeReference
?: FirErrorNamedReferenceImpl(null, FirSimpleDiagnostic("Strange Java enum value: $classId.$entryName", DiagnosticKind.Java))
?: FirErrorNamedReferenceImpl(
null, FirSimpleDiagnostic("Strange Java enum value: $classId.$entryName", DiagnosticKind.Java)
)
}
}
is JavaClassObjectAnnotationArgument -> FirGetClassCallImpl(null).apply {
@@ -270,7 +289,9 @@ private fun JavaAnnotationArgument.toFirExpression(
)
}
is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall(session, javaTypeParameterStack)
else -> FirErrorExpressionImpl(null, FirSimpleDiagnostic("Unknown JavaAnnotationArgument: ${this::class.java}", DiagnosticKind.Java))
else -> FirErrorExpressionImpl(
null, FirSimpleDiagnostic("Unknown JavaAnnotationArgument: ${this::class.java}", DiagnosticKind.Java)
)
}
}
@@ -304,7 +325,9 @@ internal fun Any?.createConstant(session: FirSession): FirExpression {
is BooleanArray -> toList().createArrayOfCall(session, FirConstKind.Boolean)
null -> FirConstExpressionImpl(null, FirConstKind.Null, null)
else -> FirErrorExpressionImpl(null, FirSimpleDiagnostic("Unknown value in JavaLiteralAnnotationArgument: $this", DiagnosticKind.Java))
else -> FirErrorExpressionImpl(
null, FirSimpleDiagnostic("Unknown value in JavaLiteralAnnotationArgument: $this", DiagnosticKind.Java)
)
}
}
@@ -152,8 +152,8 @@ internal class EnhancementSignatureParts(
is FirJavaTypeRef -> {
Pair(
// TODO: optimize
type.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable = false),
type.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, isNullable = true)
type.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, nullability = ConeNullability.NOT_NULL),
type.toConeKotlinTypeWithNullability(session, javaTypeParameterStack, nullability = ConeNullability.NULLABLE)
)
}
else -> return JavaTypeQualifiers.NONE
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.java.toConeProjection
import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
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
@@ -124,12 +123,12 @@ private fun JavaType?.subtreeSize(): Int {
private fun coneFlexibleOrSimpleType(
session: FirSession,
lowerBound: ConeLookupTagBasedType,
upperBound: ConeLookupTagBasedType,
lowerBound: ConeKotlinType,
upperBound: ConeKotlinType,
isNotNullTypeParameter: Boolean
): ConeKotlinType {
if (AbstractStrictEqualityTypeChecker.strictEqualTypes(session.typeContext, lowerBound, upperBound)) {
val lookupTag = lowerBound.lookupTag
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
@@ -164,8 +163,6 @@ 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
@@ -181,8 +178,7 @@ private fun FirTypeParameter.getErasedUpperBound(
val firstUpperBound = this.bounds.first().coneTypeUnsafe<ConeKotlinType>()
val firstUpperBoundClassifier = firstUpperBound
if (firstUpperBoundClassifier is ConeClassLikeType) {
if (firstUpperBound is ConeClassLikeType) {
return firstUpperBound.withArguments(firstUpperBound.typeArguments.map { ConeStarProjection }.toTypedArray())
}
@@ -225,7 +221,8 @@ fun computeProjection(
// in T -> Comparable<Nothing>
session.builtinTypes.nothingType.type
else if (erasedUpperBound is ConeClassLikeType &&
erasedUpperBound.lookupTag.toSymbol(session)!!.firUnsafe<FirRegularClass>().typeParameters.isNotEmpty())
erasedUpperBound.lookupTag.toSymbol(session)!!.firUnsafe<FirRegularClass>().typeParameters.isNotEmpty()
)
// T : Enum<E> -> out Enum<*>
ConeKotlinTypeProjectionOut(erasedUpperBound)
else
@@ -234,8 +231,6 @@ fun computeProjection(
}
}
private fun JavaClassifierType.enhanceInflexibleType(
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
@@ -244,9 +239,8 @@ private fun JavaClassifierType.enhanceInflexibleType(
position: TypeComponentPosition,
qualifiers: IndexedJavaTypeQualifiers,
index: Int
): ConeLookupTagBasedType {
val classifier = classifier
val originalTag = when (classifier) {
): ConeKotlinType {
val originalTag = when (val classifier = classifier) {
is JavaClass -> {
val classId = classifier.classId!!
var mappedId = JavaToKotlinClassMap.mapJavaToKotlin(classId.asSingleFqName())