diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index bb8c7ab5505..77c6c16b8fc 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -818,6 +818,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @Test + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @Test @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt index b3bf39aeaef..ae79576e1ef 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrUninitializedType import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.pureEndOffset import org.jetbrains.kotlin.psi.psiUtil.pureStartOffset import org.jetbrains.kotlin.psi2ir.isConstructorDelegatingToSuper @@ -378,7 +379,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio descriptor, descriptor.type.toIrType(), (descriptor as? ValueParameterDescriptor)?.varargElementType?.toIrType(), name - ) + ) private fun generateDefaultAnnotationParameterValue( valueExpression: KtExpression, @@ -387,11 +388,9 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio val constantDefaultValue = ConstantExpressionEvaluator.getConstant(valueExpression, context.bindingContext)?.toConstantValue(valueParameterDescriptor.type) ?: error("Constant value expected for default parameter value in annotation, got $valueExpression") - return context.irFactory.createExpressionBody( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - context.constantValueGenerator.generateConstantValueAsExpression( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, constantDefaultValue, valueParameterDescriptor.varargElementType - ) - ) + val converted = context.constantValueGenerator.generateAnnotationValueAsExpression( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, constantDefaultValue, valueParameterDescriptor + ) ?: error("Could not convert annotation default ${valueExpression.getElementTextWithContext()}") + return context.irFactory.createExpressionBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, converted) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt index cab9b887c48..b97d304d98d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt @@ -36,23 +36,32 @@ abstract class ConstantValueGenerator( startOffset: Int, endOffset: Int, constantValue: ConstantValue<*>, - varargElementType: KotlinType? = null ): IrExpression = // Assertion is safe here because annotation calls and class literals are not allowed in constant initializers - generateConstantOrAnnotationValueAsExpression(startOffset, endOffset, constantValue, null, varargElementType)!! + 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<*>, - realType: KotlinType?, - varargElementType: KotlinType? = null + expectedType: KotlinType?, + expectedArrayElementType: KotlinType? ): IrExpression? { val constantValueType = constantValue.getType(moduleDescriptor) - val constantKtType = realType ?: constantValueType + val constantKtType = expectedType ?: constantValueType val constantType = constantKtType.toIrType() return when (constantValue) { @@ -72,18 +81,27 @@ abstract class ConstantValueGenerator( is UShortValue -> IrConstImpl.short(startOffset, endOffset, constantType, constantValue.value) is ArrayValue -> { - val arrayElementType = varargElementType ?: constantValueType.getArrayElementType() + // 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, constantType, arrayElementType.toIrType(), constantValue.value.mapNotNull { - generateConstantOrAnnotationValueAsExpression(startOffset, endOffset, it, arrayElementType) + // For annotation arguments, the type of every subexpression can be inferred from the type of the parameter; + // for arbitrary constants, we should always take the type inferred by the frontend. + val newExpectedType = arrayElementType.takeIf { expectedType != null } + generateConstantOrAnnotationValueAsExpression(startOffset, endOffset, it, newExpectedType, null) } ) } is EnumValue -> { + // TODO: in `annotationWithKotlinProperty`, `@Foo(KotlinClass.FOO_INT)` is parsed as if `KotlinClass.FOO_INT` + // is an EnumValue when it's a read of a `const val` with an Int type. Not using `expectedType` somewhat masks + // that - we silently fail to translate the argument because `enumEntryDescriptor` is an error class. val enumEntryDescriptor = constantValueType.memberScope.getContributedClassifier(constantValue.enumEntryName, NoLookupLocation.FROM_BACKEND) ?: throw AssertionError("No such enum entry ${constantValue.enumEntryName} in $constantType") @@ -169,16 +187,9 @@ abstract class ConstantValueGenerator( for (valueParameter in substitutedConstructor.valueParameters) { val argumentIndex = valueParameter.index val argumentValue = annotationDescriptor.allValueArguments[valueParameter.name] ?: continue - val irArgument = generateConstantOrAnnotationValueAsExpression( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - adjustAnnotationArgumentValue(argumentValue, valueParameter), - valueParameter.type, - valueParameter.varargElementType - ) - if (irArgument != null) { - irCall.putValueArgument(argumentIndex, irArgument) - } + val adjustedValue = adjustAnnotationArgumentValue(argumentValue, valueParameter) + val irArgument = generateAnnotationValueAsExpression(UNDEFINED_OFFSET, UNDEFINED_OFFSET, adjustedValue, valueParameter) + irCall.putValueArgument(argumentIndex, irArgument) } return irCall diff --git a/compiler/testData/codegen/box/arrays/constantArrayOfAny.kt b/compiler/testData/codegen/box/arrays/constantArrayOfAny.kt new file mode 100644 index 00000000000..ab5580f1f7f --- /dev/null +++ b/compiler/testData/codegen/box/arrays/constantArrayOfAny.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +val x: Any = arrayOf(arrayOf("OK")) + +fun box(): String = ((x as Array)[0] as Array)[0] diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 835b8823e97..920ebf6fb39 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -746,6 +746,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @Test + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @Test @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 2fdf6554b45..14c845e4a4f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -818,6 +818,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @Test + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @Test @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index ae177d4ca4f..e0975ba0950 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -668,6 +668,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { runTest("compiler/testData/codegen/box/arrays/forEachBooleanArray.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 8098a67d553..095301a3aca 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -323,6 +323,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { runTest("compiler/testData/codegen/box/arrays/forEachBooleanArray.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 93b136dedfc..22034dff0a4 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -323,6 +323,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { runTest("compiler/testData/codegen/box/arrays/forEachBooleanArray.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 3c71c17454c..e30d89f74ca 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -303,6 +303,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { runTest("compiler/testData/codegen/box/arrays/forEachBooleanArray.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsLegacyPrimitiveArraysBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsLegacyPrimitiveArraysBoxTestGenerated.java index 4fc313a8706..86082628ae2 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsLegacyPrimitiveArraysBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsLegacyPrimitiveArraysBoxTestGenerated.java @@ -85,6 +85,11 @@ public class JsLegacyPrimitiveArraysBoxTestGenerated extends AbstractJsLegacyPri runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt"); } + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { runTest("compiler/testData/codegen/box/arrays/forEachBooleanArray.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index b38596f2f63..645df21ba38 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -293,6 +293,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/arrays/arrayPlusAssign.kt"); } + @TestMetadata("constantArrayOfAny.kt") + public void testConstantArrayOfAny() throws Exception { + runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt"); + } + @TestMetadata("forEachBooleanArray.kt") public void testForEachBooleanArray() throws Exception { runTest("compiler/testData/codegen/box/arrays/forEachBooleanArray.kt");