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
sw?.writeClass(arrayElementType)
} else {
arrayElementType = mapType(memberType, mode.toGenericArgumentMode(variance), sw)
arrayElementType = mapType(memberType, mode.toGenericArgumentMode(variance, ofArray = true), sw)
}
sw?.writeArrayEnd()
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
import kotlin.reflect.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 {
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")
@@ -169,6 +169,11 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest {
public void testKClassInt() throws Exception {
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")
@@ -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
* Other types mapped as DEFAULT
*/
@@ -77,7 +77,7 @@ class TypeMappingMode private constructor(
isForAnnotationParameter = true,
needPrimitiveBoxing = false,
needInlineClassWrapping = false,
genericArgumentMode = TypeMappingMode(isForAnnotationParameter = true, genericArgumentMode = GENERIC_ARGUMENT)
genericArgumentMode = GENERIC_ARGUMENT
)
@@ -89,48 +89,37 @@ class TypeMappingMode private constructor(
@JvmStatic
fun getOptimalModeForValueParameter(
type: KotlinType
) = getOptimalModeForSignaturePart(type, isForAnnotationParameter = false, canBeUsedInSupertypePosition = true)
) = getOptimalModeForSignaturePart(type, canBeUsedInSupertypePosition = true)
@JvmStatic
fun getOptimalModeForReturnType(
type: KotlinType,
isAnnotationMethod: Boolean
) = getOptimalModeForSignaturePart(type, isForAnnotationParameter = isAnnotationMethod, canBeUsedInSupertypePosition = false)
) = if (isAnnotationMethod) VALUE_FOR_ANNOTATION else getOptimalModeForSignaturePart(type, canBeUsedInSupertypePosition = false)
private fun getOptimalModeForSignaturePart(
type: KotlinType,
isForAnnotationParameter: Boolean,
canBeUsedInSupertypePosition: Boolean
): TypeMappingMode {
private fun getOptimalModeForSignaturePart(type: KotlinType, canBeUsedInSupertypePosition: Boolean): TypeMappingMode {
if (type.arguments.isEmpty()) return DEFAULT
if (type.isInlineClassType() && shouldUseUnderlyingType(type)) {
val underlyingType = computeUnderlyingType(type)
if (underlyingType != null) {
return getOptimalModeForSignaturePart(
underlyingType, isForAnnotationParameter, canBeUsedInSupertypePosition
).dontWrapInlineClassesMode()
return getOptimalModeForSignaturePart(underlyingType, canBeUsedInSupertypePosition).dontWrapInlineClassesMode()
}
}
val contravariantArgumentMode =
if (!canBeUsedInSupertypePosition)
TypeMappingMode(
isForAnnotationParameter = isForAnnotationParameter,
skipDeclarationSiteWildcards = false,
skipDeclarationSiteWildcardsIfPossible = true
)
TypeMappingMode(skipDeclarationSiteWildcards = false, skipDeclarationSiteWildcardsIfPossible = true)
else
null
val invariantArgumentMode =
if (canBeUsedInSupertypePosition)
getOptimalModeForSignaturePart(type, isForAnnotationParameter, canBeUsedInSupertypePosition = false)
getOptimalModeForSignaturePart(type, canBeUsedInSupertypePosition = false)
else
null
return TypeMappingMode(
isForAnnotationParameter = isForAnnotationParameter,
skipDeclarationSiteWildcards = !canBeUsedInSupertypePosition,
skipDeclarationSiteWildcardsIfPossible = true,
genericContravariantArgumentMode = contravariantArgumentMode,
@@ -153,8 +142,8 @@ class TypeMappingMode private constructor(
)
}
fun toGenericArgumentMode(effectiveVariance: Variance): TypeMappingMode =
when (effectiveVariance) {
fun toGenericArgumentMode(effectiveVariance: Variance, ofArray: Boolean = false): TypeMappingMode =
if (ofArray && isForAnnotationParameter) this else when (effectiveVariance) {
Variance.IN_VARIANCE -> genericContravariantArgumentMode ?: this
Variance.INVARIANT -> genericInvariantArgumentMode ?: this
else -> genericArgumentMode ?: this
@@ -121,8 +121,8 @@ fun <T : Any> mapType(
descriptorTypeWriter?.writeArrayType()
arrayElementType = mapType(
memberType, factory, mode.toGenericArgumentMode(memberProjection.projectionKind), typeMappingConfiguration,
descriptorTypeWriter, writeGenericType
memberType, factory, mode.toGenericArgumentMode(memberProjection.projectionKind, ofArray = true),
typeMappingConfiguration, descriptorTypeWriter, writeGenericType
)
descriptorTypeWriter?.writeArrayEnd()