Fix .equals for instantiated annotations with unsigned array types.
#KT-53876 Fixed
This commit is contained in:
committed by
Space Team
parent
0fea8073ef
commit
ccdb6fc599
+6
@@ -492,6 +492,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/annotations/instances/annotationType.kt");
|
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
|
@Test
|
||||||
@TestMetadata("inInlineFunction.kt")
|
@TestMetadata("inInlineFunction.kt")
|
||||||
public void testInInlineFunction() throws Exception {
|
public void testInInlineFunction() throws Exception {
|
||||||
|
|||||||
+18
-10
@@ -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()
|
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 {
|
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||||
val constructedClass = expression.type.classOrNull?.owner ?: return super.visitConstructorCall(expression)
|
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 ->
|
destination.symbol.owner.valueParameters.forEachIndexed { index, parameter ->
|
||||||
val valueArg = argumentsByName[parameter.name]
|
val valueArg = argumentsByName[parameter.name]
|
||||||
if (parameter.defaultValue == null && valueArg == null)
|
if (parameter.defaultValue == null && valueArg == null)
|
||||||
error("Usage of default value argument for this annotation is not yet possible.\n" +
|
error(
|
||||||
"Please specify value for '${source.type.classOrNull?.owner?.name}.${parameter.name}' explicitly")
|
"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)
|
destination.putValueArgument(index, valueArg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,18 +162,22 @@ abstract class AnnotationImplementationTransformer(val context: BackendContext,
|
|||||||
|
|
||||||
abstract fun getArrayContentEqualsSymbol(type: IrType): IrFunctionSymbol
|
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 =
|
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 requiredSymbol = getArrayContentEqualsSymbol(type)
|
||||||
|
val lhs = arg1.transformArrayEqualsArgument(type, irBuilder)
|
||||||
|
val rhs = arg2.transformArrayEqualsArgument(type, irBuilder)
|
||||||
irBuilder.irCall(
|
irBuilder.irCall(
|
||||||
requiredSymbol
|
requiredSymbol
|
||||||
).apply {
|
).apply {
|
||||||
if (requiredSymbol.owner.extensionReceiverParameter != null) {
|
if (requiredSymbol.owner.extensionReceiverParameter != null) {
|
||||||
extensionReceiver = arg1
|
extensionReceiver = lhs
|
||||||
putValueArgument(0, arg2)
|
putValueArgument(0, rhs)
|
||||||
} else {
|
} else {
|
||||||
putValueArgument(0, arg1)
|
putValueArgument(0, lhs)
|
||||||
putValueArgument(1, arg2)
|
putValueArgument(1, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -220,7 +227,7 @@ class AnnotationImplementationMemberGenerator(
|
|||||||
irClass: IrClass,
|
irClass: IrClass,
|
||||||
val nameForToString: String,
|
val nameForToString: String,
|
||||||
forbidDirectFieldAccess: Boolean,
|
forbidDirectFieldAccess: Boolean,
|
||||||
val selectEquals: IrBlockBodyBuilder.(IrType, IrExpression, IrExpression) -> IrExpression,
|
val selectEquals: IrBlockBodyBuilder.(IrType, IrExpression, IrExpression) -> IrExpression
|
||||||
) : LoweringDataClassMemberGenerator(backendContext, irClass, ANNOTATION_IMPLEMENTATION, forbidDirectFieldAccess) {
|
) : LoweringDataClassMemberGenerator(backendContext, irClass, ANNOTATION_IMPLEMENTATION, forbidDirectFieldAccess) {
|
||||||
|
|
||||||
override fun IrClass.classNameForToString(): String = nameForToString
|
override fun IrClass.classNameForToString(): String = nameForToString
|
||||||
@@ -263,3 +270,4 @@ class AnnotationImplementationMemberGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.types.IrType
|
|||||||
import org.jetbrains.kotlin.ir.types.isArray
|
import org.jetbrains.kotlin.ir.types.isArray
|
||||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||||
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
||||||
|
import org.jetbrains.kotlin.ir.util.isUnsignedArray
|
||||||
|
|
||||||
|
|
||||||
// JS PIR (and IC) requires DeclarationTransformer instead of FileLoweringPass
|
// JS PIR (and IC) requires DeclarationTransformer instead of FileLoweringPass
|
||||||
@@ -53,7 +54,7 @@ class JsAnnotationImplementationTransformer(val jsContext: JsIrBackendContext) :
|
|||||||
|
|
||||||
override fun getArrayContentEqualsSymbol(type: IrType) =
|
override fun getArrayContentEqualsSymbol(type: IrType) =
|
||||||
when {
|
when {
|
||||||
type.isPrimitiveArray() -> arraysContentEquals[type]
|
type.isPrimitiveArray() || type.isUnsignedArray() -> arraysContentEquals[type]
|
||||||
else -> arraysContentEquals.entries.singleOrNull { (k, _) -> k.isArray() }?.value
|
else -> arraysContentEquals.entries.singleOrNull { (k, _) -> k.isArray() }?.value
|
||||||
} ?: compilationException("Can't find an Arrays.contentEquals method for array type", type)
|
} ?: compilationException("Can't find an Arrays.contentEquals method for array type", type)
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -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.createJvmIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
|
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.javaClassReference
|
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.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
@@ -134,8 +135,22 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext,
|
|||||||
return block
|
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 {
|
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> {
|
val requiredSymbol = jvmContext.ir.symbols.arraysClass.owner.findDeclaration<IrFunction> {
|
||||||
it.name.asString() == "equals" && it.valueParameters.size == 2 && it.valueParameters.first().type == targetType
|
it.name.asString() == "equals" && it.valueParameters.size == 2 && it.valueParameters.first().type == targetType
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -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"
|
||||||
|
}
|
||||||
+6
@@ -456,6 +456,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
|
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
|
@Test
|
||||||
@TestMetadata("inInlineFunction.kt")
|
@TestMetadata("inInlineFunction.kt")
|
||||||
public void testInInlineFunction() throws Exception {
|
public void testInInlineFunction() throws Exception {
|
||||||
|
|||||||
+6
@@ -492,6 +492,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/annotations/instances/annotationType.kt");
|
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
|
@Test
|
||||||
@TestMetadata("inInlineFunction.kt")
|
@TestMetadata("inInlineFunction.kt")
|
||||||
public void testInInlineFunction() throws Exception {
|
public void testInInlineFunction() throws Exception {
|
||||||
|
|||||||
+5
@@ -395,6 +395,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
|
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")
|
@TestMetadata("inInlineFunction.kt")
|
||||||
public void ignoreInInlineFunction() throws Exception {
|
public void ignoreInInlineFunction() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/annotations/instances/inInlineFunction.kt");
|
runTest("compiler/testData/codegen/box/annotations/instances/inInlineFunction.kt");
|
||||||
|
|||||||
+6
@@ -120,6 +120,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
|
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
|
@Test
|
||||||
@TestMetadata("inInlineFunction.kt")
|
@TestMetadata("inInlineFunction.kt")
|
||||||
public void testInInlineFunction() throws Exception {
|
public void testInInlineFunction() throws Exception {
|
||||||
|
|||||||
+5
@@ -123,6 +123,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
|
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")
|
@TestMetadata("inInlineFunction.kt")
|
||||||
public void testInInlineFunction() throws Exception {
|
public void testInInlineFunction() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/annotations/instances/inInlineFunction.kt");
|
runTest("compiler/testData/codegen/box/annotations/instances/inInlineFunction.kt");
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ internal class NativeAnnotationImplementationTransformer(context: Context, irFil
|
|||||||
|
|
||||||
override fun getArrayContentEqualsSymbol(type: IrType) =
|
override fun getArrayContentEqualsSymbol(type: IrType) =
|
||||||
when {
|
when {
|
||||||
type.isPrimitiveArray() -> arrayContentEqualsMap[type]
|
type.isPrimitiveArray() || type.isUnsignedArray() -> arrayContentEqualsMap[type]
|
||||||
else -> arrayContentEqualsMap.entries.singleOrNull { (k, _) -> k.isArray() }?.value
|
else -> arrayContentEqualsMap.entries.singleOrNull { (k, _) -> k.isArray() }?.value
|
||||||
} ?: error("Can't find an Arrays.contentEquals method for array type ${type.render()}")
|
} ?: error("Can't find an Arrays.contentEquals method for array type ${type.render()}")
|
||||||
|
|
||||||
|
|||||||
+6
@@ -132,6 +132,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
|
|||||||
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
|
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
|
@Test
|
||||||
@TestMetadata("inInlineFunction.kt")
|
@TestMetadata("inInlineFunction.kt")
|
||||||
public void testInInlineFunction() throws Exception {
|
public void testInInlineFunction() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user