Problem with generic (`CapturedType`)

Hello,

I have encountered a problem with generics. I’m trying to use a library which can trigger handler for a specific event. There is a HandlerRegistry#registerHandler to bind event classes to handlers:

import kotlin.reflect.KClass

// ===============================================================
// Code out of my control (library)
// ===============================================================
interface Event

class EventWrapper<T : Event>

interface Handler<T : Event> {
    fun handle(eventWrapper: EventWrapper<T>)
}

class HandlerRegistry {
    fun <T : Event> reigsterHandler(type: KClass<T>, handler: Handler<T>) {}
}

I have defined an event and its handler. Also I have created HandlerDefinition class which implements Handler interface and introduce additional type field:

class FirstEvent : Event

abstract class HandlerDefinition<T : Event>(val type: KClass<T>) : Handler<T>

class FirstEventHandler : HandlerDefinition<FirstEvent>(FirstEvent::class) {
    override fun handle(eventWrapper: EventWrapper<FirstEvent>) = Unit
}

Now to the point. HandlerDefinition allows me to build a list of all handlers and register them by iterating over that list with forEach. Problem occurs when I’m trying to invoke registerHandler method:

val handlerRegistry = HandlerRegistry()

val eventHandlers: List<HandlerDefinition<out Event>> = listOf(
    FirstEventHandler()
)

// Compiler error - type of the value passed as second parameter is incorrect
eventHandlers.forEach { handler -> handlerRegistry.reigsterHandler(handler.type, handler) }

// Works fine
handlerRegistry.reigsterHandler(FirstEvent::class, FirstEventHandler())

Compiler shows following error:

Type mismatch: inferred type is Scratch_5.Event but CapturedType(out Event) was expected

I’m pretty confused. handler variable passed as second parameter is an instance of HandlerDefinition which implements Handler interface so it is correct. What could be the cause of this error? I would greatly appreciate any suggestions.

The type of handler is HandlerDefinition<out Event> - that out is the problem. I don’t think there is a way to specify explicit type arguments to make this compile. However, you can change the type of eventHandlers variable instead:

val eventHandlers: List<FirstEventHandler> = listOf(
    FirstEventHandler()
)