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}