Repository: JetBrains/kotlin
File: compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt (Kotlin)

Code before:
    ): IrExpression =
        // Assertion is safe here because annotation calls and class literals are not allowed in constant initializers
        generateConstantOrAnnotationValueAsExpression(startOffset, endOffset, constantValue, null, null)!!

    /**
     * @return null if the constant value is an unresolved annotation or an unresolved class literal
     */
    fun generateAnnotationValueAsExpression(
        startOffset: Int,
        endOffset: Int,
        constantValue: ConstantValue<*>,
        valueParameter: ValueParameterDescriptor,
    ): IrExpression? =
        generateConstantOrAnnotationValueAsExpression(
            startOffset, endOffset, constantValue, valueParameter.type, valueParameter.varargElementType
        )

    private fun generateConstantOrAnnotationValueAsExpression(
        startOffset: Int,
        endOffset: Int,
        constantValue: ConstantValue<*>,
        inferredType: KotlinType?,
        inferredArrayElementType: KotlinType?
    ): IrExpression? {
        val constantValueType = constantValue.getType(moduleDescriptor)
        val constantKtType = inferredType ?: constantValueType
        val constantType = constantKtType.toIrType()

        return when (constantValue) {
            is StringValue -> IrConstImpl.string(startOffset, endOffset, constantType, constantValue.value)
            is IntValue -> IrConstImpl.int(startOffset, endOffset, constantType, constantValue.value)
            is UIntValue -> IrConstImpl.int(startOffset, endOffset, constantType, constantValue.value)
            is NullValue -> IrConstImpl.constNull(startOffset, endOffset, constantType)
            is BooleanValue -> IrConstImpl.boolean(startOffset, endOffset, constantType, constantValue.value)
            is LongValue -> IrConstImpl.long(startOffset, endOffset, constantType, constantValue.value)
            is ULongValue -> IrConstImpl.long(startOffset, endOffset, constantType, constantValue.value)
            is DoubleValue -> IrConstImpl.double(startOffset, endOffset, constantType, constantValue.value)
            is FloatValue -> IrConstImpl.float(startOffset, endOffset, constantType, constantValue.value)
            is CharValue -> IrConstImpl.char(startOffset, endOffset, constantType, constantValue.value)
            is ByteValue -> IrConstImpl.byte(startOffset, endOffset, constantType, constantValue.value)
            is UByteValue -> IrConstImpl.byte(startOffset, endOffset, constantType, constantValue.value)
            is ShortValue -> IrConstImpl.short(startOffset, endOffset, constantType, constantValue.value)
            is UShortValue -> IrConstImpl.short(startOffset, endOffset, constantType, constantValue.value)

            is ArrayValue -> {
                val arrayElementType = inferredArrayElementType ?: constantValueType.getArrayElementType()
                IrVarargImpl(
                    startOffset, endOffset,
                    constantType,
                    arrayElementType.toIrType(),
                    constantValue.value.mapNotNull {

Review comment (bug):
By the way, the fact that `constantValueType` is used in two places instead of `constantKtType` hints at incorrect generation for annotations too:

 * in spreadOperatorInAnnotationArguments, `@A(*arrayOf("a"), *arrayOf("b"))` is translated into `A(xs = [['a'], ['b']])` instead of `A(xs = ['a', 'b'])` - this is an IrText test even, so you can see that in the test data;
 * in annotationWithKotlinProperty, `@Foo(KotlinClass.FOO_INT)` is parsed as if `KotlinClass.FOO_INT` is an enum value - except it's really a `const val` with a type of `Int`, so we just silently fail to translate the argument.

Code after:
    ): IrExpression =
        // Assertion is safe here because annotation calls and class literals are not allowed in constant initializers
        generateConstantOrAnnotationValueAsExpression(startOffset, endOffset, constantValue, null, null)!!

    /**
     * @return null if the constant value is an unresolved annotation or an unresolved class literal
     */
    fun generateAnnotationValueAsExpression(
        startOffset: Int,
        endOffset: Int,
        constantValue: ConstantValue<*>,
        valueParameter: ValueParameterDescriptor,
    ): IrExpression? =
        generateConstantOrAnnotationValueAsExpression(
            startOffset, endOffset, constantValue, valueParameter.type, valueParameter.varargElementType
        )

    private fun generateConstantOrAnnotationValueAsExpression(
        startOffset: Int,
        endOffset: Int,
        constantValue: ConstantValue<*>,
        expectedType: KotlinType?,
        expectedArrayElementType: KotlinType?
    ): IrExpression? {
        val constantValueType = constantValue.getType(moduleDescriptor)
        val constantKtType = expectedType ?: constantValueType
        val constantType = constantKtType.toIrType()

        return when (constantValue) {
            is StringValue -> IrConstImpl.string(startOffset, endOffset, constantType, constantValue.value)
            is IntValue -> IrConstImpl.int(startOffset, endOffset, constantType, constantValue.value)
            is UIntValue -> IrConstImpl.int(startOffset, endOffset, constantType, constantValue.value)
            is NullValue -> IrConstImpl.constNull(startOffset, endOffset, constantType)
            is BooleanValue -> IrConstImpl.boolean(startOffset, endOffset, constantType, constantValue.value)
            is LongValue -> IrConstImpl.long(startOffset, endOffset, constantType, constantValue.value)
            is ULongValue -> IrConstImpl.long(startOffset, endOffset, constantType, constantValue.value)
            is DoubleValue -> IrConstImpl.double(startOffset, endOffset, constantType, constantValue.value)
            is FloatValue -> IrConstImpl.float(startOffset, endOffset, constantType, constantValue.value)
            is CharValue -> IrConstImpl.char(startOffset, endOffset, constantType, constantValue.value)
            is ByteValue -> IrConstImpl.byte(startOffset, endOffset, constantType, constantValue.value)
            is UByteValue -> IrConstImpl.byte(startOffset, endOffset, constantType, constantValue.value)
            is ShortValue -> IrConstImpl.short(startOffset, endOffset, constantType, constantValue.value)
            is UShortValue -> IrConstImpl.short(startOffset, endOffset, constantType, constantValue.value)

            is ArrayValue -> {
                //  TODO: in `spreadOperatorInAnnotationArguments`, `@A(*arrayOf("a"), *arrayOf("b"))` is incorrectly
                //    translated into `A(xs = [['a'], ['b']])` instead of `A(xs = ['a', 'b'])`. Not using `expectedType`
                //    here masks that.
                val arrayElementType = expectedArrayElementType ?: constantValueType.getArrayElementType()
                IrVarargImpl(
                    startOffset, endOffset,