How to refer to the `this` receivers inside a lambda with context receivers

See the code below:

class A
class B

fun f(argF: context(A, B) () -> Unit) {
    argF(A(), B())
}


fun main() {
    // doesn't work
    f {
        println(this)
        println(this@A)
        println(this@B)
    }

    // doesn't work
    f { a, b ->
        println(a)
        println(b)
    }

    // doesn't work
    f(context(A, B) fun() {
        println(this@A)
        println(this@B)
    })

    // IntelliJ IDEA doesn't complain but it doesn't compile.
    f(::helper)

    // works
    f { helper() }
}


context(A, B)
        @Suppress("NOTHING_TO_INLINE")
        private inline fun helper() {
    println(this@A)
    println(this@B)
}

I tried several approaches and it seems the only way I found that works now is to define a helper function with context receivers. Is there a way to refer to the receiver arguments inside the lambda?

It seems to me like a missing feature. I would expect this@A to work inside the lambda.

3 Likes

You can use this:

context(A) fun <A> given(): A = this@A
fun main() {
    // works
    f {
        println(given<A>())
        println(given<B>())
    }
}

There is a a known resolution bug with resolving context receiver in a lambda. It will be fixed But the whole usage with lambdas is not good yet. Because context and dispatch receivers are mixing.

You can always extract a specific receiver with extension like this:

context(MyReceiver) val myReceiver get() = this@MyReceiver

and use it whenever you need to extract specific receiver by type.

I personally think that the design should be slightly revised to simplify the logic.