Support non local return generation, support non local return inlining

This commit is contained in:
Michael Bogdanov
2014-06-05 16:56:49 +04:00
parent 02c6bdeaa3
commit 8092717da4
35 changed files with 1057 additions and 121 deletions
@@ -0,0 +1,30 @@
import test.*
fun test1(b: Boolean): String {
val localResult = doCall ((@local {
() : String ->
if (b) {
return@local "local"
} else {
return "nonLocal"
}
}))
return "result=" + localResult;
}
fun test2(nonLocal: String): String {
val localResult = doCall {
return nonLocal
}
}
fun box(): String {
val test1 = test1(true)
if (test1 != "result=local") return "test1: ${test1}"
val test2 = test1(false)
if (test2 != "nonLocal") return "test2: ${test2}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,30 @@
import test.*
fun test1(b: Boolean): String {
val localResult = doCall @local {
() : String ->
if (b) {
return@local "local"
} else {
return "nonLocal"
}
}
return "localResult=" + localResult;
}
fun test2(nonLocal: String): String {
val localResult = doCall {
return nonLocal
}
}
fun box(): String {
val test1 = test1(true)
if (test1 != "localResult=local") return "test1: ${test1}"
val test2 = test1(false)
if (test2 != "nonLocal") return "test2: ${test2}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,30 @@
import test.*
fun test1(b: Boolean): String {
val localResult = doCall @local {
() : String ->
if (b) {
return@local "local"
} else {
return "nonLocal"
}
}
return "localResult=" + localResult;
}
fun test2(nonLocal: String): String {
val localResult = doCall {
return nonLocal
}
}
fun box(): String {
val test1 = test1(true)
if (test1 != "localResult=local") return "test1: ${test1}"
val test2 = test1(false)
if (test2 != "nonLocal") return "test2: ${test2}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,17 @@
import test.*
class Z {}
fun test1(nonLocal: String): String {
val localResult = doCall {
return nonLocal
}
}
fun box(): String {
val test2 = test1("OK_NONLOCAL")
if (test2 != "OK_NONLOCAL") return "test2: ${test2}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,73 @@
import test.*
import Kind.*
enum class Kind {
LOCAL
EXTERNAL
GLOBAL
}
class Internal(val value: String)
class External(val value: String)
class Global(val value: String)
fun test1(intKind: Kind, extKind: Kind): Global {
var externalResult = doCall @ext {
() : External ->
val internalResult = doCall @int {
() : Internal ->
if (intKind == Kind.GLOBAL) {
return@test1 Global("internal -> global")
} else if (intKind == EXTERNAL) {
return@ext External("internal -> external")
}
return@int Internal("internal -> local")
}
if (extKind == GLOBAL || extKind == EXTERNAL) {
return Global("external -> global")
}
External(internalResult.value + ": external -> local");
}
return Global(externalResult.value + ": exit")
}
fun box(): String {
var test1 = test1(LOCAL, LOCAL).value
if (test1 != "internal -> local: external -> local: exit") return "test1: ${test1}"
test1 = test1(EXTERNAL, LOCAL).value
if (test1 != "internal -> external: exit") return "test2: ${test1}"
test1 = test1(GLOBAL, LOCAL).value
if (test1 != "internal -> global") return "test3: ${test1}"
test1 = test1(LOCAL, EXTERNAL).value
if (test1 != "external -> global") return "test4: ${test1}"
test1 = test1(EXTERNAL, EXTERNAL).value
if (test1 != "internal -> external: exit") return "test5: ${test1}"
test1 = test1(GLOBAL, EXTERNAL).value
if (test1 != "internal -> global") return "test6: ${test1}"
test1 = test1(LOCAL, GLOBAL).value
if (test1 != "external -> global") return "test7: ${test1}"
test1 = test1(EXTERNAL, GLOBAL).value
if (test1 != "internal -> external: exit") return "test8: ${test1}"
test1 = test1(GLOBAL, GLOBAL).value
if (test1 != "internal -> global") return "test9: ${test1}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,25 @@
import test.*
fun test1(b: Boolean): String {
val localResult = noInlineCall @local {
() : Int ->
if (b) {
return@local 1
} else {
return@local 2
}
3
}
return "result=" + localResult;
}
fun box(): String {
val test1 = test1(true)
if (test1 != "result=1") return "test1: ${test1}"
val test2 = test1(false)
if (test2 != "result=2") return "test2: ${test2}"
return "OK"
}
@@ -0,0 +1,9 @@
package test
public fun <R> noInlineCall(block: ()-> R) : R {
return block()
}
public inline fun <R> notUsed(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,30 @@
import test.*
class A {
var result = 0;
var field: Int
get() {
doCall { return 1 }
return 2
}
set(v: Int) {
doCall {
result = v / 2
return
}
result = v
}
}
fun box(): String {
val a = A()
if (a.field != 1) return "fail 1: ${a.field}"
a.field = 4
if (a.result != 2) return "fail 2: ${a.result}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
inline fun <R> doCall(p: () -> R) {
p()
}
@@ -0,0 +1,51 @@
import test.*
fun test1(local: Int, nonLocal: String, doNonLocal: Boolean): String {
val localResult = doCall {
if (doNonLocal) {
return nonLocal
}
local
}
if (localResult == 11) {
return "OK_LOCAL"
}
else {
return "LOCAL_FAILED"
}
}
fun test2(local: Int, nonLocal: String, doNonLocal: Boolean): String {
val localResult = doCall {
if (doNonLocal) {
return@test2 nonLocal
}
local
}
if (localResult == 11) {
return "OK_LOCAL"
}
else {
return "LOCAL_FAILED"
}
}
fun box(): String {
var test1 = test1(11, "fail", false)
if (test1 != "OK_LOCAL") return "test1: ${test1}"
test1 = test1(-1, "OK_NONLOCAL", true)
if (test1 != "OK_NONLOCAL") return "test2: ${test1}"
var test2 = test2(11, "fail", false)
if (test2 != "OK_LOCAL") return "test1: ${test2}"
test2 = test2(-1, "OK_NONLOCAL", true)
if (test2 != "OK_NONLOCAL") return "test2: ${test2}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,30 @@
import test.*
class Holder(var value: Int)
fun test1(holder: Holder, doNonLocal: Boolean) {
holder.value = -1;
val localResult = doCall {
if (doNonLocal) {
holder.value = 1000
return
}
10
}
holder.value = localResult
}
fun box(): String {
val h = Holder(-1)
test1(h, false)
if (h.value != 10) return "test1: ${h.value}"
test1(h, true)
if (h.value != 1000) return "test2: ${h.value}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}
@@ -0,0 +1,100 @@
import test.*
import Kind.*
enum class Kind {
LOCAL
EXTERNAL
GLOBAL
}
class Holder {
var value: String = ""
}
val FINALLY_CHAIN = "in local finally, in external finally, in global finally"
class Internal(val value: String)
class External(val value: String)
class Global(val value: String)
fun test1(intKind: Kind, extKind: Kind, holder: Holder): Global {
holder.value = ""
try {
var externalResult = doCall @ext {
(): External ->
try {
val internalResult = doCall @int {
(): Internal ->
try {
if (intKind == Kind.GLOBAL) {
return@test1 Global("internal -> global")
}
else if (intKind == EXTERNAL) {
return@ext External("internal -> external")
}
return@int Internal("internal -> local")
}
finally {
holder.value += "in local finally"
}
}
if (extKind == GLOBAL || extKind == EXTERNAL) {
return Global("external -> global")
}
External(internalResult.value + ": external -> local");
}
finally {
holder.value += ", in external finally"
}
}
return Global(externalResult.value + ": exit")
}
finally {
holder.value += ", in global finally"
}
}
fun box(): String {
var holder = Holder()
var test1 = test1(LOCAL, LOCAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> local: external -> local: exit") return "test1: ${test1}, finally = ${holder.value}"
test1 = test1(EXTERNAL, LOCAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test2: ${test1}, finally = ${holder.value}"
test1 = test1(GLOBAL, LOCAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test3: ${test1}, finally = ${holder.value}"
test1 = test1(LOCAL, EXTERNAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "external -> global") return "test4: ${test1}, finally = ${holder.value}"
test1 = test1(EXTERNAL, EXTERNAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test5: ${test1}, finally = ${holder.value}"
test1 = test1(GLOBAL, EXTERNAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test6: ${test1}, finally = ${holder.value}"
test1 = test1(LOCAL, GLOBAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "external -> global") return "test7: ${test1}, finally = ${holder.value}"
test1 = test1(EXTERNAL, GLOBAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test8: ${test1}, finally = ${holder.value}"
test1 = test1(GLOBAL, GLOBAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test9: ${test1}, finally = ${holder.value}"
return "OK"
}
@@ -0,0 +1,5 @@
package test
public inline fun <R> doCall(block: ()-> R) : R {
return block()
}