stage2: "Pop" error trace for break/return within catch
This implement trace "popping" for correctly handled errors within
`catch { ... }` and `else { ... }` blocks.
When breaking from these blocks with any non-error, we pop the error
trace frames corresponding to the operand. When breaking with an error,
we preserve the frames so that error traces "chain" together as usual.
```zig
fn foo(cond1: bool, cond2: bool) !void {
bar() catch {
if (cond1) {
// If baz() result is a non-error, pop the error trace frames from bar()
// If baz() result is an error, leave the bar() frames on the error trace
return baz();
} else if (cond2) {
// If we break/return an error, then leave the error frames from bar() on the error trace
return error.Foo;
}
};
// An error returned from here does not include bar()'s error frames in the trace
return error.Bar;
}
```
Notice that if foo() does not return an error it, it leaves no extra
frames on the error trace.
This is piece (1/3) of https://github.com/ziglang/zig/issues/1923#issuecomment-1218495574
This commit is contained in:
@@ -98,6 +98,191 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
|
||||
},
|
||||
});
|
||||
|
||||
cases.addCase(.{
|
||||
.name = "try return + handled catch/if-else",
|
||||
.source =
|
||||
\\fn foo() !void {
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\}
|
||||
\\
|
||||
\\pub fn main() !void {
|
||||
\\ foo() catch {}; // should not affect error trace
|
||||
\\ if (foo()) |_| {} else |_| {
|
||||
\\ // should also not affect error trace
|
||||
\\ }
|
||||
\\ try foo();
|
||||
\\}
|
||||
,
|
||||
.Debug = .{
|
||||
.expect =
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:2:5: [address] in foo (test)
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\ ^
|
||||
\\source.zig:10:5: [address] in main (test)
|
||||
\\ try foo();
|
||||
\\ ^
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseSafe = .{
|
||||
.exclude_os = .{
|
||||
.windows, // TODO
|
||||
.linux, // defeated by aggressive inlining
|
||||
},
|
||||
.expect =
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:2:5: [address] in [function]
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\ ^
|
||||
\\source.zig:10:5: [address] in [function]
|
||||
\\ try foo();
|
||||
\\ ^
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseFast = .{
|
||||
.expect =
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseSmall = .{
|
||||
.expect =
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
},
|
||||
});
|
||||
|
||||
cases.addCase(.{
|
||||
.name = "try return from within catch",
|
||||
.source =
|
||||
\\fn foo() !void {
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\}
|
||||
\\
|
||||
\\fn bar() !void {
|
||||
\\ return error.AndMyCarIsOutOfGas;
|
||||
\\}
|
||||
\\
|
||||
\\pub fn main() !void {
|
||||
\\ foo() catch { // error trace should include foo()
|
||||
\\ try bar();
|
||||
\\ };
|
||||
\\}
|
||||
,
|
||||
.Debug = .{
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\source.zig:2:5: [address] in foo (test)
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\ ^
|
||||
\\source.zig:6:5: [address] in bar (test)
|
||||
\\ return error.AndMyCarIsOutOfGas;
|
||||
\\ ^
|
||||
\\source.zig:11:9: [address] in main (test)
|
||||
\\ try bar();
|
||||
\\ ^
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseSafe = .{
|
||||
.exclude_os = .{
|
||||
.windows, // TODO
|
||||
},
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\source.zig:2:5: [address] in [function]
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\ ^
|
||||
\\source.zig:6:5: [address] in [function]
|
||||
\\ return error.AndMyCarIsOutOfGas;
|
||||
\\ ^
|
||||
\\source.zig:11:9: [address] in [function]
|
||||
\\ try bar();
|
||||
\\ ^
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseFast = .{
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseSmall = .{
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\
|
||||
,
|
||||
},
|
||||
});
|
||||
|
||||
cases.addCase(.{
|
||||
.name = "try return from within if-else",
|
||||
.source =
|
||||
\\fn foo() !void {
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\}
|
||||
\\
|
||||
\\fn bar() !void {
|
||||
\\ return error.AndMyCarIsOutOfGas;
|
||||
\\}
|
||||
\\
|
||||
\\pub fn main() !void {
|
||||
\\ if (foo()) |_| {} else |_| { // error trace should include foo()
|
||||
\\ try bar();
|
||||
\\ }
|
||||
\\}
|
||||
,
|
||||
.Debug = .{
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\source.zig:2:5: [address] in foo (test)
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\ ^
|
||||
\\source.zig:6:5: [address] in bar (test)
|
||||
\\ return error.AndMyCarIsOutOfGas;
|
||||
\\ ^
|
||||
\\source.zig:11:9: [address] in main (test)
|
||||
\\ try bar();
|
||||
\\ ^
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseSafe = .{
|
||||
.exclude_os = .{
|
||||
.windows, // TODO
|
||||
},
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\source.zig:2:5: [address] in [function]
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\ ^
|
||||
\\source.zig:6:5: [address] in [function]
|
||||
\\ return error.AndMyCarIsOutOfGas;
|
||||
\\ ^
|
||||
\\source.zig:11:9: [address] in [function]
|
||||
\\ try bar();
|
||||
\\ ^
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseFast = .{
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\
|
||||
,
|
||||
},
|
||||
.ReleaseSmall = .{
|
||||
.expect =
|
||||
\\error: AndMyCarIsOutOfGas
|
||||
\\
|
||||
,
|
||||
},
|
||||
});
|
||||
|
||||
cases.addCase(.{
|
||||
.name = "try try return return",
|
||||
.source =
|
||||
|
||||
Reference in New Issue
Block a user