interface Inter {
// 源函数
suspend fun <T> run(api: Api<T /* 1 */>): T
// 编译器插件合成出来的函数
fun <T> runBlocking(api: Api<T/* 2 */>): T = ...
}
虽然看上去没什么问题,但是在Kotlin的IR树中,/* 2 */ 位置的泛型 T 和 /* 1 */ 的一样,仍然是属于 run 而不是 runBlocking 的。
此时 runBlocking 的IR树的部分内容:
FUN FAKE_OVERRIDE name:runBlocking visibility:public modality:OPEN <R> ($this:<root>.Inter, api:<root>.Api<R of <root>.Inter.run>) returnType:R of <root>.Inter.run[fake_override]
可以看到,其中有 R of <root>.Inter.run,这说明即使在 runBlocking 中,参数的泛型依旧是 run 的。
然而,这种问题似乎并不会影响到 编译 ,因为不论是兼容性检测还是打包发布都没有受到影响。
在IDEA中,如果查看 OneBotApiExecutable 的 class 文件,会看到:
参数的泛型内都是一些 Error type,这也导致了IDE无法分析,进而无法提供相关的提示。
[!note]
但是即然 class 存在且完整,而泛型又不是运行时的内容,所以我猜测,禁用IDEA的Kotlin 插件这个方法可以临时解决此问题。
虽然比起“不可访问”,我觉得大概率是 IDEA 的 Kotlin 插件无法识别,强行执行大概是可以的。
大概原因: 在 Kotlin 2.x 某个版本中,编译器为泛型增加了从属性,而在所使用的编译器插件中,阻塞、异步等合成函数在基于源项目进行拷贝时,仅拷贝了源函数上的泛型参数,但没有对参数内的泛型进行覆盖。
这会导致,生成的合成函数的参数中如果包含泛型,那么它的泛型还是属于源函数的。
例如,一个源函数和其生成的合成函数:
虽然看上去没什么问题,但是在Kotlin的IR树中,
/* 2 */
位置的泛型T
和/* 1 */
的一样,仍然是属于run
而不是runBlocking
的。此时
runBlocking
的IR树的部分内容:可以看到,其中有
R of <root>.Inter.run
,这说明即使在runBlocking
中,参数的泛型依旧是run
的。 然而,这种问题似乎并不会影响到 编译 ,因为不论是兼容性检测还是打包发布都没有受到影响。 在IDEA中,如果查看OneBotApiExecutable
的class
文件,会看到:参数的泛型内都是一些
Error type
,这也导致了IDE无法分析,进而无法提供相关的提示。