[KSP2] Keep the variance of component type in getArrayType()
In KSP2 varargs are no longer of array type and we rely on getArrayType() to convert it back to array type to keep the behavior consistent between Javac/KAPT and KSP. However, our getArrayType() ignores the variance of the passed in component type and makes it always invariant. This CL adds the variance back.
Test: XArrayTypeTest.kt
Change-Id: I773186436f127fded3af10defe188c7ce031d252
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt
index db7d512..1f7d254 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspArrayType.kt
@@ -60,7 +60,11 @@
typeAlias: KSType? = null,
) : KspArrayType(env, ksType, originalKSAnnotations, scope, typeAlias) {
override fun resolveJTypeName(): JTypeName {
- return JArrayTypeName.of(componentType.asTypeName().java.box())
+ return if (ksType.arguments.single().variance == Variance.CONTRAVARIANT) {
+ JArrayTypeName.of(JTypeName.OBJECT)
+ } else {
+ JArrayTypeName.of(componentType.asTypeName().java.box())
+ }
}
override fun resolveKTypeName(): KTypeName {
@@ -155,7 +159,11 @@
listOf(
env.resolver.getTypeArgument(
componentType.ksType.createTypeReference(),
- Variance.INVARIANT
+ if (componentType is KspTypeArgumentType) {
+ componentType.typeArg.variance
+ } else {
+ Variance.INVARIANT
+ }
)
)
),
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
index a0549e5..bcadc1a 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspExecutableParameterElement.kt
@@ -95,7 +95,7 @@
// In KSP2 the varargs have the component type instead of the array type. We make it always
// return the array type in XProcessing.
return if (isVarArgs() && !type.isArray()) {
- env.getArrayType(type)
+ env.getArrayType(env.getWildcardType(producerExtends = type))
} else {
type
}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt
index 11397a3..7d1da28 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XArrayTypeTest.kt
@@ -31,6 +31,7 @@
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.javapoet.JTypeName
import com.squareup.kotlinpoet.javapoet.KTypeName
+import com.squareup.kotlinpoet.javapoet.KWildcardTypeName
import org.junit.Test
class XArrayTypeTest {
@@ -341,6 +342,52 @@
)
)
}
+
+ // Out variance
+ val numberType = invocation.processingEnv.requireType("kotlin.Number")
+ val outNumberType = invocation.processingEnv.getWildcardType(
+ producerExtends = numberType)
+ invocation.processingEnv.getArrayType(outNumberType).let {
+ assertThat(it.isArray()).isTrue()
+ assertThat(it.componentType).isEqualTo(outNumberType)
+ assertThat(it.asTypeName().java).isEqualTo(
+ JArrayTypeName.of(numberType.asTypeName().java)
+ )
+ assertThat(it.asTypeName().kotlin).isEqualTo(
+ com.squareup.kotlinpoet.ARRAY.parameterizedBy(
+ KWildcardTypeName.producerOf(numberType.asTypeName().kotlin)
+ )
+ )
+ }
+ // In variance
+ val inNumberType = invocation.processingEnv.getWildcardType(consumerSuper = numberType)
+ invocation.processingEnv.getArrayType(inNumberType).let {
+ assertThat(it.isArray()).isTrue()
+ assertThat(it.componentType).isEqualTo(inNumberType)
+ assertThat(it.asTypeName().java).isEqualTo(
+ JArrayTypeName.of(JTypeName.OBJECT)
+ )
+ assertThat(it.asTypeName().kotlin).isEqualTo(
+ com.squareup.kotlinpoet.ARRAY.parameterizedBy(
+ KWildcardTypeName.consumerOf(numberType.asTypeName().kotlin)
+ )
+ )
+ }
+ // Star variance
+ val starType = invocation.processingEnv.getWildcardType()
+ invocation.processingEnv.getArrayType(starType).let {
+ assertThat(it.isArray()).isTrue()
+ assertThat(it.componentType).isEqualTo(starType)
+ assertThat(it.asTypeName().java).isEqualTo(
+ JArrayTypeName.of(JTypeName.OBJECT)
+ )
+ assertThat(it.asTypeName().kotlin).isEqualTo(
+ com.squareup.kotlinpoet.ARRAY.parameterizedBy(
+ KWildcardTypeName.producerOf(
+ Any::class.asKTypeName().copy(nullable = true))
+ )
+ )
+ }
}
}