master
1pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext) void {
2 cases.addCase(.{
3 .name = "return",
4 .source =
5 \\pub fn main() !void {
6 \\ return error.TheSkyIsFalling;
7 \\}
8 ,
9 .expect_error = "TheSkyIsFalling",
10 .expect_trace =
11 \\source.zig:2:5: [address] in main
12 \\ return error.TheSkyIsFalling;
13 \\ ^
14 ,
15 });
16
17 cases.addCase(.{
18 .name = "try return",
19 .source =
20 \\fn foo() !void {
21 \\ return error.TheSkyIsFalling;
22 \\}
23 \\
24 \\pub fn main() !void {
25 \\ try foo();
26 \\}
27 ,
28 .expect_error = "TheSkyIsFalling",
29 .expect_trace =
30 \\source.zig:2:5: [address] in foo
31 \\ return error.TheSkyIsFalling;
32 \\ ^
33 \\source.zig:6:5: [address] in main
34 \\ try foo();
35 \\ ^
36 ,
37 .disable_trace_optimized = &.{
38 .{ .x86_64, .windows },
39 .{ .x86, .windows },
40 .{ .x86_64, .macos },
41 .{ .aarch64, .macos },
42 },
43 });
44 cases.addCase(.{
45 .name = "non-error return pops error trace",
46 .source =
47 \\fn bar() !void {
48 \\ return error.UhOh;
49 \\}
50 \\
51 \\fn foo() !void {
52 \\ bar() catch {
53 \\ return; // non-error result: success
54 \\ };
55 \\}
56 \\
57 \\pub fn main() !void {
58 \\ try foo();
59 \\ return error.UnrelatedError;
60 \\}
61 ,
62 .expect_error = "UnrelatedError",
63 .expect_trace =
64 \\source.zig:13:5: [address] in main
65 \\ return error.UnrelatedError;
66 \\ ^
67 ,
68 });
69
70 cases.addCase(.{
71 .name = "continue in while loop",
72 .source =
73 \\fn foo() !void {
74 \\ return error.UhOh;
75 \\}
76 \\
77 \\pub fn main() !void {
78 \\ var i: usize = 0;
79 \\ while (i < 3) : (i += 1) {
80 \\ foo() catch continue;
81 \\ }
82 \\ return error.UnrelatedError;
83 \\}
84 ,
85 .expect_error = "UnrelatedError",
86 .expect_trace =
87 \\source.zig:10:5: [address] in main
88 \\ return error.UnrelatedError;
89 \\ ^
90 ,
91 });
92
93 cases.addCase(.{
94 .name = "try return + handled catch/if-else",
95 .source =
96 \\fn foo() !void {
97 \\ return error.TheSkyIsFalling;
98 \\}
99 \\
100 \\pub fn main() !void {
101 \\ foo() catch {}; // should not affect error trace
102 \\ if (foo()) |_| {} else |_| {
103 \\ // should also not affect error trace
104 \\ }
105 \\ try foo();
106 \\}
107 ,
108 .expect_error = "TheSkyIsFalling",
109 .expect_trace =
110 \\source.zig:2:5: [address] in foo
111 \\ return error.TheSkyIsFalling;
112 \\ ^
113 \\source.zig:10:5: [address] in main
114 \\ try foo();
115 \\ ^
116 ,
117 .disable_trace_optimized = &.{
118 .{ .x86_64, .windows },
119 .{ .x86, .windows },
120 .{ .x86_64, .macos },
121 .{ .aarch64, .macos },
122 },
123 });
124
125 cases.addCase(.{
126 .name = "break from inline loop pops error return trace",
127 .source =
128 \\fn foo() !void { return error.FooBar; }
129 \\
130 \\pub fn main() !void {
131 \\ comptime var i: usize = 0;
132 \\ b: inline while (i < 5) : (i += 1) {
133 \\ foo() catch {
134 \\ break :b; // non-error break, success
135 \\ };
136 \\ }
137 \\ // foo() was successfully handled, should not appear in trace
138 \\
139 \\ return error.BadTime;
140 \\}
141 ,
142 .expect_error = "BadTime",
143 .expect_trace =
144 \\source.zig:12:5: [address] in main
145 \\ return error.BadTime;
146 \\ ^
147 ,
148 });
149
150 cases.addCase(.{
151 .name = "catch and re-throw error",
152 .source =
153 \\fn foo() !void {
154 \\ return error.TheSkyIsFalling;
155 \\}
156 \\
157 \\pub fn main() !void {
158 \\ return foo() catch error.AndMyCarIsOutOfGas;
159 \\}
160 ,
161 .expect_error = "AndMyCarIsOutOfGas",
162 .expect_trace =
163 \\source.zig:2:5: [address] in foo
164 \\ return error.TheSkyIsFalling;
165 \\ ^
166 \\source.zig:6:5: [address] in main
167 \\ return foo() catch error.AndMyCarIsOutOfGas;
168 \\ ^
169 ,
170 .disable_trace_optimized = &.{
171 .{ .x86_64, .windows },
172 .{ .x86, .windows },
173 .{ .x86_64, .macos },
174 .{ .aarch64, .macos },
175 },
176 });
177
178 cases.addCase(.{
179 .name = "errors stored in var do not contribute to error trace",
180 .source =
181 \\fn foo() !void {
182 \\ return error.TheSkyIsFalling;
183 \\}
184 \\
185 \\pub fn main() !void {
186 \\ // Once an error is stored in a variable, it is popped from the trace
187 \\ var x = foo();
188 \\ x = {};
189 \\
190 \\ // As a result, this error trace will still be clean
191 \\ return error.SomethingUnrelatedWentWrong;
192 \\}
193 ,
194 .expect_error = "SomethingUnrelatedWentWrong",
195 .expect_trace =
196 \\source.zig:11:5: [address] in main
197 \\ return error.SomethingUnrelatedWentWrong;
198 \\ ^
199 ,
200 });
201
202 cases.addCase(.{
203 .name = "error stored in const has trace preserved for duration of block",
204 .source =
205 \\fn foo() !void { return error.TheSkyIsFalling; }
206 \\fn bar() !void { return error.InternalError; }
207 \\fn baz() !void { return error.UnexpectedReality; }
208 \\
209 \\pub fn main() !void {
210 \\ const x = foo();
211 \\ const y = b: {
212 \\ if (true)
213 \\ break :b bar();
214 \\
215 \\ break :b {};
216 \\ };
217 \\ x catch {};
218 \\ y catch {};
219 \\ // foo()/bar() error traces not popped until end of block
220 \\
221 \\ {
222 \\ const z = baz();
223 \\ z catch {};
224 \\ // baz() error trace still alive here
225 \\ }
226 \\ // baz() error trace popped, foo(), bar() still alive
227 \\ return error.StillUnresolved;
228 \\}
229 ,
230 .expect_error = "StillUnresolved",
231 .expect_trace =
232 \\source.zig:1:18: [address] in foo
233 \\fn foo() !void { return error.TheSkyIsFalling; }
234 \\ ^
235 \\source.zig:2:18: [address] in bar
236 \\fn bar() !void { return error.InternalError; }
237 \\ ^
238 \\source.zig:23:5: [address] in main
239 \\ return error.StillUnresolved;
240 \\ ^
241 ,
242 .disable_trace_optimized = &.{
243 .{ .x86_64, .windows },
244 .{ .x86, .windows },
245 .{ .x86_64, .macos },
246 .{ .aarch64, .macos },
247 },
248 });
249
250 cases.addCase(.{
251 .name = "error passed to function has its trace preserved for duration of the call",
252 .source =
253 \\pub fn expectError(expected_error: anyerror, actual_error: anyerror!void) !void {
254 \\ actual_error catch |err| {
255 \\ if (err == expected_error) return {};
256 \\ };
257 \\ return error.TestExpectedError;
258 \\}
259 \\
260 \\fn alwaysErrors() !void { return error.ThisErrorShouldNotAppearInAnyTrace; }
261 \\fn foo() !void { return error.Foo; }
262 \\
263 \\pub fn main() !void {
264 \\ try expectError(error.ThisErrorShouldNotAppearInAnyTrace, alwaysErrors());
265 \\ try expectError(error.ThisErrorShouldNotAppearInAnyTrace, alwaysErrors());
266 \\ try expectError(error.Foo, foo());
267 \\
268 \\ // Only the error trace for this failing check should appear:
269 \\ try expectError(error.Bar, foo());
270 \\}
271 ,
272 .expect_error = "TestExpectedError",
273 .expect_trace =
274 \\source.zig:9:18: [address] in foo
275 \\fn foo() !void { return error.Foo; }
276 \\ ^
277 \\source.zig:5:5: [address] in expectError
278 \\ return error.TestExpectedError;
279 \\ ^
280 \\source.zig:17:5: [address] in main
281 \\ try expectError(error.Bar, foo());
282 \\ ^
283 ,
284 .disable_trace_optimized = &.{
285 .{ .x86_64, .windows },
286 .{ .x86, .windows },
287 .{ .x86_64, .macos },
288 .{ .aarch64, .macos },
289 },
290 });
291
292 cases.addCase(.{
293 .name = "try return from within catch",
294 .source =
295 \\fn foo() !void {
296 \\ return error.TheSkyIsFalling;
297 \\}
298 \\
299 \\fn bar() !void {
300 \\ return error.AndMyCarIsOutOfGas;
301 \\}
302 \\
303 \\pub fn main() !void {
304 \\ foo() catch { // error trace should include foo()
305 \\ try bar();
306 \\ };
307 \\}
308 ,
309 .expect_error = "AndMyCarIsOutOfGas",
310 .expect_trace =
311 \\source.zig:2:5: [address] in foo
312 \\ return error.TheSkyIsFalling;
313 \\ ^
314 \\source.zig:6:5: [address] in bar
315 \\ return error.AndMyCarIsOutOfGas;
316 \\ ^
317 \\source.zig:11:9: [address] in main
318 \\ try bar();
319 \\ ^
320 ,
321 .disable_trace_optimized = &.{
322 .{ .x86_64, .windows },
323 .{ .x86, .windows },
324 .{ .x86_64, .macos },
325 .{ .aarch64, .macos },
326 },
327 });
328
329 cases.addCase(.{
330 .name = "try return from within if-else",
331 .source =
332 \\fn foo() !void {
333 \\ return error.TheSkyIsFalling;
334 \\}
335 \\
336 \\fn bar() !void {
337 \\ return error.AndMyCarIsOutOfGas;
338 \\}
339 \\
340 \\pub fn main() !void {
341 \\ if (foo()) |_| {} else |_| { // error trace should include foo()
342 \\ try bar();
343 \\ }
344 \\}
345 ,
346 .expect_error = "AndMyCarIsOutOfGas",
347 .expect_trace =
348 \\source.zig:2:5: [address] in foo
349 \\ return error.TheSkyIsFalling;
350 \\ ^
351 \\source.zig:6:5: [address] in bar
352 \\ return error.AndMyCarIsOutOfGas;
353 \\ ^
354 \\source.zig:11:9: [address] in main
355 \\ try bar();
356 \\ ^
357 ,
358 .disable_trace_optimized = &.{
359 .{ .x86_64, .windows },
360 .{ .x86, .windows },
361 .{ .x86_64, .macos },
362 .{ .aarch64, .macos },
363 },
364 });
365
366 cases.addCase(.{
367 .name = "try try return return",
368 .source =
369 \\fn foo() !void {
370 \\ try bar();
371 \\}
372 \\
373 \\fn bar() !void {
374 \\ return make_error();
375 \\}
376 \\
377 \\fn make_error() !void {
378 \\ return error.TheSkyIsFalling;
379 \\}
380 \\
381 \\pub fn main() !void {
382 \\ try foo();
383 \\}
384 ,
385 .expect_error = "TheSkyIsFalling",
386 .expect_trace =
387 \\source.zig:10:5: [address] in make_error
388 \\ return error.TheSkyIsFalling;
389 \\ ^
390 \\source.zig:6:5: [address] in bar
391 \\ return make_error();
392 \\ ^
393 \\source.zig:2:5: [address] in foo
394 \\ try bar();
395 \\ ^
396 \\source.zig:14:5: [address] in main
397 \\ try foo();
398 \\ ^
399 ,
400 .disable_trace_optimized = &.{
401 .{ .x86_64, .windows },
402 .{ .x86, .windows },
403 .{ .x86_64, .macos },
404 .{ .aarch64, .macos },
405 },
406 });
407
408 cases.addCase(.{
409 .name = "error union switch with call operand",
410 .source =
411 \\pub fn main() !void {
412 \\ try foo();
413 \\ return error.TheSkyIsFalling;
414 \\}
415 \\
416 \\noinline fn failure() error{ Fatal, NonFatal }!void {
417 \\ return error.NonFatal;
418 \\}
419 \\
420 \\fn foo() error{Fatal}!void {
421 \\ return failure() catch |err| switch (err) {
422 \\ error.Fatal => return error.Fatal,
423 \\ error.NonFatal => return,
424 \\ };
425 \\}
426 ,
427 .expect_error = "TheSkyIsFalling",
428 .expect_trace =
429 \\source.zig:3:5: [address] in main
430 \\ return error.TheSkyIsFalling;
431 \\ ^
432 ,
433 .disable_trace_optimized = &.{
434 .{ .x86_64, .freebsd },
435 .{ .x86_64, .linux },
436 .{ .x86, .linux },
437 .{ .aarch64, .linux },
438 .{ .loongarch64, .linux },
439 .{ .riscv64, .linux },
440 .{ .s390x, .linux },
441 .{ .x86_64, .windows },
442 .{ .x86, .windows },
443 .{ .x86_64, .macos },
444 .{ .aarch64, .macos },
445 },
446 });
447}