diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 794192c258b..0267b8536e3 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -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>`, we will be called with `t` being + * `Array>`, then `Array`, 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 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 as Object[], Array> 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("@\"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("@\"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` 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("@\"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 as Object[], Array> 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 -> {