Kotlin 编译器混淆了具体化的类型参数

Kotlin compiler mixing up reified type parameters

我想我可能遇到了关于具体化类型参数的编译器错误。用代码示例可能最容易解释:

fun main() {
    println("Same:");

    proxySame<Int>();
    directSame<String, Int>();

    println("\nDifferent:");

    proxyDiff<Int>();
    directDiff<String, Int>();
}


inline fun <reified P> proxySame() = directSame<String, P>();
inline fun <reified P, reified Z> directSame(
    func: () -> Unit = {
        println(Z::class.java.simpleName)
    }
) = func();


inline fun <reified P> proxyDiff() = directDiff<String, P>();
inline fun <reified Q, reified Z> directDiff(
    func: () -> Unit = {
        println(Z::class.java.simpleName)
    }
) = func();

这个例子显然不是真实场景,但它是我能找到的最简单的程序,它仍然表现出意外的行为。

在此代码中有 2 种类型的函数:directXproxyX,其中 XSameDiffSameDiff 函数之间的唯一区别是 directX 函数的第一个类型参数的名称 。对于Same,它与proxyX函数相同,对于Diff,它是不同的。

无论是否通过代理函数调用 directX,人们都希望输出相同。不幸的是,情况显然并非总是如此:

Same:
String         (proxy, wrong)
Integer        (direct, correct)

Different:
Integer        (proxy, correct)
Integer        (direct, correct)

正如您所看到的,通过代理函数调用时输出是不同的,但前提是具体化类型参数具有相同的名称。 代理函数 P 的值不知何故落在了直接函数的 Z 中。但是,这只发生在 lambda 函数内部,在常规函数体中打印 class 名称会导致预期结果。

我在这里完全不知所措。除了编译器错误外,我找不到任何其他解释。我真的 运行 遇到了一些晦涩的错误,还是我在这里遗漏了什么?

编辑:我已经为此 here 打开了一个错误报告。

如果您查看反编译的字节码,您会发现 proxyDiff() 似乎考虑了通用参数 PproxySame() 没有。

public final void proxyDiff() {
   // ...
   Intrinsics.reifiedOperationMarker(4, "P");
   String var5 = Object.class.getSimpleName();
   // ...
}

public final void proxySame() {
   // ...
   String var5 = String.class.getSimpleName();
   // ...
}

我的猜测是它在内联期间被优化掉了。

编译器看到 P 没有在 directSame() 中使用,因此推断它也没有在 proxySame() 中使用。所以这个:

inline fun <reified P> proxySame() = directSame<String, P>();
inline fun <reified P, reified Z> directSame(
        func: () -> Unit = {
            println(Z::class.java.simpleName)
        }
) = func();

在引擎盖下变成了这个:

inline fun proxySame() = directSame<String>();
inline fun <reified Z> directSame(
        func: () -> Unit = {
            println(Z::class.java.simpleName)
        }
) = func(); 

所以,是的,我肯定会说这是一个错误。