IR: do not infer array element types for non-annotation constants

While annotations restrict the set of allowed types to a few final
built-ins, in arbitrary constants we can have array elements that are
some subtype of the array's element type.

 #KT-48671 Fixed
This commit is contained in:
pyos
2021-09-09 14:50:35 +02:00
committed by Alexander Udalov
parent 51c85e7f86
commit 23420ecf7a
12 changed files with 86 additions and 24 deletions
@@ -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 {
@@ -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)
}
}
@@ -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
@@ -0,0 +1,4 @@
// WITH_RUNTIME
val x: Any = arrayOf<Any>(arrayOf("OK"))
fun box(): String = ((x as Array<Any>)[0] as Array<String>)[0]
@@ -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 {
@@ -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 {
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");