Youssef Shoaib [MOD]
05/21/2022, 8:15 PMinterface Id<A>{
context(Unit)
fun A.identity(): A
}
object StringId: Id<String>{
context(Unit)
override fun String.identity(): String = this
}
fun main() {
with(Unit){
with(StringId){
"42".identity() // works fine
}
with(StringId as Id<String>){
"42".identity() // AbstractMethodError
}
}
}
when StringId
is cast as a Id<String>
, a call to identity
throws the exception java.lang.AbstractMethodError: Receiver class StringId does not define or inherit an implementation of the resolved method 'abstract java.lang.Object identity(kotlin.Unit, java.lang.Object)' of interface Id.
.
With javap, the bytecode for StringId is as follows:
public java.lang.String identity(kotlin.Unit, java.lang.String);
Code:
0: aload_2
1: ldc #18 // String <this>
3: invokestatic #24 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_1
7: ldc #18 // String <this>
9: invokestatic #24 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
12: aload_2
13: areturn
public java.lang.Object identity(java.lang.Object, kotlin.Unit);
Code:
0: aload_0
1: aload_1
2: checkcast #30 // class kotlin/Unit
5: aload_2
6: checkcast #32 // class java/lang/String
9: invokevirtual #34 // Method identity:(Lkotlin/Unit;Ljava/lang/String;)Ljava/lang/String;
12: areturn
It seems like, when the compiler generates the interface method override, it swaps the parameter order of the receiver and the context, resulting in a weird mishap
Youtrack issue