Yes ... the compiler is definitely wrong. (testing with Kotlin version 1.1.2-5)
First of all, in the case of delegating ownership of a map, you use the name of the property to find the value for it on the map.
Using MutableMap<String, in String> equivalent to Java Map<String, ? super String> Map<String, ? super String> , which uses contravariance.
Using MutableMap<String, out String> equivalent to Java Map<String, ? extends String> Map<String, ? extends String> , which uses covariance.
(you mixed twice)
As a manufacturer, a covariant type can be used. The contravariant type can be used as a consumer. (See PECS . Sorry, I don't have a special Kotlin link, but the principle still applies.)
Delegating by map uses the second general type of map as the producer (you get things from the map), so you should not use MutableMap<String, in String> , since the second parameter is the consumer (to insert things into).
For some reason, the compiler generates the code that it needs for MutableMap<String, out String> in the case of MutableMap<String, in String> , and this is incorrect, as you can see in this example:
class User(val map: MutableMap<String, in String>) { val name: String by map } fun main(args:Array<String>){ val m: MutableMap<String, CharSequence> = mutableMapOf("name" to StringBuilder()) val a = User(m) val s: String = a.name }
You will get a class exception because the VM is trying to treat StringBuilder as String . But you are not using any explicit tricks, so this should be safe.
Unfortunately, it generates throw null ( throw null ) in a valid example of using out .
In the case of String it makes no sense to use covariance ( out ), since String is final, but in the case of a different type hierarchy, the only work I can think of is manually fixing the bytecode, which is a nightmare.
I do not know if there is an existing error report. I think we just need to wait until it gets better.