This message was deleted.
# getting-started
s
This message was deleted.
👀 1
y
so I made a little function like this to see what type parameters the
Scope
has:
Copy code
fun <S: Gen.A, P: Gen.B> Scope<S, P>.scopeId() = this
(this is really useful when debugging weird context receivers issues since you can't quite see a list of context receivers rn) and hitting Ctrl-Shift-P in IDEA says that the
Scope
is of type
Scope<MyGen.A, out Any?>
which is really weird
Adding a bit of TypeWrapper magic (same workaround I gave for the original bug) fixes the issue, which leads me to believe that it might be the same bug:
Copy code
operator fun <A : Gen.A, B : Gen.B> Gen<A, B>.invoke(
    rules: context(Scope<A, B>) A.(TypeWrapper<B>) -> Unit
) {
    with(Scope(this)) {
        rules(this, a(), TypeWrapper.IMPL)
    }
}
fun main() {
    MyGen {
        a {
            scopeId()
            // `this` now shows `MyGen.B`
            println(b)  // Error: Unresolved reference: b
        }
    }
}

fun <S: Gen.A, P: Gen.B> Scope<S, P>.scopeId() = this
This looks like the compiler is again removing any type parameters that don't appear in the main signature of the lambda and only appear in the context bit, resulting in that lambda having no idea that those parameters exist. I'd say yeah absolutely add that to the bug
👍 1
Hopefully this'll be fixed soon in a future context receiver prototype. Meanwhile use the TypeWrapper workaround or any other way of mentioning the very last type parameter context inside of the main lambda signature (e.g. you can use a List just the same as a type wrapper, passing in an empty list, I personally just use type wrappers as my personal pattern-of-choice cuz it carries practically no overhead (just as much overhead as Units really)) It is very interesting though to know that this is just a type parameter issue. Like, I'm speculating but, it might be quite a short change in the compiler code to just consider those type parameters to be "real" type parameters and it can fix that one significant bug.
A bit off-topic, but TypeWrappers can be useful in other ways too. I originally came up with that pattern when I wanted to emulate partial type parameter inference (i.e. only specifying some type parameters when calling a function with many type parameters). For instance, I used them here to prevent having a caller specify an intersection type as a type argument (which is currently impossible). They can be used in general whenever you expect that users will probably specify some specific type parameters but might leave the others up for grabs (you can use multiple TypeWrappers for different possible sets of specifiable types, and just ensure you have default values of
type()
). In the same thread, I provided this list of TypeWrappers up to 22 type params.