Good morning everyone! I am - of course - trying t...
# k2-adopters
o
Good morning everyone! I am - of course - trying to quickly jump to K2 and Kotlin 2.0 in my project, but it seems there are some things related to experimental Context Receivers not working the same way anymore in Kotlin 2 as before. I am not sure whether this is a bug or simply because Context Receivers will be replaced by Context Parameters anyway? Because Context Parameters are not yet available, I am stuck now in my migration experiment. Also, there is some really odd behaviour when switching the project to use Kotlin 2.0.0, but not using the IntelliJ K2 Alpha mode: errors are not shown in the IDE text editors, but only in the problems view - when using K2 Alpha mode, but the project is still on 1.9.24, the editor shows errors that aren't actually there. So, in real life, one would always have to switch both the project dependencies as well as the IDE settings to properly go Kotlin 2.0? This feels wrong as not all of my projects are there... So, here is an example of what works perfectly fine in Kotlin 1.9, but breaks with Kotlin 2.0. It needs Arrow installed as a dependency, but the rest is completely generic now.
Copy code
import arrow.core.EitherNel
import arrow.core.right

interface ConfigScope
interface ConfigError

typealias Validated<A> = EitherNel<ConfigError, A>

object ConfigurationContext
object CreationContext

typealias Configuration<C> = context(ConfigurationContext) ConfigScope.() -> Validated<C>
typealias Creation<C, T> = context(CreationContext) C.(C) -> Validated<T>

class Definition<C, T>(
    val name: String,
    val configuration: Configuration<C>,
    val creation: Creation<C, T>,
)

class Source

fun sources(block: BuilderDsl<Source>.() -> Unit) = BuilderDsl<Source>().apply(block).things

class BuilderDsl<T> {
    val things = mutableMapOf<String, Definition<*, T>>()

    infix fun <C> String.configuredBy(config: Configuration<C>) = Pair(this, config)
    infix fun <C> Pair<String, Configuration<C>>.createdBy(creator: Creation<C, T>) {
        Definition(first, second, creator).also {
            things[it.name] = it
        }
    }
}

fun main() {
    sources {
        "Dummy" configuredBy { 42.right() } createdBy { Source().right() }
    }
}
It's a little mini DSL to define how to create something with a two step approach: first configuration, then later creation. The DSL
sources
is there to allow the definition of a specific source. The problem with Kotlin 2.0 lies in the context receivers on the typealiases
Configuration
and
Creation
- which are needed in real life to supply some more, you guessed it, context. K2 is not able to correctly create the two lambdas in the
main
function. You get this error message on the lambda after
configuredBy
and `createdBy`:
Argument type mismatch: actual type is 'kotlin.Function2<ConfigScope, ConfigScope, Validated<C>>', but 'Configuration<C>' was expected.
I do not understand why this is. Why does K2 not just create the required lambda here and what could I do to force it to "take" the correct type? Thanks!!
So, by accident, I just discovered: it is the
typealias
that creates this problem! If I remove the
Configuration<C>
and
Creation<C, T>
type aliases and instead declare the exact same thing in the fun
configuredBy
and
createdBy
- it compiles!
Copy code
infix fun <C> String.configuredBy(config: context(ConfigurationContext) ConfigScope.() -> Validated<C>) =
    Pair(this, config)

infix fun <C> Pair<String, Configuration<C>>.createdBy(creator: context(CreationContext) C.(C) -> Validated<T>) {
    Definition(first, second, creator).also {
        things[it.name] = it
    }
works... So, why is the
typealias
in the way here? Is this a bug or a wanted change in behaviour? Thanks!
@Alejandro Serrano.Mena maybe you can help? 😉
a
I'm not sure, but remember that context receivers is experimental (in fact, it's going to be replaced by context parameters), so changes in behavior may occur from time to time
o
I know, I know... but this one here is awkward. It seems the typealiases are somehow not working correctly. And, to make things worse: of course I do know that Context Receivers have been experimental and will be replaced, but we are now in a time frame with nothing... :(
No matter whether we look at CR here: I do expect that a typealias is simply behaving as if I would put their definition in every place I have the alias... but this is not the case here.
a
the problem here seems related to the fact that
context(A) (B) -> C
is identical, as a type, to
(A, B) -> C
(or
KFunction2
), and somehow the compiler has gotten confused about this
m
I'd recommend to report an issue in youtrack (some type aliases related problems are going to be fixed in 2.0.20)
👍 1
o
Yes, but you can clearly see that the typealias is causing the confusion and if a typealias just worked like a "template" (which I expected it to do) there is no problem. Even with K2...
@mglukhikh created KT-68687 In K2, typealias is not working as expected when using Context Receivers
🙏 1