FIR: in computeJvmDescriptor, convert type parameter bounds too
Note the sheer amount of TODOs, though - I'm honestly surprised that function works at all.
This commit is contained in:
@@ -25,6 +25,8 @@ fun FirFunction.computeJvmSignature(typeConversion: (FirTypeRef) -> ConeKotlinTy
|
|||||||
return SignatureBuildingComponents.signature(containingClass.classId, computeJvmDescriptor(typeConversion = typeConversion))
|
return SignatureBuildingComponents.signature(containingClass.classId, computeJvmDescriptor(typeConversion = typeConversion))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: `typeConversion` is only used for converting Java types into cone types, but shouldn't it be trivial
|
||||||
|
// to construct a JVM descriptor from a Java type directly? The question is how to make the two paths consistent...
|
||||||
fun FirFunction.computeJvmDescriptor(
|
fun FirFunction.computeJvmDescriptor(
|
||||||
customName: String? = null,
|
customName: String? = null,
|
||||||
includeReturnType: Boolean = true,
|
includeReturnType: Boolean = true,
|
||||||
@@ -42,7 +44,7 @@ fun FirFunction.computeJvmDescriptor(
|
|||||||
|
|
||||||
append("(")
|
append("(")
|
||||||
for (parameter in valueParameters) {
|
for (parameter in valueParameters) {
|
||||||
typeConversion(parameter.returnTypeRef)?.let(this::appendConeType)
|
typeConversion(parameter.returnTypeRef)?.let { appendConeType(it, typeConversion) }
|
||||||
}
|
}
|
||||||
append(")")
|
append(")")
|
||||||
|
|
||||||
@@ -50,7 +52,7 @@ fun FirFunction.computeJvmDescriptor(
|
|||||||
if (this@computeJvmDescriptor !is FirSimpleFunction || returnTypeRef.isVoid()) {
|
if (this@computeJvmDescriptor !is FirSimpleFunction || returnTypeRef.isVoid()) {
|
||||||
append("V")
|
append("V")
|
||||||
} else {
|
} else {
|
||||||
typeConversion(returnTypeRef)?.let(this::appendConeType)
|
typeConversion(returnTypeRef)?.let { appendConeType(it, typeConversion) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +68,7 @@ private val PRIMITIVE_TYPE_SIGNATURE: Map<String, String> = mapOf(
|
|||||||
"Double" to "D",
|
"Double" to "D",
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun StringBuilder.appendConeType(coneType: ConeKotlinType) {
|
private fun StringBuilder.appendConeType(coneType: ConeKotlinType, typeConversion: (FirTypeRef) -> ConeKotlinType?) {
|
||||||
(coneType as? ConeClassLikeType)?.let {
|
(coneType as? ConeClassLikeType)?.let {
|
||||||
val classId = it.lookupTag.classId
|
val classId = it.lookupTag.classId
|
||||||
if (classId.packageFqName.toString() == "kotlin") {
|
if (classId.packageFqName.toString() == "kotlin") {
|
||||||
@@ -79,13 +81,14 @@ private fun StringBuilder.appendConeType(coneType: ConeKotlinType) {
|
|||||||
|
|
||||||
fun appendClassLikeType(type: ConeClassLikeType) {
|
fun appendClassLikeType(type: ConeClassLikeType) {
|
||||||
val baseClassId = type.lookupTag.classId
|
val baseClassId = type.lookupTag.classId
|
||||||
|
// TODO: what about primitive arrays?
|
||||||
val classId = JavaToKotlinClassMap.mapKotlinToJava(baseClassId.asSingleFqName().toUnsafe()) ?: baseClassId
|
val classId = JavaToKotlinClassMap.mapKotlinToJava(baseClassId.asSingleFqName().toUnsafe()) ?: baseClassId
|
||||||
if (classId == StandardClassIds.Array) {
|
if (classId == StandardClassIds.Array) {
|
||||||
append("[")
|
append("[")
|
||||||
type.typeArguments.forEach { typeArg ->
|
type.typeArguments.forEach { typeArg ->
|
||||||
when (typeArg) {
|
when (typeArg) {
|
||||||
ConeStarProjection -> append("*")
|
ConeStarProjection -> append("*")
|
||||||
is ConeKotlinTypeProjection -> appendConeType(typeArg.type)
|
is ConeKotlinTypeProjection -> appendConeType(typeArg.type, typeConversion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -97,28 +100,29 @@ private fun StringBuilder.appendConeType(coneType: ConeKotlinType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coneType is ConeClassErrorType) return
|
|
||||||
when (coneType) {
|
when (coneType) {
|
||||||
|
is ConeClassErrorType -> Unit // TODO: just skipping it seems wrong
|
||||||
is ConeClassLikeType -> {
|
is ConeClassLikeType -> {
|
||||||
appendClassLikeType(coneType)
|
appendClassLikeType(coneType)
|
||||||
}
|
}
|
||||||
is ConeTypeParameterType -> {
|
is ConeTypeParameterType -> {
|
||||||
val representative = coneType.lookupTag.typeParameterSymbol.fir.bounds.firstOrNull {
|
// TODO: 1. unannotated bounds are probably flexible, so this isn't right;
|
||||||
it.coneType is ConeClassLikeType
|
// 2. shouldn't this always take the first bound and recurse if it's also a type parameter?
|
||||||
}
|
coneType.lookupTag.typeParameterSymbol.fir.bounds.firstNotNullOfOrNull {
|
||||||
if (representative == null || representative is FirImplicitNullableAnyTypeRef || representative is FirImplicitAnyTypeRef) {
|
val converted = typeConversion(it)
|
||||||
append("Ljava/lang/Object;")
|
if (converted is ConeClassLikeType) it to converted else null
|
||||||
} else {
|
}?.let { (firBound, coneBound) ->
|
||||||
appendClassLikeType(representative.coneTypeUnsafe())
|
// TODO: pretty sure Java type conversion does not produce either of these
|
||||||
|
if (firBound !is FirImplicitNullableAnyTypeRef && firBound !is FirImplicitAnyTypeRef) {
|
||||||
|
appendClassLikeType(coneBound)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
append("Ljava/lang/Object;")
|
||||||
}
|
}
|
||||||
is ConeDefinitelyNotNullType -> {
|
is ConeDefinitelyNotNullType -> appendConeType(coneType.original, typeConversion)
|
||||||
appendConeType(coneType.original)
|
is ConeFlexibleType -> appendConeType(coneType.lowerBound, typeConversion)
|
||||||
}
|
else -> Unit // TODO: throw an error? should check that Java type conversion/enhancement can only produce these cone types
|
||||||
is ConeFlexibleType -> {
|
|
||||||
appendConeType(coneType.lowerBound)
|
|
||||||
}
|
|
||||||
else -> {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user