Merge pull request #10322 from igfoo/igfoo/arrays2

Kotlin: Rewrite array type extraction
This commit is contained in:
Ian Lynagh
2022-09-07 10:45:33 +01:00
committed by GitHub

View File

@@ -539,21 +539,52 @@ open class KotlinUsesExtractor(
)
}
private fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int, isPrimitiveArray: Boolean): TypeResults {
data class ArrayInfo(val elementTypeResults: TypeResults,
val componentTypeResults: TypeResults,
val dimensions: Int)
val arrayClass = arrayType.classifier.owner
if (arrayClass !is IrClass) {
error("Unexpected owner type for array type: ${arrayClass.javaClass}")
return extractErrorType()
/**
* `t` is somewhere in a stack of array types, or possibly the
* element type of the innermost array. For example, in
* `Array<Array<Int>>`, we will be called with `t` being
* `Array<Array<Int>>`, then `Array<Int>`, then `Int`.
* `isPrimitiveArray` is true if we are immediately nested
* inside a primitive array.
*/
private fun useArrayType(t: IrType, isPrimitiveArray: Boolean): ArrayInfo {
if (!t.isBoxedArray && !t.isPrimitiveArray()) {
val nullableT = if (t.isPrimitiveType() && !isPrimitiveArray) t.makeNullable() else t
val typeResults = useType(nullableT)
return ArrayInfo(typeResults, typeResults, 0)
}
// Ensure we extract Array<Int> as Integer[], not int[], for example:
fun nullableIfNotPrimitive(type: IrType) = if (type.isPrimitiveType() && !isPrimitiveArray) type.makeNullable() else type
if (t !is IrSimpleType) {
logger.error("Unexpected non-simple array type: ${t.javaClass}")
return ArrayInfo(extractErrorType(), extractErrorType(), 0)
}
val componentTypeResults = useType(nullableIfNotPrimitive(componentType))
val elementTypeLabel = useType(nullableIfNotPrimitive(elementType)).javaResult.id
val arrayClass = t.classifier.owner
if (arrayClass !is IrClass) {
logger.error("Unexpected owner type for array type: ${arrayClass.javaClass}")
return ArrayInfo(extractErrorType(), extractErrorType(), 0)
}
val javaShortName = componentTypeResults.javaResult.shortName + "[]"
// Because Java's arrays are covariant, Kotlin will render
// Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
val elementType = if ((t.arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
pluginContext.irBuiltIns.anyType
} else {
t.getArrayElementType(pluginContext.irBuiltIns)
}
val recInfo = useArrayType(elementType, t.isPrimitiveArray())
val javaShortName = recInfo.componentTypeResults.javaResult.shortName + "[]"
val kotlinShortName = recInfo.componentTypeResults.kotlinResult.shortName + "[]"
val elementTypeLabel = recInfo.elementTypeResults.javaResult.id
val componentTypeLabel = recInfo.componentTypeResults.javaResult.id
val dimensions = recInfo.dimensions + 1
val id = tw.getLabelFor<DbArray>("@\"array;$dimensions;{${elementTypeLabel}}\"") {
tw.writeArrays(
@@ -561,9 +592,9 @@ open class KotlinUsesExtractor(
javaShortName,
elementTypeLabel,
dimensions,
componentTypeResults.javaResult.id)
componentTypeLabel)
extractClassSupertypes(arrayClass, it, ExtractSupertypesMode.Specialised(arrayType.arguments))
extractClassSupertypes(arrayClass, it, ExtractSupertypesMode.Specialised(t.arguments))
// array.length
val length = tw.getLabelFor<DbField>("@\"field;{$it};length\"")
@@ -574,7 +605,7 @@ open class KotlinUsesExtractor(
// Note we will only emit one `clone()` method per Java array type, so we choose `Array<C?>` as its Kotlin
// return type, where C is the component type with any nested arrays themselves invariant and nullable.
val kotlinCloneReturnType = getInvariantNullableArrayType(arrayType).makeNullable()
val kotlinCloneReturnType = getInvariantNullableArrayType(t).makeNullable()
val kotlinCloneReturnTypeLabel = useType(kotlinCloneReturnType).kotlinResult.id
val clone = tw.getLabelFor<DbMethod>("@\"callable;{$it}.clone(){$it}\"")
@@ -585,11 +616,15 @@ open class KotlinUsesExtractor(
val javaResult = TypeResult(
id,
componentTypeResults.javaResult.signature + "[]",
recInfo.componentTypeResults.javaResult.signature + "[]",
javaShortName)
val kotlinResult = TypeResult(
fakeKotlinType(),
recInfo.componentTypeResults.kotlinResult.signature + "[]",
kotlinShortName)
val typeResults = TypeResults(javaResult, kotlinResult)
val arrayClassResult = useSimpleTypeClass(arrayClass, arrayType.arguments, arrayType.hasQuestionMark)
return TypeResults(javaResult, arrayClassResult.kotlinResult)
return ArrayInfo(recInfo.elementTypeResults, typeResults, dimensions)
}
enum class TypeContext {
@@ -662,45 +697,8 @@ open class KotlinUsesExtractor(
}
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
fun replaceComponentTypeWithAny(t: IrSimpleType, dimensions: Int): IrType =
if (dimensions == 0)
pluginContext.irBuiltIns.anyType
else
t.toBuilder().also { it.arguments = (it.arguments[0] as IrTypeProjection)
.let { oldArg ->
listOf(makeTypeProjection(replaceComponentTypeWithAny(oldArg.type as IrSimpleType, dimensions - 1), oldArg.variance))
}
}.buildSimpleType()
var componentType: IrType = s.getArrayElementType(pluginContext.irBuiltIns)
var isPrimitiveArray = false
var dimensions = 0
var elementType: IrType = s
while (elementType.isBoxedArray || elementType.isPrimitiveArray()) {
dimensions++
if (elementType.isPrimitiveArray())
isPrimitiveArray = true
if (elementType is IrSimpleType) {
if ((elementType.arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
// Because Java's arrays are covariant, Kotlin will render Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
componentType = replaceComponentTypeWithAny(s, dimensions - 1)
elementType = pluginContext.irBuiltIns.anyType
break
}
} else {
logger.warn("Unexpected element type representation ${elementType.javaClass} for ${s.render()}")
}
elementType = elementType.getArrayElementType(pluginContext.irBuiltIns)
}
return useArrayType(
s,
componentType,
elementType,
dimensions,
isPrimitiveArray
)
val arrayInfo = useArrayType(s, false)
return arrayInfo.componentTypeResults
}
owner is IrClass -> {