stage2: Propagate error return trace into fn call

This change extends the "lifetime" of the error return trace associated
with an error to include the duration of a function call it is passed
to.

This means that if a function returns an error, its return trace will
include the error return trace for any error inputs. This is needed to
support `testing.expectError` and similar functions.

If a function returns a non-error, we have to clean up any error return
traces created by error-able call arguments.
This commit is contained in:
Cody Tapscott
2022-09-23 11:50:55 -07:00
parent 77720e30aa
commit b529d8e48f
3 changed files with 247 additions and 69 deletions

View File

@@ -260,6 +260,75 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
},
});
cases.addCase(.{
.name = "error passed to function has its trace preserved for duration of the call",
.source =
\\pub fn expectError(expected_error: anyerror, actual_error: anyerror!void) !void {
\\ actual_error catch |err| {
\\ if (err == expected_error) return {};
\\ };
\\ return error.TestExpectedError;
\\}
\\
\\fn alwaysErrors() !void { return error.ThisErrorShouldNotAppearInAnyTrace; }
\\fn foo() !void { return error.Foo; }
\\
\\pub fn main() !void {
\\ try expectError(error.ThisErrorShouldNotAppearInAnyTrace, alwaysErrors());
\\ try expectError(error.ThisErrorShouldNotAppearInAnyTrace, alwaysErrors());
\\ try expectError(error.Foo, foo());
\\
\\ // Only the error trace for this failing check should appear:
\\ try expectError(error.Bar, foo());
\\}
,
.Debug = .{
.expect =
\\error: TestExpectedError
\\source.zig:9:18: [address] in foo (test)
\\fn foo() !void { return error.Foo; }
\\ ^
\\source.zig:5:5: [address] in expectError (test)
\\ return error.TestExpectedError;
\\ ^
\\source.zig:17:5: [address] in main (test)
\\ try expectError(error.Bar, foo());
\\ ^
\\
,
},
.ReleaseSafe = .{
.exclude_os = .{
.windows, // TODO
},
.expect =
\\error: TestExpectedError
\\source.zig:9:18: [address] in [function]
\\fn foo() !void { return error.Foo; }
\\ ^
\\source.zig:5:5: [address] in [function]
\\ return error.TestExpectedError;
\\ ^
\\source.zig:17:5: [address] in [function]
\\ try expectError(error.Bar, foo());
\\ ^
\\
,
},
.ReleaseFast = .{
.expect =
\\error: TestExpectedError
\\
,
},
.ReleaseSmall = .{
.expect =
\\error: TestExpectedError
\\
,
},
});
cases.addCase(.{
.name = "try return from within catch",
.source =