Encountered an interface-breaking bug with context...
# language-evolution
y
Encountered an interface-breaking bug with context receivers. Here's a reproducer:
Copy code
interface 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:
Copy code
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
👍 1