I've defined this class:
class NeverNullMap<K, V>(private val backing: MutableMap<K, V> = mutableMapOf(), val default: () -> V): MutableMap<K, V> by backing {
override operator fun get(key: K): V = backing.getOrPut(key, default)
}
And I can use it perfectly fine like this:
fun main(args: Array<String>) {
val myMap = NeverNullMap<String, Int> {0}
println(myMap["test"])
myMap["test"] = myMap["test"] + 10
println(myMap["test"])
}
as expected the output is:
0
10
But when I try to change it to:
fun main(args: Array<String>) {
val myMap = NeverNullMap<String, Int> {0}
println(myMap["test"])
myMap["test"] += 10
println(myMap["test"])
}
I get:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method kotlin.collections.MapsKt__MapsKt.set(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)V from class Day08Kt
at Day08Kt.main(Day08.kt:10)
Why is this happening?
Edit:
Digging a bit into decompiled code both get compiled to completly diffrent code.
In the working version without the +=
it gets compiled to:
Map var2 = (Map)myMap;
String var3 = "test";
Integer var4 = ((Number)myMap.get("test")).intValue() + 10;
var2.put(var3, var4);
The non working version gets compiled to:
MapsKt.set(myMap, "test", ((Number)myMap.get("test")).intValue() + 10);
So it calles this function: https://github.com/JetBrains/kotlin/blob/1.2.0/libraries/stdlib/src/kotlin/collections/Maps.kt#L175
I still have no idea why that produces the Error, just why the first version behaves diffrently.
Edit: YouTrack link to the report
Edit: yes, this is a bug, it has been merged with KT-14227:
Incorrect code is generated when using
MutableMap.set
withplusAssign
operator
After compilation (or decompilation, in this case), MapsKt.set
is turned into a private
method:
@InlineOnly
private static final void set(@NotNull Map $receiver, Object key, Object value) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
$receiver.put(key, value);
}
This explains the IllegalAccessError
.
Now, as to why it is private, I'm only speculating, but I feel like it may be due to this:
@usbpc102 pointed out that @InlineOnly
is indeed the reason for the method being private
.
@InlineOnly
specifies that the method should never be called directly:
Specifies that this function should not be called directly without inlining
so I feel like this is a case where the call to set
should have been inlined, but it was not.
Had the call been inlined, you would have ended up with compiled code that is practically identical to the working version, since the method only contains a call to put
.
I suspect this is due to a compiler bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With