JVM/JVM_IR: fix mapping of KClass in annotation classes

* JVM incorrectly mapped T<KClass<...>> to T<Class<...>> because the
   annotation-ness of the type mapping mode was inherited one level
   down into a generic signature independent of T

 * JVM_IR was even worse as it did not use VALUE_FOR_ANNOTATION at all,
   mapping T<T<KClass<...>> to T<T<Class<...>> as well.

The correct behavior is to map KClass to Class only at top level or as
an argument of Array.
This commit is contained in:
pyos
2019-11-27 10:31:42 +01:00
committed by Alexander Udalov
parent f869be6a71
commit 7cd55c85e6
7 changed files with 30 additions and 26 deletions
@@ -137,7 +137,7 @@ class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBas
arrayElementType = AsmTypes.OBJECT_TYPE arrayElementType = AsmTypes.OBJECT_TYPE
sw?.writeClass(arrayElementType) sw?.writeClass(arrayElementType)
} else { } else {
arrayElementType = mapType(memberType, mode.toGenericArgumentMode(variance), sw) arrayElementType = mapType(memberType, mode.toGenericArgumentMode(variance, ofArray = true), sw)
} }
sw?.writeArrayEnd() sw?.writeArrayEnd()
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
import kotlin.reflect.KClass import kotlin.reflect.KClass
annotation class Ann(val arg: Array<out KClass<out KClass<*>>>) annotation class Ann(val arg: Array<out KClass<out KClass<*>>>)
@@ -0,0 +1,7 @@
import kotlin.reflect.KClass
annotation class Ann(val arg: KClass<out KClass<*>>)
// method: Ann::arg
// jvm signature: ()Ljava/lang/Class;
// generic signature: ()Ljava/lang/Class<+Lkotlin/reflect/KClass<*>;>;
@@ -170,6 +170,11 @@ public class IrWriteSignatureTestGenerated extends AbstractIrWriteSignatureTest
public void testKClassInt() throws Exception { public void testKClassInt() throws Exception {
runTest("compiler/testData/writeSignature/annotations/kClassInt.kt"); runTest("compiler/testData/writeSignature/annotations/kClassInt.kt");
} }
@TestMetadata("kClassOfKClass.kt")
public void testKClassOfKClass() throws Exception {
runTest("compiler/testData/writeSignature/annotations/kClassOfKClass.kt");
}
} }
@TestMetadata("compiler/testData/writeSignature/callableReference") @TestMetadata("compiler/testData/writeSignature/callableReference")
@@ -169,6 +169,11 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest {
public void testKClassInt() throws Exception { public void testKClassInt() throws Exception {
runTest("compiler/testData/writeSignature/annotations/kClassInt.kt"); runTest("compiler/testData/writeSignature/annotations/kClassInt.kt");
} }
@TestMetadata("kClassOfKClass.kt")
public void testKClassOfKClass() throws Exception {
runTest("compiler/testData/writeSignature/annotations/kClassOfKClass.kt");
}
} }
@TestMetadata("compiler/testData/writeSignature/callableReference") @TestMetadata("compiler/testData/writeSignature/callableReference")
@@ -68,7 +68,7 @@ class TypeMappingMode private constructor(
) )
/** /**
* kotlin.reflect.KClass mapped to java.lang.Class * kotlin.reflect.KClass mapped to java.lang.Class when at top level or in an array;
* primitive types and inline class types are not boxed because types in annotations cannot be nullable * primitive types and inline class types are not boxed because types in annotations cannot be nullable
* Other types mapped as DEFAULT * Other types mapped as DEFAULT
*/ */
@@ -77,7 +77,7 @@ class TypeMappingMode private constructor(
isForAnnotationParameter = true, isForAnnotationParameter = true,
needPrimitiveBoxing = false, needPrimitiveBoxing = false,
needInlineClassWrapping = false, needInlineClassWrapping = false,
genericArgumentMode = TypeMappingMode(isForAnnotationParameter = true, genericArgumentMode = GENERIC_ARGUMENT) genericArgumentMode = GENERIC_ARGUMENT
) )
@@ -89,48 +89,37 @@ class TypeMappingMode private constructor(
@JvmStatic @JvmStatic
fun getOptimalModeForValueParameter( fun getOptimalModeForValueParameter(
type: KotlinType type: KotlinType
) = getOptimalModeForSignaturePart(type, isForAnnotationParameter = false, canBeUsedInSupertypePosition = true) ) = getOptimalModeForSignaturePart(type, canBeUsedInSupertypePosition = true)
@JvmStatic @JvmStatic
fun getOptimalModeForReturnType( fun getOptimalModeForReturnType(
type: KotlinType, type: KotlinType,
isAnnotationMethod: Boolean isAnnotationMethod: Boolean
) = getOptimalModeForSignaturePart(type, isForAnnotationParameter = isAnnotationMethod, canBeUsedInSupertypePosition = false) ) = if (isAnnotationMethod) VALUE_FOR_ANNOTATION else getOptimalModeForSignaturePart(type, canBeUsedInSupertypePosition = false)
private fun getOptimalModeForSignaturePart( private fun getOptimalModeForSignaturePart(type: KotlinType, canBeUsedInSupertypePosition: Boolean): TypeMappingMode {
type: KotlinType,
isForAnnotationParameter: Boolean,
canBeUsedInSupertypePosition: Boolean
): TypeMappingMode {
if (type.arguments.isEmpty()) return DEFAULT if (type.arguments.isEmpty()) return DEFAULT
if (type.isInlineClassType() && shouldUseUnderlyingType(type)) { if (type.isInlineClassType() && shouldUseUnderlyingType(type)) {
val underlyingType = computeUnderlyingType(type) val underlyingType = computeUnderlyingType(type)
if (underlyingType != null) { if (underlyingType != null) {
return getOptimalModeForSignaturePart( return getOptimalModeForSignaturePart(underlyingType, canBeUsedInSupertypePosition).dontWrapInlineClassesMode()
underlyingType, isForAnnotationParameter, canBeUsedInSupertypePosition
).dontWrapInlineClassesMode()
} }
} }
val contravariantArgumentMode = val contravariantArgumentMode =
if (!canBeUsedInSupertypePosition) if (!canBeUsedInSupertypePosition)
TypeMappingMode( TypeMappingMode(skipDeclarationSiteWildcards = false, skipDeclarationSiteWildcardsIfPossible = true)
isForAnnotationParameter = isForAnnotationParameter,
skipDeclarationSiteWildcards = false,
skipDeclarationSiteWildcardsIfPossible = true
)
else else
null null
val invariantArgumentMode = val invariantArgumentMode =
if (canBeUsedInSupertypePosition) if (canBeUsedInSupertypePosition)
getOptimalModeForSignaturePart(type, isForAnnotationParameter, canBeUsedInSupertypePosition = false) getOptimalModeForSignaturePart(type, canBeUsedInSupertypePosition = false)
else else
null null
return TypeMappingMode( return TypeMappingMode(
isForAnnotationParameter = isForAnnotationParameter,
skipDeclarationSiteWildcards = !canBeUsedInSupertypePosition, skipDeclarationSiteWildcards = !canBeUsedInSupertypePosition,
skipDeclarationSiteWildcardsIfPossible = true, skipDeclarationSiteWildcardsIfPossible = true,
genericContravariantArgumentMode = contravariantArgumentMode, genericContravariantArgumentMode = contravariantArgumentMode,
@@ -153,8 +142,8 @@ class TypeMappingMode private constructor(
) )
} }
fun toGenericArgumentMode(effectiveVariance: Variance): TypeMappingMode = fun toGenericArgumentMode(effectiveVariance: Variance, ofArray: Boolean = false): TypeMappingMode =
when (effectiveVariance) { if (ofArray && isForAnnotationParameter) this else when (effectiveVariance) {
Variance.IN_VARIANCE -> genericContravariantArgumentMode ?: this Variance.IN_VARIANCE -> genericContravariantArgumentMode ?: this
Variance.INVARIANT -> genericInvariantArgumentMode ?: this Variance.INVARIANT -> genericInvariantArgumentMode ?: this
else -> genericArgumentMode ?: this else -> genericArgumentMode ?: this
@@ -121,8 +121,8 @@ fun <T : Any> mapType(
descriptorTypeWriter?.writeArrayType() descriptorTypeWriter?.writeArrayType()
arrayElementType = mapType( arrayElementType = mapType(
memberType, factory, mode.toGenericArgumentMode(memberProjection.projectionKind), typeMappingConfiguration, memberType, factory, mode.toGenericArgumentMode(memberProjection.projectionKind, ofArray = true),
descriptorTypeWriter, writeGenericType typeMappingConfiguration, descriptorTypeWriter, writeGenericType
) )
descriptorTypeWriter?.writeArrayEnd() descriptorTypeWriter?.writeArrayEnd()