Fix some try-catch block related problems in coroutine transformer
Split all try-catch blocks when they intersect suspension points
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
// WITH_RUNTIME
|
||||
var globalResult = ""
|
||||
var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = java.util.ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
globalResult = x
|
||||
}
|
||||
|
||||
fun run(c: Controller.() -> Continuation<Unit>) {
|
||||
c(this).resume(Unit)
|
||||
while (postponedActions.isNotEmpty()) {
|
||||
postponedActions[0]()
|
||||
postponedActions.removeAt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
val controller = Controller()
|
||||
|
||||
globalResult = "#"
|
||||
wasCalled = false
|
||||
if (!expectException) {
|
||||
controller.run(c)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
controller.run(c)
|
||||
globalResult = "fail: exception was not thrown"
|
||||
} catch (e: Exception) {
|
||||
globalResult = e.message!!
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasCalled) {
|
||||
throw RuntimeException("fail wasCalled")
|
||||
}
|
||||
|
||||
if (globalResult != "OK") {
|
||||
throw RuntimeException("fail $globalResult")
|
||||
}
|
||||
}
|
||||
|
||||
fun commonThrow(t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
|
||||
inline fun tryCatch(t: () -> String, onException: (Exception) -> String) =
|
||||
try {
|
||||
t()
|
||||
} catch (e: java.lang.RuntimeException) {
|
||||
onException(e)
|
||||
}
|
||||
|
||||
inline fun tryCatchFinally(t: () -> String, onException: (Exception) -> String, f: () -> Unit) =
|
||||
try {
|
||||
t()
|
||||
} catch (e: java.lang.RuntimeException) {
|
||||
onException(e)
|
||||
} finally {
|
||||
f()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
tryCatch(
|
||||
{
|
||||
suspendWithValue("<ignored>")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
},
|
||||
{ e ->
|
||||
suspendWithValue("fail 1")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
builder {
|
||||
tryCatch(
|
||||
{
|
||||
suspendWithException(RuntimeException("M"))
|
||||
},
|
||||
{ e ->
|
||||
if (e.message != "M") throw RuntimeException("fail 2")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
builder {
|
||||
tryCatchFinally(
|
||||
{
|
||||
suspendWithValue("<none>")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
},
|
||||
{
|
||||
suspendWithValue("fail 1")
|
||||
},
|
||||
{
|
||||
suspendWithValue("ignored 1")
|
||||
wasCalled = true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
builder {
|
||||
tryCatchFinally(
|
||||
{
|
||||
suspendWithException(RuntimeException("M"))
|
||||
},
|
||||
{ e ->
|
||||
if (e.message != "M") throw RuntimeException("fail 2")
|
||||
suspendWithValue("OK")
|
||||
},
|
||||
{
|
||||
suspendWithValue("ignored 2")
|
||||
wasCalled = true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
builder {
|
||||
tryCatchFinally(
|
||||
{
|
||||
if (suspendWithValue("56") == "56") return@tryCatchFinally "OK"
|
||||
suspendWithValue("fail 4")
|
||||
},
|
||||
{
|
||||
suspendWithValue("fail 5")
|
||||
},
|
||||
{
|
||||
suspendWithValue("ignored 3")
|
||||
wasCalled = true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return globalResult
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// WITH_RUNTIME
|
||||
var globalResult = ""
|
||||
var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = java.util.ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
globalResult = x
|
||||
}
|
||||
|
||||
fun run(c: Controller.() -> Continuation<Unit>) {
|
||||
c(this).resume(Unit)
|
||||
while (postponedActions.isNotEmpty()) {
|
||||
postponedActions[0]()
|
||||
postponedActions.removeAt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
val controller = Controller()
|
||||
|
||||
globalResult = "#"
|
||||
wasCalled = false
|
||||
if (!expectException) {
|
||||
controller.run(c)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
controller.run(c)
|
||||
globalResult = "fail: exception was not thrown"
|
||||
} catch (e: Exception) {
|
||||
globalResult = e.message!!
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasCalled) {
|
||||
throw RuntimeException("fail wasCalled")
|
||||
}
|
||||
|
||||
if (globalResult != "OK") {
|
||||
throw RuntimeException("fail $globalResult")
|
||||
}
|
||||
}
|
||||
|
||||
fun commonThrow(t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
try {
|
||||
try {
|
||||
suspendWithValue("<ignored>")
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
suspendWithValue("fail 1")
|
||||
}
|
||||
} finally {
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
try {
|
||||
suspendWithException(RuntimeException("M1"))
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
if (e.message != "M1") throw RuntimeException("fail 2")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
suspendWithValue("fail 3")
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
try {
|
||||
suspendWithException(Exception("M2"))
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
suspendWithValue("fail 4")
|
||||
} finally {
|
||||
wasCalled = true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (e.message != "M2") throw RuntimeException("fail 5")
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
}
|
||||
|
||||
return globalResult
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// WITH_RUNTIME
|
||||
var globalResult = ""
|
||||
var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = java.util.ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
globalResult = x
|
||||
}
|
||||
|
||||
fun run(c: Controller.() -> Continuation<Unit>) {
|
||||
c(this).resume(Unit)
|
||||
while (postponedActions.isNotEmpty()) {
|
||||
postponedActions[0]()
|
||||
postponedActions.removeAt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
val controller = Controller()
|
||||
|
||||
globalResult = "#"
|
||||
wasCalled = false
|
||||
if (!expectException) {
|
||||
controller.run(c)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
controller.run(c)
|
||||
globalResult = "fail: exception was not thrown"
|
||||
} catch (e: Exception) {
|
||||
globalResult = e.message!!
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasCalled) {
|
||||
throw RuntimeException("fail wasCalled")
|
||||
}
|
||||
|
||||
if (globalResult != "OK") {
|
||||
throw RuntimeException("fail $globalResult")
|
||||
}
|
||||
}
|
||||
|
||||
fun commonThrow(t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
try {
|
||||
suspendWithValue("<none>")
|
||||
suspendWithValue("OK")
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail 1")
|
||||
} finally {
|
||||
suspendWithValue("ignored 1")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithException(RuntimeException("M"))
|
||||
} catch (e: RuntimeException) {
|
||||
if (e.message != "M") throw RuntimeException("fail 2")
|
||||
suspendWithValue("OK")
|
||||
} finally {
|
||||
suspendWithValue("ignored 2")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder(expectException = true) {
|
||||
try {
|
||||
suspendWithException(Exception("OK"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 3")
|
||||
} finally {
|
||||
suspendWithValue("ignored 3")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder(expectException = true) {
|
||||
try {
|
||||
suspendWithException(Exception("OK"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
return@builder "xyz"
|
||||
} finally {
|
||||
suspendWithValue("ignored 4")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithException(Exception("M2"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 4")
|
||||
} catch (e: Exception) {
|
||||
if (e.message != "M2") throw Exception("fail 5: ${e.message}")
|
||||
suspendWithValue("OK")
|
||||
} finally {
|
||||
suspendWithValue("ignored 4")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithValue("123")
|
||||
commonThrow(RuntimeException("M3"))
|
||||
suspendWithValue("456")
|
||||
} catch (e: RuntimeException) {
|
||||
if (e.message != "M3") throw Exception("fail 6: ${e.message}")
|
||||
suspendWithValue("OK")
|
||||
} finally {
|
||||
suspendWithValue("ignored 5")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder(expectException = true) {
|
||||
try {
|
||||
suspendWithValue("123")
|
||||
commonThrow(Exception("OK"))
|
||||
suspendWithValue("456")
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 7")
|
||||
} finally {
|
||||
suspendWithValue("ignored 6")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithValue("123")
|
||||
commonThrow(Exception("M3"))
|
||||
suspendWithValue("456")
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 8")
|
||||
} catch (e: Exception) {
|
||||
if (e.message != "M3") throw Exception("fail 9: ${e.message}")
|
||||
suspendWithValue("OK")
|
||||
} finally {
|
||||
suspendWithValue("ignored 7")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
return globalResult
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// WITH_RUNTIME
|
||||
var globalResult = ""
|
||||
var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = java.util.ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
globalResult = x
|
||||
}
|
||||
|
||||
fun run(c: Controller.() -> Continuation<Unit>) {
|
||||
c(this).resume(Unit)
|
||||
while (postponedActions.isNotEmpty()) {
|
||||
postponedActions[0]()
|
||||
postponedActions.removeAt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
val controller = Controller()
|
||||
|
||||
globalResult = "#"
|
||||
wasCalled = false
|
||||
if (!expectException) {
|
||||
controller.run(c)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
controller.run(c)
|
||||
globalResult = "fail: exception was not thrown"
|
||||
} catch (e: Exception) {
|
||||
globalResult = e.message!!
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasCalled) {
|
||||
throw RuntimeException("fail wasCalled")
|
||||
}
|
||||
|
||||
if (globalResult != "OK") {
|
||||
throw RuntimeException("fail $globalResult")
|
||||
}
|
||||
}
|
||||
|
||||
fun commonThrow(t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
try {
|
||||
suspendWithValue("<ignored>")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail 1")
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithException(RuntimeException("M"))
|
||||
} catch (e: RuntimeException) {
|
||||
if (e.message != "M") throw RuntimeException("fail 2")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
}
|
||||
|
||||
builder(expectException = true) {
|
||||
try {
|
||||
wasCalled = true
|
||||
suspendWithException(Exception("OK"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 3")
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithException(Exception("M2"))
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 4")
|
||||
} catch (e: Exception) {
|
||||
if (e.message != "M2") throw Exception("fail 5: ${e.message}")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithValue("123")
|
||||
commonThrow(RuntimeException("M3"))
|
||||
suspendWithValue("456")
|
||||
} catch (e: RuntimeException) {
|
||||
if (e.message != "M3") throw Exception("fail 6: ${e.message}")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
}
|
||||
|
||||
builder(expectException = true) {
|
||||
try {
|
||||
suspendWithValue("123")
|
||||
wasCalled = true
|
||||
commonThrow(Exception("OK"))
|
||||
suspendWithValue("456")
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 7")
|
||||
}
|
||||
}
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendWithValue("123")
|
||||
commonThrow(Exception("M3"))
|
||||
suspendWithValue("456")
|
||||
} catch (e: RuntimeException) {
|
||||
suspendWithValue("fail")
|
||||
throw RuntimeException("fail 8")
|
||||
} catch (e: Exception) {
|
||||
if (e.message != "M3") throw Exception("fail 9: ${e.message}")
|
||||
wasCalled = true
|
||||
suspendWithValue("OK")
|
||||
}
|
||||
}
|
||||
|
||||
return globalResult
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// WITH_RUNTIME
|
||||
var globalResult = ""
|
||||
var wasCalled = false
|
||||
class Controller {
|
||||
val postponedActions = java.util.ArrayList<() -> Unit>()
|
||||
|
||||
suspend fun suspendWithValue(v: String, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resume(v)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun suspendWithException(e: Exception, x: Continuation<String>) {
|
||||
postponedActions.add {
|
||||
x.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun handleResult(x: String, c: Continuation<Nothing>) {
|
||||
globalResult = x
|
||||
}
|
||||
|
||||
fun run(c: Controller.() -> Continuation<Unit>) {
|
||||
c(this).resume(Unit)
|
||||
while (postponedActions.isNotEmpty()) {
|
||||
postponedActions[0]()
|
||||
postponedActions.removeAt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
val controller = Controller()
|
||||
|
||||
globalResult = "#"
|
||||
wasCalled = false
|
||||
if (!expectException) {
|
||||
controller.run(c)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
controller.run(c)
|
||||
globalResult = "fail: exception was not thrown"
|
||||
} catch (e: Exception) {
|
||||
globalResult = e.message!!
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasCalled) {
|
||||
throw RuntimeException("fail wasCalled")
|
||||
}
|
||||
|
||||
if (globalResult != "OK") {
|
||||
throw RuntimeException("fail $globalResult")
|
||||
}
|
||||
}
|
||||
|
||||
fun commonThrow() {
|
||||
throw RuntimeException("OK")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
try {
|
||||
suspendWithValue("OK")
|
||||
} finally {
|
||||
if (suspendWithValue("G") != "G") throw RuntimeException("fail 1")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder(expectException = true) {
|
||||
try {
|
||||
suspendWithException(java.lang.RuntimeException("OK"))
|
||||
} finally {
|
||||
if (suspendWithValue("G") != "G") throw RuntimeException("fail 2")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
builder(expectException = true) {
|
||||
try {
|
||||
suspendWithValue("OK")
|
||||
commonThrow()
|
||||
suspendWithValue("OK")
|
||||
} finally {
|
||||
if (suspendWithValue("G") != "G") throw RuntimeException("fail 3")
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
return globalResult
|
||||
}
|
||||
Reference in New Issue
Block a user