Skip to content

Commit 89fc84d

Browse files
authored
Merge pull request github#10322 from igfoo/igfoo/arrays2
Kotlin: Rewrite array type extraction
2 parents 6bee9d8 + 5c3d6ce commit 89fc84d

File tree

1 file changed

+52
-54
lines changed

1 file changed

+52
-54
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -539,31 +539,62 @@ open class KotlinUsesExtractor(
539539
)
540540
}
541541

542-
private fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int, isPrimitiveArray: Boolean): TypeResults {
542+
data class ArrayInfo(val elementTypeResults: TypeResults,
543+
val componentTypeResults: TypeResults,
544+
val dimensions: Int)
543545

544-
val arrayClass = arrayType.classifier.owner
546+
/**
547+
* `t` is somewhere in a stack of array types, or possibly the
548+
* element type of the innermost array. For example, in
549+
* `Array<Array<Int>>`, we will be called with `t` being
550+
* `Array<Array<Int>>`, then `Array<Int>`, then `Int`.
551+
* `isPrimitiveArray` is true if we are immediately nested
552+
* inside a primitive array.
553+
*/
554+
private fun useArrayType(t: IrType, isPrimitiveArray: Boolean): ArrayInfo {
555+
556+
if (!t.isBoxedArray && !t.isPrimitiveArray()) {
557+
val nullableT = if (t.isPrimitiveType() && !isPrimitiveArray) t.makeNullable() else t
558+
val typeResults = useType(nullableT)
559+
return ArrayInfo(typeResults, typeResults, 0)
560+
}
561+
562+
if (t !is IrSimpleType) {
563+
logger.error("Unexpected non-simple array type: ${t.javaClass}")
564+
return ArrayInfo(extractErrorType(), extractErrorType(), 0)
565+
}
566+
567+
val arrayClass = t.classifier.owner
545568
if (arrayClass !is IrClass) {
546-
error("Unexpected owner type for array type: ${arrayClass.javaClass}")
547-
return extractErrorType()
569+
logger.error("Unexpected owner type for array type: ${arrayClass.javaClass}")
570+
return ArrayInfo(extractErrorType(), extractErrorType(), 0)
548571
}
549572

550-
// Ensure we extract Array<Int> as Integer[], not int[], for example:
551-
fun nullableIfNotPrimitive(type: IrType) = if (type.isPrimitiveType() && !isPrimitiveArray) type.makeNullable() else type
573+
// Because Java's arrays are covariant, Kotlin will render
574+
// Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
575+
val elementType = if ((t.arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
576+
pluginContext.irBuiltIns.anyType
577+
} else {
578+
t.getArrayElementType(pluginContext.irBuiltIns)
579+
}
552580

553-
val componentTypeResults = useType(nullableIfNotPrimitive(componentType))
554-
val elementTypeLabel = useType(nullableIfNotPrimitive(elementType)).javaResult.id
581+
val recInfo = useArrayType(elementType, t.isPrimitiveArray())
555582

556-
val javaShortName = componentTypeResults.javaResult.shortName + "[]"
583+
val javaShortName = recInfo.componentTypeResults.javaResult.shortName + "[]"
584+
val kotlinShortName = recInfo.componentTypeResults.kotlinResult.shortName + "[]"
585+
val elementTypeLabel = recInfo.elementTypeResults.javaResult.id
586+
val componentTypeLabel = recInfo.componentTypeResults.javaResult.id
587+
val dimensions = recInfo.dimensions + 1
557588

558589
val id = tw.getLabelFor<DbArray>("@\"array;$dimensions;{${elementTypeLabel}}\"") {
559590
tw.writeArrays(
560591
it,
561592
javaShortName,
562593
elementTypeLabel,
563594
dimensions,
564-
componentTypeResults.javaResult.id)
595+
componentTypeLabel)
565596

566-
extractClassSupertypes(arrayClass, it, ExtractSupertypesMode.Specialised(arrayType.arguments))
597+
extractClassSupertypes(arrayClass, it, ExtractSupertypesMode.Specialised(t.arguments))
567598

568599
// array.length
569600
val length = tw.getLabelFor<DbField>("@\"field;{$it};length\"")
@@ -574,7 +605,7 @@ open class KotlinUsesExtractor(
574605

575606
// Note we will only emit one `clone()` method per Java array type, so we choose `Array<C?>` as its Kotlin
576607
// return type, where C is the component type with any nested arrays themselves invariant and nullable.
577-
val kotlinCloneReturnType = getInvariantNullableArrayType(arrayType).makeNullable()
608+
val kotlinCloneReturnType = getInvariantNullableArrayType(t).makeNullable()
578609
val kotlinCloneReturnTypeLabel = useType(kotlinCloneReturnType).kotlinResult.id
579610

580611
val clone = tw.getLabelFor<DbMethod>("@\"callable;{$it}.clone(){$it}\"")
@@ -585,11 +616,15 @@ open class KotlinUsesExtractor(
585616

586617
val javaResult = TypeResult(
587618
id,
588-
componentTypeResults.javaResult.signature + "[]",
619+
recInfo.componentTypeResults.javaResult.signature + "[]",
589620
javaShortName)
621+
val kotlinResult = TypeResult(
622+
fakeKotlinType(),
623+
recInfo.componentTypeResults.kotlinResult.signature + "[]",
624+
kotlinShortName)
625+
val typeResults = TypeResults(javaResult, kotlinResult)
590626

591-
val arrayClassResult = useSimpleTypeClass(arrayClass, arrayType.arguments, arrayType.hasQuestionMark)
592-
return TypeResults(javaResult, arrayClassResult.kotlinResult)
627+
return ArrayInfo(recInfo.elementTypeResults, typeResults, dimensions)
593628
}
594629

595630
enum class TypeContext {
@@ -662,45 +697,8 @@ open class KotlinUsesExtractor(
662697
}
663698

664699
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
665-
666-
fun replaceComponentTypeWithAny(t: IrSimpleType, dimensions: Int): IrType =
667-
if (dimensions == 0)
668-
pluginContext.irBuiltIns.anyType
669-
else
670-
t.toBuilder().also { it.arguments = (it.arguments[0] as IrTypeProjection)
671-
.let { oldArg ->
672-
listOf(makeTypeProjection(replaceComponentTypeWithAny(oldArg.type as IrSimpleType, dimensions - 1), oldArg.variance))
673-
}
674-
}.buildSimpleType()
675-
676-
var componentType: IrType = s.getArrayElementType(pluginContext.irBuiltIns)
677-
var isPrimitiveArray = false
678-
var dimensions = 0
679-
var elementType: IrType = s
680-
while (elementType.isBoxedArray || elementType.isPrimitiveArray()) {
681-
dimensions++
682-
if (elementType.isPrimitiveArray())
683-
isPrimitiveArray = true
684-
if (elementType is IrSimpleType) {
685-
if ((elementType.arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
686-
// Because Java's arrays are covariant, Kotlin will render Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
687-
componentType = replaceComponentTypeWithAny(s, dimensions - 1)
688-
elementType = pluginContext.irBuiltIns.anyType
689-
break
690-
}
691-
} else {
692-
logger.warn("Unexpected element type representation ${elementType.javaClass} for ${s.render()}")
693-
}
694-
elementType = elementType.getArrayElementType(pluginContext.irBuiltIns)
695-
}
696-
697-
return useArrayType(
698-
s,
699-
componentType,
700-
elementType,
701-
dimensions,
702-
isPrimitiveArray
703-
)
700+
val arrayInfo = useArrayType(s, false)
701+
return arrayInfo.componentTypeResults
704702
}
705703

706704
owner is IrClass -> {

0 commit comments

Comments
 (0)