Kotlin IllegalAccessError with + = and - = for delegated interface

I 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:

 fun main(args: Array<String>) { val myMap = NeverNullMap<String, Int> {0} println(myMap["test"]) myMap["test"] = myMap["test"] + 10 println(myMap["test"]) } 

as expected, output:

 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:

By digging a bit into decompiled code, both are compiled to completely different code.

In the working version without += it compiles to:

  Map var2 = (Map)myMap; String var3 = "test"; Integer var4 = ((Number)myMap.get("test")).intValue() + 10; var2.put(var3, var4); 

The broken version will compile for:

 MapsKt.set(myMap, "test", ((Number)myMap.get("test")).intValue() + 10); 

Therefore, it calls this function: https://github.com/JetBrains/kotlin/blob/1.2.0/libraries/stdlib/src/kotlin/collections/Maps.kt#L175

I still don’t know why this causes an error, just why the first version behaves differently.

Edit: YouTrack Report Link

+7
kotlin
source share
1 answer

Edit: yes, this is a bug, it has been merged with KT-14227 :

Wrong code generated when using MutableMap.set with plusAssign operator


After compilation (or decompilation in this case), MapsKt.set turns 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 for the private, I am only thinking, but it seems to me that this may be because of this:

@ usbpc102 indicated that @InlineOnly really is the reason that the private method .

@InlineOnly indicates that a method should never be called directly:

Indicates that this function cannot be called directly without insertion.

so I feel that this is the case when the set call had to be inline, but it is not.

If the call were inline, you would get compiled code that is almost identical to the working version, since the method contains only the put call.

I suspect this is due to a compiler error.

+4
source share

All Articles