Support non local return generation, support non local return inlining
This commit is contained in:
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user