Fix .equals for instantiated annotations with unsigned array types.

#KT-53876 Fixed
This commit is contained in:
Leonid Startsev
2022-09-28 17:19:34 +02:00
committed by Space Team
parent 0fea8073ef
commit ccdb6fc599
12 changed files with 92 additions and 13 deletions
@@ -492,6 +492,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/annotations/instances/annotationType.kt");
}
@Test
@TestMetadata("annotationsUnsignedTypes.kt")
public void testAnnotationsUnsignedTypes() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationsUnsignedTypes.kt");
}
@Test
@TestMetadata("inInlineFunction.kt")
public void testInInlineFunction() throws Exception {
@@ -42,7 +42,8 @@ class AnnotationImplementationLowering(
}
}
abstract class AnnotationImplementationTransformer(val context: BackendContext, val irFile: IrFile?) : IrElementTransformerVoidWithContext() {
abstract class AnnotationImplementationTransformer(val context: BackendContext, val irFile: IrFile?) :
IrElementTransformerVoidWithContext() {
internal val implementations: MutableMap<IrClass, IrClass> = mutableMapOf()
@@ -72,7 +73,7 @@ abstract class AnnotationImplementationTransformer(val context: BackendContext,
}
}
abstract fun chooseConstructor(implClass: IrClass, expression: IrConstructorCall) : IrConstructor
abstract fun chooseConstructor(implClass: IrClass, expression: IrConstructorCall): IrConstructor
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
val constructedClass = expression.type.classOrNull?.owner ?: return super.visitConstructorCall(expression)
@@ -104,8 +105,10 @@ abstract class AnnotationImplementationTransformer(val context: BackendContext,
destination.symbol.owner.valueParameters.forEachIndexed { index, parameter ->
val valueArg = argumentsByName[parameter.name]
if (parameter.defaultValue == null && valueArg == null)
error("Usage of default value argument for this annotation is not yet possible.\n" +
"Please specify value for '${source.type.classOrNull?.owner?.name}.${parameter.name}' explicitly")
error(
"Usage of default value argument for this annotation is not yet possible.\n" +
"Please specify value for '${source.type.classOrNull?.owner?.name}.${parameter.name}' explicitly"
)
destination.putValueArgument(index, valueArg)
}
}
@@ -159,18 +162,22 @@ abstract class AnnotationImplementationTransformer(val context: BackendContext,
abstract fun getArrayContentEqualsSymbol(type: IrType): IrFunctionSymbol
open fun IrExpression.transformArrayEqualsArgument(type: IrType, irBuilder: IrBlockBodyBuilder): IrExpression = this
fun generatedEquals(irBuilder: IrBlockBodyBuilder, type: IrType, arg1: IrExpression, arg2: IrExpression): IrExpression =
if (type.isArray() || type.isPrimitiveArray()) {
if (type.isArray() || type.isPrimitiveArray() || type.isUnsignedArray()) {
val requiredSymbol = getArrayContentEqualsSymbol(type)
val lhs = arg1.transformArrayEqualsArgument(type, irBuilder)
val rhs = arg2.transformArrayEqualsArgument(type, irBuilder)
irBuilder.irCall(
requiredSymbol
).apply {
if (requiredSymbol.owner.extensionReceiverParameter != null) {
extensionReceiver = arg1
putValueArgument(0, arg2)
extensionReceiver = lhs
putValueArgument(0, rhs)
} else {
putValueArgument(0, arg1)
putValueArgument(1, arg2)
putValueArgument(0, lhs)
putValueArgument(1, rhs)
}
}
} else
@@ -220,7 +227,7 @@ class AnnotationImplementationMemberGenerator(
irClass: IrClass,
val nameForToString: String,
forbidDirectFieldAccess: Boolean,
val selectEquals: IrBlockBodyBuilder.(IrType, IrExpression, IrExpression) -> IrExpression,
val selectEquals: IrBlockBodyBuilder.(IrType, IrExpression, IrExpression) -> IrExpression
) : LoweringDataClassMemberGenerator(backendContext, irClass, ANNOTATION_IMPLEMENTATION, forbidDirectFieldAccess) {
override fun IrClass.classNameForToString(): String = nameForToString
@@ -263,3 +270,4 @@ class AnnotationImplementationMemberGenerator(
}
}
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.kotlin.ir.util.isAnnotationClass
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
import org.jetbrains.kotlin.ir.util.isUnsignedArray
// JS PIR (and IC) requires DeclarationTransformer instead of FileLoweringPass
@@ -53,7 +54,7 @@ class JsAnnotationImplementationTransformer(val jsContext: JsIrBackendContext) :
override fun getArrayContentEqualsSymbol(type: IrType) =
when {
type.isPrimitiveArray() -> arraysContentEquals[type]
type.isPrimitiveArray() || type.isUnsignedArray() -> arraysContentEquals[type]
else -> arraysContentEquals.entries.singleOrNull { (k, _) -> k.isArray() }?.value
} ?: compilationException("Can't find an Arrays.contentEquals method for array type", type)
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
import org.jetbrains.kotlin.backend.jvm.ir.javaClassReference
import org.jetbrains.kotlin.backend.jvm.unboxInlineClass
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.builders.*
@@ -134,8 +135,22 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext,
return block
}
// There's no specialized Array.equals for unsigned arrays (as this is a Java function), so we force compiler not to box
// result of property getter call
override fun IrExpression.transformArrayEqualsArgument(type: IrType, irBuilder: IrBlockBodyBuilder): IrExpression =
if (!type.isUnsignedArray()) this
else irBuilder.irCall(jvmContext.ir.symbols.unsafeCoerceIntrinsic).apply {
putTypeArgument(0, type)
putTypeArgument(1, type.unboxInlineClass())
putValueArgument(0, this@transformArrayEqualsArgument)
}
override fun getArrayContentEqualsSymbol(type: IrType): IrFunctionSymbol {
val targetType = if (type.isPrimitiveArray()) type else jvmContext.ir.symbols.arrayOfAnyNType
val targetType = when {
type.isPrimitiveArray() -> type
type.isUnsignedArray() -> type.unboxInlineClass()
else -> jvmContext.ir.symbols.arrayOfAnyNType
}
val requiredSymbol = jvmContext.ir.symbols.arraysClass.owner.findDeclaration<IrFunction> {
it.name.asString() == "equals" && it.valueParameters.size == 2 && it.valueParameters.first().type == targetType
}
@@ -0,0 +1,15 @@
// IGNORE_BACKEND: JVM
// IGNORE_BACKEND: WASM
// DONT_TARGET_EXACT_BACKEND: JS
// WITH_STDLIB
// !LANGUAGE: +InstantiationOfAnnotationClasses
annotation class AnnotationWithSignedArray(val array: IntArray)
annotation class AnnotationWithUnsignedArray(val array: UIntArray)
fun box(): String {
if (!(AnnotationWithSignedArray(intArrayOf()) == AnnotationWithSignedArray(intArrayOf()))) return "Fail signed"
if (!(AnnotationWithUnsignedArray(uintArrayOf()) == AnnotationWithUnsignedArray(uintArrayOf()))) return "Fail unsigned"
return "OK"
}
@@ -456,6 +456,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
}
@Test
@TestMetadata("annotationsUnsignedTypes.kt")
public void testAnnotationsUnsignedTypes() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationsUnsignedTypes.kt");
}
@Test
@TestMetadata("inInlineFunction.kt")
public void testInInlineFunction() throws Exception {
@@ -492,6 +492,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/annotations/instances/annotationType.kt");
}
@Test
@TestMetadata("annotationsUnsignedTypes.kt")
public void testAnnotationsUnsignedTypes() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationsUnsignedTypes.kt");
}
@Test
@TestMetadata("inInlineFunction.kt")
public void testInInlineFunction() throws Exception {
@@ -395,6 +395,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
}
@TestMetadata("annotationsUnsignedTypes.kt")
public void ignoreAnnotationsUnsignedTypes() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationsUnsignedTypes.kt");
}
@TestMetadata("inInlineFunction.kt")
public void ignoreInInlineFunction() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/inInlineFunction.kt");
@@ -120,6 +120,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
}
@Test
@TestMetadata("annotationsUnsignedTypes.kt")
public void testAnnotationsUnsignedTypes() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationsUnsignedTypes.kt");
}
@Test
@TestMetadata("inInlineFunction.kt")
public void testInInlineFunction() throws Exception {
@@ -123,6 +123,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
}
@TestMetadata("annotationsUnsignedTypes.kt")
public void testAnnotationsUnsignedTypes() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationsUnsignedTypes.kt");
}
@TestMetadata("inInlineFunction.kt")
public void testInInlineFunction() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/inInlineFunction.kt");
@@ -26,7 +26,7 @@ internal class NativeAnnotationImplementationTransformer(context: Context, irFil
override fun getArrayContentEqualsSymbol(type: IrType) =
when {
type.isPrimitiveArray() -> arrayContentEqualsMap[type]
type.isPrimitiveArray() || type.isUnsignedArray() -> arrayContentEqualsMap[type]
else -> arrayContentEqualsMap.entries.singleOrNull { (k, _) -> k.isArray() }?.value
} ?: error("Can't find an Arrays.contentEquals method for array type ${type.render()}")
@@ -132,6 +132,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
}
@Test
@TestMetadata("annotationsUnsignedTypes.kt")
public void testAnnotationsUnsignedTypes() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationsUnsignedTypes.kt");
}
@Test
@TestMetadata("inInlineFunction.kt")
public void testInInlineFunction() throws Exception {