| // Tests that are inspired by the stack-related and verifier-related bugs in the wasm backend |
| |
| // WITH_STDLIB |
| |
| fun box(): String { |
| if (!test1()) return "Fail 1" |
| if (!test2()) return "Fail 2" |
| if (!test3()) return "Fail 3" |
| if (!test4()) return "Fail 4" |
| if (!test5()) return "Fail 5" |
| if (!test6()) return "Fail 6" |
| if (!test7()) return "Fail 7" |
| if (!test8()) return "Fail 8" |
| return "OK" |
| } |
| |
| open class Foo: Throwable("") {} |
| class Bar: Foo() {} |
| class Baz: Foo() {} |
| class Darb: Throwable("") {} |
| |
| fun ooo() { |
| throw Baz() |
| } |
| |
| fun zoot(): String { |
| return "str" |
| } |
| |
| // Standard exception handling case without finally |
| fun test1(): Boolean { |
| try { |
| ooo() |
| } catch (b: Bar) { |
| throw Darb() |
| return false |
| } catch (b: Baz) { |
| return true |
| } catch (b: Darb) { |
| return false |
| } |
| |
| return false |
| } |
| |
| // Standart case with finally |
| fun test2(): Boolean { |
| var catched = false |
| |
| try { |
| ooo() |
| } catch (b: Bar) { |
| throw Darb() |
| return false |
| } catch (b: Baz) { |
| catched = true |
| return false |
| } catch (b: Darb) { |
| return false |
| } finally { |
| return catched |
| } |
| |
| return false |
| } |
| |
| |
| // Fallthrough with value on the stack (only needs to compile) |
| fun test3(): Boolean { |
| try { |
| 1 |
| } catch (e: Throwable) { |
| 2 |
| } |
| |
| return true |
| } |
| |
| // Fallthrough with value on the stack and finally |
| fun test4(): Boolean { |
| var seenFinally = false |
| |
| try { |
| ooo() |
| 2 |
| } catch (b: Throwable) { |
| 1 |
| } finally { |
| seenFinally = true |
| } |
| |
| return seenFinally |
| } |
| |
| // Try with return value which is used later |
| fun test5(): Boolean { |
| val arg = try { |
| ooo() |
| 1 |
| } catch (b: Baz) { |
| 3 |
| } catch (b: Darb) { |
| 4 |
| } |
| |
| return arg == 3 |
| } |
| |
| |
| // Case where catch uses labeled return which doesn't end the catch |
| fun foo_for_test6(): String { |
| var ret = "" |
| |
| try { |
| ooo() |
| } catch (e: Throwable) { |
| listOf(1, 2, 3, 4, 5).forEach { |
| if (it == 3) return@forEach |
| } |
| ret += "O" |
| } finally { |
| ret += "K" |
| } |
| |
| return ret |
| } |
| |
| fun test6(): Boolean { |
| return foo_for_test6() == "OK" |
| } |
| |
| // Catch is ended with the loop break into outer loop |
| fun test7(): Boolean { |
| var num_exc = 0 |
| var num_breaks = 0 |
| var num_finallies = 0 |
| var num_bodies = 0 |
| |
| loop@ for (i in 1..3) { |
| for (j in 1..5) { |
| try { |
| ooo() |
| } catch (e: Throwable) { |
| ++num_exc |
| if (i == 2 || i == 4) { |
| ++num_breaks |
| break@loop |
| } |
| } finally { |
| ++num_finallies |
| } |
| ++num_bodies |
| } |
| } |
| |
| if (num_exc == 6 && num_breaks == 1 && num_finallies == 6 && num_bodies == 5) |
| return true |
| return false |
| } |
| |
| // Finally throws an exception |
| class Baobab: Throwable() |
| class Zanzibar: Throwable() |
| class Hypo(val catchedBaobab: Boolean, val thrownZanzibar: Boolean, val seenFinally: Boolean): Throwable() |
| |
| fun golb() { |
| throw Baobab() |
| } |
| |
| fun foo(i: Int) { |
| var catchedBaobab = false |
| var thrownZanzibar = false |
| var seenFinally = false |
| |
| try { |
| golb() |
| } catch (b: Baobab) { |
| catchedBaobab = true |
| if (i == 9) { |
| thrownZanzibar = true |
| throw Zanzibar() |
| } |
| } finally { |
| seenFinally = true |
| throw Hypo(catchedBaobab, thrownZanzibar, seenFinally) |
| } |
| } |
| |
| fun test8(): Boolean { |
| try { |
| foo(9) |
| } catch (z: Hypo) { |
| if (z.catchedBaobab && z.seenFinally && z.thrownZanzibar) |
| return true |
| return false |
| } catch (e: Throwable) { |
| return false |
| } |
| return false |
| } |