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:
Denis Zharkov
2016-06-08 13:37:55 +03:00
parent e802049fd0
commit 771cca9c23
8 changed files with 812 additions and 26 deletions
@@ -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
}