Kotlin IllegalAccessError,带有+ =和-=用于委托接口 [英] Kotlin IllegalAccessError with += and -= for delegated Interface
问题描述
我已经定义了此类:
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"])
}
我得到:
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)
为什么会这样?
深入研究反编译代码,它们都将被编译为完全不同的代码.
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);
因此它调用此函数: 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.
推荐答案
yes, this is a bug, it has been merged with KT-14227:
将
MutableMap.set
与plusAssign
运算符一起使用时会生成不正确的代码
Incorrect code is generated when using
MutableMap.set
withplusAssign
operator
编译(在这种情况下为反编译)后,将MapsKt.set
转换为private
方法:
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);
}
这说明了IllegalAccessError
.
现在,关于为什么它是私有的,我只是在推测,但我觉得可能是由于以下原因:
@ usbpc102 指出
@usbpc102 pointed out that @InlineOnly
is indeed the reason for the method being private
.
@InlineOnly
指定永远不要直接调用该方法:
@InlineOnly
specifies that the method should never be called directly:
指定不应在没有内联的情况下直接调用此函数
Specifies that this function should not be called directly without inlining
所以我觉得这是内嵌对set
的调用的情况,但事实并非如此.
so I feel like this is a case where the call to set
should have been inlined, but it was not.
如果该调用已内联,则最终将获得与工作版本几乎相同的已编译代码,因为该方法仅包含对put
的调用.
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.
这篇关于Kotlin IllegalAccessError,带有+ =和-=用于委托接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!