https://kotlinlang.org logo
Title
e

elihart

10/28/2021, 8:36 PM
I think I’m seeing variance handled incorrectly by KSP, but could use a sanity check. For the built in
List<out T>
it should be covariant, and javac processors view it that way, but KSP reports the argument as invariant. I have a repro using xprocessing. I don’t think it is a problem within xProcessing because the debugger shows the originating
KSTypeImpl
to have an invariant argument
@Test
    fun testListVariance() {
        val libSource = Source.kotlin(
            "lib.kt",
            """
            class KotlinClass {
                fun foo(list: List<CharSequence>) {}
            }
            """.trimIndent()
        )
        runProcessorTest(listOf(libSource)) { invocation ->
            val clazz = invocation.processingEnv.requireTypeElement("KotlinClass")
            val param = clazz.getDeclaredMethods().single().parameters.single()

            if (invocation.isKsp) {
                expectThat(param.type.typeName.toString())
                    .isEqualTo("java.util.List<java.lang.CharSequence>")
            } else {
                expectThat(param.type.typeName.toString())
                    .isEqualTo("java.util.List<? extends java.lang.CharSequence>")
            }
        }
    }
The KSTypeImpl in KSP showing the argument as invariant
j

Jiaxiang

10/28/2021, 8:50 PM
looks a bug to me
t

Ting-Yuan Huang

10/28/2021, 9:45 PM
Could be related or not, but why it is
java.util.List
, instead of
kotlin.collections.List
?
On the other hand, could it be that
param.type.typeName.toString()
prints use-site variance instead of declaration-site variance?
j

Jiaxiang

10/28/2021, 9:59 PM
in this case it should respect the declaration site variance.
t

Ting-Yuan Huang

10/28/2021, 10:00 PM
The KSTypeImpl also looks good to me; The argument is invariant.
j

Jiaxiang

10/28/2021, 10:00 PM
if you try to write List<in T>, compiler will complain about conflicting variance.
e

elihart

10/28/2021, 10:03 PM
why it is 
java.util.List
, instead of 
kotlin.collections.List
That’s the JavaPoet TypeName representation that xprocessing exposes. Since it is for java codegen it converts kotlin instrinsics to the java equivalent writing
List<out CharSequence>
gives a warning because
List
already marks its type as
out
. so the type should always be covariant - it is inherited
t

Ting-Yuan Huang

10/29/2021, 3:20 AM
Kotlin allows variance annotations to appear in both declaration and use sites. Type arguments (need to) hold use-site variances, instead of the combined (projected) information from type parameters. It is more like a difference in how Kotlin and Java models variance than a bug.
e

elihart

10/29/2021, 4:43 AM
thanks for explaining. I see now that if I dig deeper into the type class I can access the declaration and the type arguments, which show the original type argument
E
as covariant. It seems like a bug with XProcessing then, so I’ll file there
reported at https://issuetracker.google.com/issues/204415667 in case anyone else runs into this. Thanks a lot for the help!
😃 1
t

Ting-Yuan Huang

10/29/2021, 4:58 AM
I think it should be feasible to write a small util to convert Kotlin variances into Java wildcards on top of KSP's API. Please let us know if you see any issues implementing it or feel it better to be implemented in KSP.