errdefer and try/defer fix
This commit is contained in:
@@ -91,6 +91,36 @@ use_try func() i32 ! Error {
|
||||
return value + 1
|
||||
}
|
||||
|
||||
ct_errdefer func(fail bool) i32 ! Error {
|
||||
trace i32 = 0
|
||||
defer trace = trace * 10 + 1
|
||||
errdefer |err| {
|
||||
if (err == .bad) trace = trace * 10 + 2
|
||||
}
|
||||
defer trace = trace * 10 + 3
|
||||
if (fail) return .bad
|
||||
return 7
|
||||
}
|
||||
|
||||
ct_try_errdefer func() i32 ! Error {
|
||||
trace i32 = 0
|
||||
defer trace = trace * 10 + 4
|
||||
errdefer |err| {
|
||||
if (err == .bad) trace = trace * 10 + 5
|
||||
}
|
||||
return try may_fail(true)
|
||||
}
|
||||
|
||||
ct_errdefer_check func() i32 {
|
||||
ok i32 :: ct_errdefer(false) catch 0
|
||||
if (ok != 7) return 1
|
||||
explicit_error i32 :: ct_errdefer(true) catch 9
|
||||
if (explicit_error != 9) return 2
|
||||
try_error i32 :: ct_try_errdefer() catch 9
|
||||
if (try_error != 9) return 3
|
||||
return 42
|
||||
}
|
||||
|
||||
recover func() i32 {
|
||||
return may_fail(true) catch |e| {
|
||||
match e {
|
||||
@@ -135,6 +165,7 @@ storage_mutation func() i32 {
|
||||
}
|
||||
|
||||
GLOBAL :: $sum_loop(4)
|
||||
ERRDEFER :: $ct_errdefer_check()
|
||||
|
||||
main func() i32 {
|
||||
point Point :: $make_point()
|
||||
@@ -205,5 +236,8 @@ main func() i32 {
|
||||
if fallible_err != 13 {
|
||||
return 16
|
||||
}
|
||||
if ERRDEFER != 42 {
|
||||
return 17
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Milestone 19: `defer` and bare block statements.
|
||||
# Milestone 19: `defer`, `errdefer`, and bare block statements.
|
||||
#
|
||||
# `defer <stmt>` runs the statement when the enclosing scope exits, in reverse
|
||||
# (LIFO) order, on every exit path. A bare `{ ... }` introduces a scope. Each
|
||||
@@ -24,6 +24,66 @@ enclosing_defer_check func() i32 {
|
||||
return v # 0->1 (i=0 fall-through), ->2 (i=1 break); the +100 runs after capture
|
||||
}
|
||||
|
||||
CleanupError :: enum {
|
||||
bad
|
||||
}
|
||||
|
||||
ExtraError :: enum {
|
||||
extra
|
||||
}
|
||||
|
||||
CleanupErrors :: alias CleanupError | ExtraError
|
||||
|
||||
explicit_cleanup func(fail bool, trace *mut i32) i32 ! CleanupError {
|
||||
defer trace^ = trace^ * 10 + 1
|
||||
errdefer |err| {
|
||||
if (err == .bad) {
|
||||
trace^ = trace^ * 10 + 2
|
||||
} else {
|
||||
trace^ = 99
|
||||
}
|
||||
}
|
||||
defer trace^ = trace^ * 10 + 3
|
||||
if (fail) return .bad
|
||||
return 7
|
||||
}
|
||||
|
||||
fail_cleanup func() i32 ! CleanupError {
|
||||
return .bad
|
||||
}
|
||||
|
||||
try_cleanup func(trace *mut i32) i32 ! CleanupError {
|
||||
defer trace^ = trace^ * 10 + 4
|
||||
errdefer trace^ = trace^ * 10 + 5
|
||||
return try fail_cleanup()
|
||||
}
|
||||
|
||||
widen_cleanup func(trace *mut i32) i32 ! CleanupErrors {
|
||||
errdefer |err| {
|
||||
match err {
|
||||
.bad: trace^ = trace^ * 10 + 6
|
||||
.extra: trace^ = 99
|
||||
}
|
||||
}
|
||||
return try fail_cleanup()
|
||||
}
|
||||
|
||||
scoped_cleanup func(trace *mut i32) i32 ! CleanupError {
|
||||
errdefer trace^ = trace^ * 10 + 7
|
||||
{
|
||||
errdefer trace^ = 99
|
||||
}
|
||||
return .bad
|
||||
}
|
||||
|
||||
multi_exit_cleanup func(direct bool, trace *mut i32) i32 ! CleanupError {
|
||||
errdefer |err| {
|
||||
if (err == .bad) trace^ = trace^ + 8
|
||||
}
|
||||
if (direct) return .bad
|
||||
return try fail_cleanup()
|
||||
}
|
||||
|
||||
main func() i32 {
|
||||
# 1. return value captured before defers run.
|
||||
if (spill_check() != 5) return 101
|
||||
@@ -78,5 +138,31 @@ main func() i32 {
|
||||
# 7. break does not run an enclosing function-scope defer.
|
||||
if (enclosing_defer_check() != 2) return 107
|
||||
|
||||
# 8. errdefer is skipped on success; ordinary defers stay interleaved.
|
||||
trace i32 = 0
|
||||
if ((explicit_cleanup(false, &trace) catch 0) != 7 or trace != 31) return 108
|
||||
|
||||
# 9. Explicit errors run errdefer and expose the captured error.
|
||||
trace = 0
|
||||
if ((explicit_cleanup(true, &trace) catch 9) != 9 or trace != 321) return 109
|
||||
|
||||
# 10. Propagated errors run both errdefer and ordinary defer.
|
||||
trace = 0
|
||||
if ((try_cleanup(&trace) catch 9) != 9 or trace != 54) return 110
|
||||
|
||||
# 11. Captures observe the widened enclosing error type.
|
||||
trace = 0
|
||||
if ((widen_cleanup(&trace) catch 9) != 9 or trace != 6) return 111
|
||||
|
||||
# 12. An errdefer expires when its block exits normally.
|
||||
trace = 0
|
||||
if ((scoped_cleanup(&trace) catch 9) != 9 or trace != 7) return 112
|
||||
|
||||
# 13. One captured errdefer can be replayed at several distinct error exits.
|
||||
trace = 0
|
||||
_ = multi_exit_cleanup(true, &trace) catch 0
|
||||
_ = multi_exit_cleanup(false, &trace) catch 0
|
||||
if (trace != 16) return 113
|
||||
|
||||
return 42
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user