"Materializing" a CapturedType without using an intermediate method

The following code will not type-check using the latest Kotlin compiler.

class GenericA<T>
class GenericB<T>

fun instance(): GenericA<*> = TODO()
fun <T> transformGeneric(a: GenericA<T>): GenericB<T> = TODO()
fun <T> reconcileGenerics(a: GenericA<T>, b: GenericB<T>): Nothing = TODO()

fun withoutIntermediateMethod() {
    val a = instance()
    val b = transformGeneric(a)

    // Type mismatch: inferred type is Any? but CapturedType(*) was expected
    // Type mismatch: inferred type is Any? but CapturedType(out Any?) was expected
    reconcileGenerics(a, b)
}

However, we can make it type-check by “materializing” the CapturedType<*> using an intermediate method with a new type parameter T.

fun withIntermediateMethod() {
    fun <T> reconcileTyped(a: GenericA<T>) {
        val b = transformGeneric(a)
	    reconcileGenerics(a, b)
    }
 	
    val a = instance()
    reconcileTyped(a)
}

Is there any way to get this to work without using an intermediary method, and ideally without changing the signature of reconcileGenerics? Thanks!

1 Like

This workaround works as expected:

class GenericA<T>
class GenericB<T>

fun instance(): GenericA<*> = TODO()
fun <T> transformGeneric(a: GenericA<T>): GenericB<T> = TODO()
fun <T> reconcileGenerics(a: GenericA<T>, b: GenericB<T>): Nothing = TODO()

fun main() {
    val a = instance() as GenericA<Any>
    val b = transformGeneric(a)

    // Type mismatch: inferred type is Any? but CapturedType(*) was expected
    // Type mismatch: inferred type is Any? but CapturedType(out Any?) was expected
    reconcileGenerics(a, b)
}

Thanks! This seems to work well, except for the fact that the type-checker complains about the unchecked cast.

1 Like