Add receiver-stack function types
This commit is contained in:
1 parent
1bababa058
commit
e107296bca
11 files changed
+415
-46
No files matched your search
@@ -473,6 +473,29 @@ class MiniAstTest {
|
||||
assertEquals("b", fn.params[1].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun miniAst_captures_context_receiver_function_type() = runTest {
|
||||
val code = """
|
||||
val block: context(Html, Head) Body.()->String = { "ok" }
|
||||
""".trimIndent()
|
||||
val (_, sink) = compileWithMini(code)
|
||||
val mini = sink.build()
|
||||
assertNotNull(mini)
|
||||
val vd = mini.declarations.filterIsInstance<MiniValDecl>().firstOrNull { it.name == "block" }
|
||||
assertNotNull(vd)
|
||||
val type = vd.type as MiniFunctionType
|
||||
val receiver = type.receiver as MiniTypeName
|
||||
assertEquals(listOf("Body"), receiver.segments.map { it.name })
|
||||
assertEquals(2, type.contextReceivers.size)
|
||||
val ctx0 = type.contextReceivers[0] as MiniTypeName
|
||||
val ctx1 = type.contextReceivers[1] as MiniTypeName
|
||||
assertEquals(listOf("Html"), ctx0.segments.map { it.name })
|
||||
assertEquals(listOf("Head"), ctx1.segments.map { it.name })
|
||||
assertTrue(type.params.isEmpty())
|
||||
val ret = type.returnType as MiniTypeName
|
||||
assertEquals(listOf("String"), ret.segments.map { it.name })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun miniAst_captures_dokka_tags() = runTest {
|
||||
val code = """
|
||||
|
||||
@@ -154,4 +154,132 @@ class OptTest {
|
||||
assert( cnt == 4 )
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReceivers1() = runTest {
|
||||
eval("""
|
||||
class RA {
|
||||
fun a() { println("a") }
|
||||
}
|
||||
class RB {
|
||||
fun b() { println("b") }
|
||||
}
|
||||
|
||||
fun ta( f: RA.()->Unit ) {
|
||||
val instance = RA()
|
||||
with(instance) { f(this) }
|
||||
}
|
||||
fun tb( f: RB.()->Unit ) {
|
||||
val b = RB()
|
||||
with(b) { f(this) }
|
||||
}
|
||||
ta {
|
||||
a()
|
||||
tb {
|
||||
b()
|
||||
// but important: a() must still be accessible
|
||||
// because it is inner block, sort of closure:
|
||||
a()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testContextReceiverFunctionType() = runTest {
|
||||
eval("""
|
||||
class RA {
|
||||
fun value(): Int = 10
|
||||
}
|
||||
class RB {
|
||||
fun value(): Int = 20
|
||||
}
|
||||
|
||||
fun ta(f: RA.()->Int): Int {
|
||||
val instance = RA()
|
||||
return with(instance) { f(this) }
|
||||
}
|
||||
|
||||
fun tb(f: context(RA) RB.()->Int): Int {
|
||||
val instance = RB()
|
||||
return with(instance) { f(this) }
|
||||
}
|
||||
|
||||
val result = ta {
|
||||
val block: context(RA) RB.()->Int = {
|
||||
value() + this@RA.value()
|
||||
}
|
||||
tb(block)
|
||||
}
|
||||
|
||||
assertEquals(30, result)
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNestedReceiverQualifiedThis() = runTest {
|
||||
eval("""
|
||||
class RA {
|
||||
fun value(): Int = 1
|
||||
}
|
||||
class RB {
|
||||
fun value(): Int = 2
|
||||
}
|
||||
|
||||
fun ta(f: RA.()->Int): Int {
|
||||
val instance = RA()
|
||||
return with(instance) { f(this) }
|
||||
}
|
||||
fun tb(f: RB.()->Int): Int {
|
||||
val instance = RB()
|
||||
return with(instance) { f(this) }
|
||||
}
|
||||
|
||||
val result = ta {
|
||||
tb {
|
||||
value() + this@RA.value()
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(3, result)
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReceiverAmbiguityRequiresQualifiedThis() = runTest {
|
||||
val ex = assertFailsWith<ScriptError> {
|
||||
eval("""
|
||||
class RA {
|
||||
fun shared(): Int = 10
|
||||
}
|
||||
class RC {
|
||||
fun shared(): Int = 30
|
||||
}
|
||||
class RB
|
||||
|
||||
fun ta(f: RA.()->Int): Int {
|
||||
val instance = RA()
|
||||
return with(instance) { f(this) }
|
||||
}
|
||||
fun tc(f: RC.()->Int): Int {
|
||||
val instance = RC()
|
||||
return with(instance) { f(this) }
|
||||
}
|
||||
fun tb(f: context(RA, RC) RB.()->Int): Int {
|
||||
val instance = RB()
|
||||
return with(instance) { f(this) }
|
||||
}
|
||||
|
||||
ta {
|
||||
tc {
|
||||
val block: context(RA, RC) RB.()->Int = {
|
||||
shared()
|
||||
}
|
||||
tb(block)
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
assertContains(ex.message ?: "", "ambiguous between receivers RA, RC")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user