authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-11 19:31:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-11 19:38:07-07:00
log55ba335e0ffc2af76bf0743d98f5a959ccce0409
treef9f705b5f33d0d54c52cdee9e38e40424ab9fd52
parent2ee3cc453c4cefa3519f6a6238d4721364d829ae

Sema: fix resolution of inferred error sets

Introduce `Module.ensureFuncBodyAnalyzed` and corresponding `Sema` function. This mirrors `ensureDeclAnalyzed` except also waits until the function body has been semantically analyzed, meaning that inferred error sets will have been populated. Resolving error sets can now emit a "unable to resolve inferred error set" error instead of producing an incorrect error set type. Resolving error sets now calls `ensureFuncBodyAnalyzed`. Closes #11046. `coerceInMemoryAllowedErrorSets` now does a lot more work to avoid resolving an inferred error set if possible. Same with `wrapErrorUnionSet`. Inferred error set types no longer check the `func` field to determine if they are equal. That was incorrect because an inline or comptime function call produces a unique error set which has the same `*Module.Fn` value for this field. Instead we use the `*Module.Fn.InferredErrorSet` pointers to test equality of inferred error sets.

8 files changed, 271 insertions(+), 195 deletions(-)

src/Compilation.zig+28-106
...@@ -15,7 +15,6 @@ const Package = @import("Package.zig");...@@ -15,7 +15,6 @@ const Package = @import("Package.zig");
15const link = @import("link.zig");15const link = @import("link.zig");
16const tracy = @import("tracy.zig");16const tracy = @import("tracy.zig");
17const trace = tracy.trace;17const trace = tracy.trace;
18const Liveness = @import("Liveness.zig");
19const build_options = @import("build_options");18const build_options = @import("build_options");
20const LibCInstallation = @import("libc_installation.zig").LibCInstallation;19const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
21const glibc = @import("glibc.zig");20const glibc = @import("glibc.zig");
...@@ -2702,12 +2701,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2702,12 +2701,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
2702 => return,2701 => return,
27032702
2704 .complete, .codegen_failure_retryable => {2703 .complete, .codegen_failure_retryable => {
2705 const named_frame = tracy.namedFrame("codegen_decl");
2706 defer named_frame.end();
2707
2708 if (build_options.omit_stage2)2704 if (build_options.omit_stage2)
2709 @panic("sadly stage2 is omitted from this build to save memory on the CI server");2705 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
27102706
2707 const named_frame = tracy.namedFrame("codegen_decl");
2708 defer named_frame.end();
2709
2711 const module = comp.bin_file.options.module.?;2710 const module = comp.bin_file.options.module.?;
2712 assert(decl.has_tv);2711 assert(decl.has_tv);
27132712
...@@ -2722,100 +2721,18 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2722,100 +2721,18 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
2722 return;2721 return;
2723 },2722 },
2724 },2723 },
2725 .codegen_func => |func| switch (func.owner_decl.analysis) {2724 .codegen_func => |func| {
2726 .unreferenced => unreachable,2725 if (build_options.omit_stage2)
2727 .in_progress => unreachable,2726 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2728 .outdated => unreachable,
2729
2730 .file_failure,
2731 .sema_failure,
2732 .codegen_failure,
2733 .dependency_failure,
2734 .sema_failure_retryable,
2735 => return,
2736
2737 .complete, .codegen_failure_retryable => {
2738 if (build_options.omit_stage2)
2739 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2740 switch (func.state) {
2741 .sema_failure, .dependency_failure => return,
2742 .queued => {},
2743 .in_progress => unreachable,
2744 .inline_only => unreachable, // don't queue work for this
2745 .success => unreachable, // don't queue it twice
2746 }
2747
2748 const gpa = comp.gpa;
2749 const module = comp.bin_file.options.module.?;
2750 const decl = func.owner_decl;
2751
2752 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
2753 defer tmp_arena.deinit();
2754 const sema_arena = tmp_arena.allocator();
2755
2756 const sema_frame = tracy.namedFrame("sema");
2757 var sema_frame_ended = false;
2758 errdefer if (!sema_frame_ended) sema_frame.end();
2759
2760 var air = module.analyzeFnBody(decl, func, sema_arena) catch |err| switch (err) {
2761 error.AnalysisFail => {
2762 if (func.state == .in_progress) {
2763 // If this decl caused the compile error, the analysis field would
2764 // be changed to indicate it was this Decl's fault. Because this
2765 // did not happen, we infer here that it was a dependency failure.
2766 func.state = .dependency_failure;
2767 }
2768 return;
2769 },
2770 error.OutOfMemory => return error.OutOfMemory,
2771 };
2772 defer air.deinit(gpa);
2773
2774 sema_frame.end();
2775 sema_frame_ended = true;
2776
2777 if (comp.bin_file.options.emit == null) return;
2778
2779 const liveness_frame = tracy.namedFrame("liveness");
2780 var liveness_frame_ended = false;
2781 errdefer if (!liveness_frame_ended) liveness_frame.end();
2782
2783 log.debug("analyze liveness of {s}", .{decl.name});
2784 var liveness = try Liveness.analyze(gpa, air);
2785 defer liveness.deinit(gpa);
2786
2787 liveness_frame.end();
2788 liveness_frame_ended = true;
2789
2790 if (builtin.mode == .Debug and comp.verbose_air) {
2791 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
2792 @import("print_air.zig").dump(gpa, air, liveness);
2793 std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
2794 }
27952727
2796 const named_frame = tracy.namedFrame("codegen");2728 const named_frame = tracy.namedFrame("codegen_func");
2797 defer named_frame.end();2729 defer named_frame.end();
27982730
2799 comp.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {2731 const module = comp.bin_file.options.module.?;
2800 error.OutOfMemory => return error.OutOfMemory,2732 module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
2801 error.AnalysisFail => {2733 error.OutOfMemory => return error.OutOfMemory,
2802 decl.analysis = .codegen_failure;2734 error.AnalysisFail => return,
2803 return;2735 };
2804 },
2805 else => {
2806 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
2807 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
2808 gpa,
2809 decl.srcLoc(),
2810 "unable to codegen: {s}",
2811 .{@errorName(err)},
2812 ));
2813 decl.analysis = .codegen_failure_retryable;
2814 return;
2815 },
2816 };
2817 return;
2818 },
2819 },2736 },
2820 .emit_h_decl => |decl| switch (decl.analysis) {2737 .emit_h_decl => |decl| switch (decl.analysis) {
2821 .unreferenced => unreachable,2738 .unreferenced => unreachable,
...@@ -2831,11 +2748,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2831,11 +2748,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
2831 // emit-h only requires semantic analysis of the Decl to be complete,2748 // emit-h only requires semantic analysis of the Decl to be complete,
2832 // it does not depend on machine code generation to succeed.2749 // it does not depend on machine code generation to succeed.
2833 .codegen_failure, .codegen_failure_retryable, .complete => {2750 .codegen_failure, .codegen_failure_retryable, .complete => {
2751 if (build_options.omit_stage2)
2752 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2753
2834 const named_frame = tracy.namedFrame("emit_h_decl");2754 const named_frame = tracy.namedFrame("emit_h_decl");
2835 defer named_frame.end();2755 defer named_frame.end();
28362756
2837 if (build_options.omit_stage2)
2838 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2839 const gpa = comp.gpa;2757 const gpa = comp.gpa;
2840 const module = comp.bin_file.options.module.?;2758 const module = comp.bin_file.options.module.?;
2841 const emit_h = module.emit_h.?;2759 const emit_h = module.emit_h.?;
...@@ -2871,11 +2789,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2871,11 +2789,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
2871 },2789 },
2872 },2790 },
2873 .analyze_decl => |decl| {2791 .analyze_decl => |decl| {
2792 if (build_options.omit_stage2)
2793 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2794
2874 const named_frame = tracy.namedFrame("analyze_decl");2795 const named_frame = tracy.namedFrame("analyze_decl");
2875 defer named_frame.end();2796 defer named_frame.end();
28762797
2877 if (build_options.omit_stage2)
2878 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2879 const module = comp.bin_file.options.module.?;2798 const module = comp.bin_file.options.module.?;
2880 module.ensureDeclAnalyzed(decl) catch |err| switch (err) {2799 module.ensureDeclAnalyzed(decl) catch |err| switch (err) {
2881 error.OutOfMemory => return error.OutOfMemory,2800 error.OutOfMemory => return error.OutOfMemory,
...@@ -2883,11 +2802,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2883,11 +2802,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
2883 };2802 };
2884 },2803 },
2885 .update_embed_file => |embed_file| {2804 .update_embed_file => |embed_file| {
2805 if (build_options.omit_stage2)
2806 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2807
2886 const named_frame = tracy.namedFrame("update_embed_file");2808 const named_frame = tracy.namedFrame("update_embed_file");
2887 defer named_frame.end();2809 defer named_frame.end();
28882810
2889 if (build_options.omit_stage2)
2890 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2891 const module = comp.bin_file.options.module.?;2811 const module = comp.bin_file.options.module.?;
2892 module.updateEmbedFile(embed_file) catch |err| switch (err) {2812 module.updateEmbedFile(embed_file) catch |err| switch (err) {
2893 error.OutOfMemory => return error.OutOfMemory,2813 error.OutOfMemory => return error.OutOfMemory,
...@@ -2895,11 +2815,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2895,11 +2815,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
2895 };2815 };
2896 },2816 },
2897 .update_line_number => |decl| {2817 .update_line_number => |decl| {
2818 if (build_options.omit_stage2)
2819 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2820
2898 const named_frame = tracy.namedFrame("update_line_number");2821 const named_frame = tracy.namedFrame("update_line_number");
2899 defer named_frame.end();2822 defer named_frame.end();
29002823
2901 if (build_options.omit_stage2)
2902 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2903 const gpa = comp.gpa;2824 const gpa = comp.gpa;
2904 const module = comp.bin_file.options.module.?;2825 const module = comp.bin_file.options.module.?;
2905 comp.bin_file.updateDeclLineNumber(module, decl) catch |err| {2826 comp.bin_file.updateDeclLineNumber(module, decl) catch |err| {
...@@ -2914,11 +2835,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2914,11 +2835,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
2914 };2835 };
2915 },2836 },
2916 .analyze_pkg => |pkg| {2837 .analyze_pkg => |pkg| {
2838 if (build_options.omit_stage2)
2839 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2840
2917 const named_frame = tracy.namedFrame("analyze_pkg");2841 const named_frame = tracy.namedFrame("analyze_pkg");
2918 defer named_frame.end();2842 defer named_frame.end();
29192843
2920 if (build_options.omit_stage2)
2921 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2922 const module = comp.bin_file.options.module.?;2844 const module = comp.bin_file.options.module.?;
2923 module.semaPkg(pkg) catch |err| switch (err) {2845 module.semaPkg(pkg) catch |err| switch (err) {
2924 error.CurrentWorkingDirectoryUnlinked,2846 error.CurrentWorkingDirectoryUnlinked,
src/Module.zig+106-15
...@@ -3,6 +3,7 @@...@@ -3,6 +3,7 @@
3//! there is or is not any zig source code, respectively.3//! there is or is not any zig source code, respectively.
44
5const std = @import("std");5const std = @import("std");
6const builtin = @import("builtin");
6const mem = std.mem;7const mem = std.mem;
7const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
8const ArrayListUnmanaged = std.ArrayListUnmanaged;9const ArrayListUnmanaged = std.ArrayListUnmanaged;
...@@ -28,6 +29,7 @@ const AstGen = @import("AstGen.zig");...@@ -28,6 +29,7 @@ const AstGen = @import("AstGen.zig");
28const Sema = @import("Sema.zig");29const Sema = @import("Sema.zig");
29const target_util = @import("target.zig");30const target_util = @import("target.zig");
30const build_options = @import("build_options");31const build_options = @import("build_options");
32const Liveness = @import("Liveness.zig");
3133
32/// General-purpose allocator. Used for both temporary and long-term storage.34/// General-purpose allocator. Used for both temporary and long-term storage.
33gpa: Allocator,35gpa: Allocator,
...@@ -1438,8 +1440,11 @@ pub const Fn = struct {...@@ -1438,8 +1440,11 @@ pub const Fn = struct {
1438 is_cold: bool = false,1440 is_cold: bool = false,
1439 is_noinline: bool = false,1441 is_noinline: bool = false,
14401442
1441 /// Any inferred error sets that this function owns, both it's own inferred error set and1443 /// Any inferred error sets that this function owns, both its own inferred error set and
1442 /// inferred error sets of any inline/comptime functions called.1444 /// inferred error sets of any inline/comptime functions called. Not to be confused
1445 /// with inferred error sets of generic instantiations of this function, which are
1446 /// *not* tracked here - they are tracked in the new `Fn` object created for the
1447 /// instantiations.
1443 inferred_error_sets: InferredErrorSetList = .{},1448 inferred_error_sets: InferredErrorSetList = .{},
14441449
1445 pub const Analysis = enum {1450 pub const Analysis = enum {
...@@ -1457,28 +1462,29 @@ pub const Fn = struct {...@@ -1457,28 +1462,29 @@ pub const Fn = struct {
1457 };1462 };
14581463
1459 /// This struct is used to keep track of any dependencies related to functions instances1464 /// This struct is used to keep track of any dependencies related to functions instances
1460 /// that return inferred error sets. Note that a function may be associated to multiple different error sets,1465 /// that return inferred error sets. Note that a function may be associated to
1461 /// for example an inferred error set which this function returns, but also any inferred error sets1466 /// multiple different error sets, for example an inferred error set which
1462 /// of called inline or comptime functions.1467 /// this function returns, but also any inferred error sets of called inline
1468 /// or comptime functions.
1463 pub const InferredErrorSet = struct {1469 pub const InferredErrorSet = struct {
1464 /// The function from which this error set originates.1470 /// The function from which this error set originates.
1465 /// Note: may be the function itself.
1466 func: *Fn,1471 func: *Fn,
14671472
1468 /// All currently known errors that this error set contains. This includes direct additions1473 /// All currently known errors that this error set contains. This includes
1469 /// via `return error.Foo;`, and possibly also errors that are returned from any dependent functions.1474 /// direct additions via `return error.Foo;`, and possibly also errors that
1470 /// When the inferred error set is fully resolved, this map contains all the errors that the function might return.1475 /// are returned from any dependent functions. When the inferred error set is
1476 /// fully resolved, this map contains all the errors that the function might return.
1471 errors: ErrorSet.NameMap = .{},1477 errors: ErrorSet.NameMap = .{},
14721478
1473 /// Other inferred error sets which this inferred error set should include.1479 /// Other inferred error sets which this inferred error set should include.
1474 inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{},1480 inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{},
14751481
1476 /// Whether the function returned anyerror. This is true if either of the dependent functions1482 /// Whether the function returned anyerror. This is true if either of
1477 /// returns anyerror.1483 /// the dependent functions returns anyerror.
1478 is_anyerror: bool = false,1484 is_anyerror: bool = false,
14791485
1480 /// Whether this error set is already fully resolved. If true, resolving can skip resolving any dependents1486 /// Whether this error set is already fully resolved. If true, resolving
1481 /// of this inferred error set.1487 /// can skip resolving any dependents of this inferred error set.
1482 is_resolved: bool = false,1488 is_resolved: bool = false,
14831489
1484 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void {1490 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void {
...@@ -1494,8 +1500,8 @@ pub const Fn = struct {...@@ -1494,8 +1500,8 @@ pub const Fn = struct {
1494 try self.errors.put(gpa, name, {});1500 try self.errors.put(gpa, name, {});
1495 },1501 },
1496 .error_set_inferred => {1502 .error_set_inferred => {
1497 const set = err_set_ty.castTag(.error_set_inferred).?.data;1503 const ies = err_set_ty.castTag(.error_set_inferred).?.data;
1498 try self.inferred_error_sets.put(gpa, set, {});1504 try self.inferred_error_sets.put(gpa, ies, {});
1499 },1505 },
1500 .error_set_merged => {1506 .error_set_merged => {
1501 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();1507 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
...@@ -3441,6 +3447,10 @@ pub fn mapOldZirToNew(...@@ -3441,6 +3447,10 @@ pub fn mapOldZirToNew(
3441 }3447 }
3442}3448}
34433449
3450/// This ensures that the Decl will have a Type and Value populated.
3451/// However the resolution status of the Type may not be fully resolved.
3452/// For example an inferred error set is not resolved until after `analyzeFnBody`.
3453/// is called.
3444pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {3454pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
3445 const tracy = trace(@src());3455 const tracy = trace(@src());
3446 defer tracy.end();3456 defer tracy.end();
...@@ -3533,6 +3543,87 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {...@@ -3533,6 +3543,87 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
3533 }3543 }
3534}3544}
35353545
3546pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
3547 const tracy = trace(@src());
3548 defer tracy.end();
3549
3550 switch (func.owner_decl.analysis) {
3551 .unreferenced => unreachable,
3552 .in_progress => unreachable,
3553 .outdated => unreachable,
3554
3555 .file_failure,
3556 .sema_failure,
3557 .codegen_failure,
3558 .dependency_failure,
3559 .sema_failure_retryable,
3560 => return error.AnalysisFail,
3561
3562 .complete, .codegen_failure_retryable => {
3563 switch (func.state) {
3564 .sema_failure, .dependency_failure => return error.AnalysisFail,
3565 .queued => {},
3566 .in_progress => unreachable,
3567 .inline_only => unreachable, // don't queue work for this
3568 .success => return,
3569 }
3570
3571 const gpa = mod.gpa;
3572 const decl = func.owner_decl;
3573
3574 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
3575 defer tmp_arena.deinit();
3576 const sema_arena = tmp_arena.allocator();
3577
3578 var air = mod.analyzeFnBody(decl, func, sema_arena) catch |err| switch (err) {
3579 error.AnalysisFail => {
3580 if (func.state == .in_progress) {
3581 // If this decl caused the compile error, the analysis field would
3582 // be changed to indicate it was this Decl's fault. Because this
3583 // did not happen, we infer here that it was a dependency failure.
3584 func.state = .dependency_failure;
3585 }
3586 return error.AnalysisFail;
3587 },
3588 error.OutOfMemory => return error.OutOfMemory,
3589 };
3590 defer air.deinit(gpa);
3591
3592 if (mod.comp.bin_file.options.emit == null) return;
3593
3594 log.debug("analyze liveness of {s}", .{decl.name});
3595 var liveness = try Liveness.analyze(gpa, air);
3596 defer liveness.deinit(gpa);
3597
3598 if (builtin.mode == .Debug and mod.comp.verbose_air) {
3599 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
3600 @import("print_air.zig").dump(gpa, air, liveness);
3601 std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
3602 }
3603
3604 mod.comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) {
3605 error.OutOfMemory => return error.OutOfMemory,
3606 error.AnalysisFail => {
3607 decl.analysis = .codegen_failure;
3608 return;
3609 },
3610 else => {
3611 try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
3612 mod.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
3613 gpa,
3614 decl.srcLoc(),
3615 "unable to codegen: {s}",
3616 .{@errorName(err)},
3617 ));
3618 decl.analysis = .codegen_failure_retryable;
3619 return;
3620 },
3621 };
3622 return;
3623 },
3624 }
3625}
3626
3536pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void {3627pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void {
3537 const tracy = trace(@src());3628 const tracy = trace(@src());
3538 defer tracy.end();3629 defer tracy.end();
src/Sema.zig+105-65
...@@ -5346,14 +5346,14 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5346,14 +5346,14 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
5346 }5346 }
53475347
5348 if (lhs_ty.castTag(.error_set_inferred)) |payload| {5348 if (lhs_ty.castTag(.error_set_inferred)) |payload| {
5349 try sema.resolveInferredErrorSet(payload.data);5349 try sema.resolveInferredErrorSet(block, src, payload.data);
5350 // isAnyError might have changed from a false negative to a true positive after resolution.5350 // isAnyError might have changed from a false negative to a true positive after resolution.
5351 if (lhs_ty.isAnyError()) {5351 if (lhs_ty.isAnyError()) {
5352 return Air.Inst.Ref.anyerror_type;5352 return Air.Inst.Ref.anyerror_type;
5353 }5353 }
5354 }5354 }
5355 if (rhs_ty.castTag(.error_set_inferred)) |payload| {5355 if (rhs_ty.castTag(.error_set_inferred)) |payload| {
5356 try sema.resolveInferredErrorSet(payload.data);5356 try sema.resolveInferredErrorSet(block, src, payload.data);
5357 // isAnyError might have changed from a false negative to a true positive after resolution.5357 // isAnyError might have changed from a false negative to a true positive after resolution.
5358 if (rhs_ty.isAnyError()) {5358 if (rhs_ty.isAnyError()) {
5359 return Air.Inst.Ref.anyerror_type;5359 return Air.Inst.Ref.anyerror_type;
...@@ -6927,7 +6927,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -6927,7 +6927,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
6927 }6927 }
6928 }6928 }
69296929
6930 try sema.resolveInferredErrorSetTy(operand_ty);6930 try sema.resolveInferredErrorSetTy(block, src, operand_ty);
69316931
6932 if (operand_ty.isAnyError()) {6932 if (operand_ty.isAnyError()) {
6933 if (special_prong != .@"else") {6933 if (special_prong != .@"else") {
...@@ -10437,7 +10437,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -10437,7 +10437,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
10437 };10437 };
1043810438
10439 // If the error set is inferred it has to be resolved at this point10439 // If the error set is inferred it has to be resolved at this point
10440 try sema.resolveInferredErrorSetTy(ty);10440 try sema.resolveInferredErrorSetTy(block, src, ty);
1044110441
10442 // Build our list of Error values10442 // Build our list of Error values
10443 // Optional value is only null if anyerror10443 // Optional value is only null if anyerror
...@@ -12627,7 +12627,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -12627,7 +12627,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
12627 try sema.checkErrorSetType(block, operand_src, operand_ty);12627 try sema.checkErrorSetType(block, operand_src, operand_ty);
1262812628
12629 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {12629 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
12630 try sema.resolveInferredErrorSetTy(dest_ty);12630 try sema.resolveInferredErrorSetTy(block, src, dest_ty);
1263112631
12632 if (!dest_ty.isAnyError()) {12632 if (!dest_ty.isAnyError()) {
12633 const error_name = val.castTag(.@"error").?.data.name;12633 const error_name = val.castTag(.@"error").?.data.name;
...@@ -16616,7 +16616,7 @@ fn coerceInMemoryAllowed(...@@ -16616,7 +16616,7 @@ fn coerceInMemoryAllowed(
1661616616
16617 // Error Sets16617 // Error Sets
16618 if (dest_tag == .ErrorSet and src_tag == .ErrorSet) {16618 if (dest_tag == .ErrorSet and src_tag == .ErrorSet) {
16619 return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty);16619 return try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src);
16620 }16620 }
1662116621
16622 // Arrays16622 // Arrays
...@@ -16646,8 +16646,11 @@ fn coerceInMemoryAllowed(...@@ -16646,8 +16646,11 @@ fn coerceInMemoryAllowed(
1664616646
16647fn coerceInMemoryAllowedErrorSets(16647fn coerceInMemoryAllowedErrorSets(
16648 sema: *Sema,16648 sema: *Sema,
16649 block: *Block,
16649 dest_ty: Type,16650 dest_ty: Type,
16650 src_ty: Type,16651 src_ty: Type,
16652 dest_src: LazySrcLoc,
16653 src_src: LazySrcLoc,
16651) !InMemoryCoercionResult {16654) !InMemoryCoercionResult {
16652 // Coercion to `anyerror`. Note that this check can return false negatives16655 // Coercion to `anyerror`. Note that this check can return false negatives
16653 // in case the error sets did not get resolved.16656 // in case the error sets did not get resolved.
...@@ -16655,24 +16658,43 @@ fn coerceInMemoryAllowedErrorSets(...@@ -16655,24 +16658,43 @@ fn coerceInMemoryAllowedErrorSets(
16655 return .ok;16658 return .ok;
16656 }16659 }
1665716660
16658 // If both are inferred error sets of functions, and16661 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
16659 // the dest includes the source function, the coercion is OK.16662 const dst_ies = dst_payload.data;
16660 // This check is important because it works without forcing a full resolution16663 // We will make an effort to return `ok` without resolving either error set, to
16661 // of inferred error sets.16664 // avoid unnecessary "unable to resolve error set" dependency loop errors.
16662 if (src_ty.castTag(.error_set_inferred)) |src_payload| {16665 switch (src_ty.tag()) {
16663 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {16666 .error_set_inferred => {
16664 const src_func = src_payload.data.func;16667 // If both are inferred error sets of functions, and
16665 const dst_func = dst_payload.data.func;16668 // the dest includes the source function, the coercion is OK.
1666616669 // This check is important because it works without forcing a full resolution
16667 if (src_func == dst_func or dst_payload.data.inferred_error_sets.contains(src_payload.data)) {16670 // of inferred error sets.
16668 return .ok;16671 const src_ies = src_ty.castTag(.error_set_inferred).?.data;
16669 }16672
16670 return .no_match;16673 if (dst_ies.inferred_error_sets.contains(src_ies)) {
16674 return .ok;
16675 }
16676 },
16677 .error_set_single => {
16678 const name = src_ty.castTag(.error_set_single).?.data;
16679 if (dst_ies.errors.contains(name)) return .ok;
16680 },
16681 .error_set_merged => {
16682 const names = src_ty.castTag(.error_set_merged).?.data.keys();
16683 for (names) |name| {
16684 if (!dst_ies.errors.contains(name)) break;
16685 } else return .ok;
16686 },
16687 .error_set => {
16688 const names = src_ty.castTag(.error_set).?.data.names.keys();
16689 for (names) |name| {
16690 if (!dst_ies.errors.contains(name)) break;
16691 } else return .ok;
16692 },
16693 .anyerror => {},
16694 else => unreachable,
16671 }16695 }
16672 }
1667316696
16674 if (dest_ty.castTag(.error_set_inferred)) |payload| {16697 try sema.resolveInferredErrorSet(block, dest_src, dst_payload.data);
16675 try sema.resolveInferredErrorSet(payload.data);
16676 // isAnyError might have changed from a false negative to a true positive after resolution.16698 // isAnyError might have changed from a false negative to a true positive after resolution.
16677 if (dest_ty.isAnyError()) {16699 if (dest_ty.isAnyError()) {
16678 return .ok;16700 return .ok;
...@@ -16683,7 +16705,7 @@ fn coerceInMemoryAllowedErrorSets(...@@ -16683,7 +16705,7 @@ fn coerceInMemoryAllowedErrorSets(
16683 .error_set_inferred => {16705 .error_set_inferred => {
16684 const src_data = src_ty.castTag(.error_set_inferred).?.data;16706 const src_data = src_ty.castTag(.error_set_inferred).?.data;
1668516707
16686 try sema.resolveInferredErrorSet(src_data);16708 try sema.resolveInferredErrorSet(block, src_src, src_data);
16687 // src anyerror status might have changed after the resolution.16709 // src anyerror status might have changed after the resolution.
16688 if (src_ty.isAnyError()) {16710 if (src_ty.isAnyError()) {
16689 // dest_ty.isAnyError() == true is already checked for at this point.16711 // dest_ty.isAnyError() == true is already checked for at this point.
...@@ -17969,6 +17991,17 @@ fn ensureDeclAnalyzed(sema: *Sema, decl: *Decl) CompileError!void {...@@ -17969,6 +17991,17 @@ fn ensureDeclAnalyzed(sema: *Sema, decl: *Decl) CompileError!void {
17969 };17991 };
17970}17992}
1797117993
17994fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void {
17995 sema.mod.ensureFuncBodyAnalyzed(func) catch |err| {
17996 if (sema.owner_func) |owner_func| {
17997 owner_func.state = .dependency_failure;
17998 } else {
17999 sema.owner_decl.analysis = .dependency_failure;
18000 }
18001 return err;
18002 };
18003}
18004
17972fn refValue(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, val: Value) !Value {18005fn refValue(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, val: Value) !Value {
17973 var anon_decl = try block.startAnonDecl(src);18006 var anon_decl = try block.startAnonDecl(src);
17974 defer anon_decl.deinit();18007 defer anon_decl.deinit();
...@@ -18635,10 +18668,16 @@ fn wrapErrorUnionSet(...@@ -18635,10 +18668,16 @@ fn wrapErrorUnionSet(
18635 },18668 },
18636 .error_set_inferred => ok: {18669 .error_set_inferred => ok: {
18637 const expected_name = val.castTag(.@"error").?.data.name;18670 const expected_name = val.castTag(.@"error").?.data.name;
18638 const data = dest_err_set_ty.castTag(.error_set_inferred).?.data;18671 const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data;
18639 try sema.resolveInferredErrorSet(data);18672
18640 if (data.is_anyerror) break :ok;18673 // We carefully do this in an order that avoids unnecessarily
18641 if (data.errors.contains(expected_name)) break :ok;18674 // resolving the destination error set type.
18675 if (ies.is_anyerror) break :ok;
18676 if (ies.errors.contains(expected_name)) break :ok;
18677 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
18678 break :ok;
18679 }
18680
18642 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);18681 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
18643 },18682 },
18644 .error_set_merged => {18683 .error_set_merged => {
...@@ -18794,10 +18833,10 @@ fn resolvePeerTypes(...@@ -18794,10 +18833,10 @@ fn resolvePeerTypes(
18794 // If neither is a superset, merge errors.18833 // If neither is a superset, merge errors.
18795 const chosen_set_ty = err_set_ty orelse chosen_ty;18834 const chosen_set_ty = err_set_ty orelse chosen_ty;
1879618835
18797 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_ty)) {18836 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
18798 continue;18837 continue;
18799 }18838 }
18800 if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_ty, chosen_set_ty)) {18839 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
18801 err_set_ty = null;18840 err_set_ty = null;
18802 chosen = candidate;18841 chosen = candidate;
18803 chosen_i = candidate_i + 1;18842 chosen_i = candidate_i + 1;
...@@ -18810,10 +18849,10 @@ fn resolvePeerTypes(...@@ -18810,10 +18849,10 @@ fn resolvePeerTypes(
18810 .ErrorUnion => {18849 .ErrorUnion => {
18811 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();18850 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
1881218851
18813 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_ty)) {18852 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
18814 continue;18853 continue;
18815 }18854 }
18816 if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_ty, chosen_set_ty)) {18855 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
18817 err_set_ty = candidate_ty;18856 err_set_ty = candidate_ty;
18818 continue;18857 continue;
18819 }18858 }
...@@ -18823,10 +18862,10 @@ fn resolvePeerTypes(...@@ -18823,10 +18862,10 @@ fn resolvePeerTypes(
18823 },18862 },
18824 else => {18863 else => {
18825 if (err_set_ty) |chosen_set_ty| {18864 if (err_set_ty) |chosen_set_ty| {
18826 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_ty)) {18865 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
18827 continue;18866 continue;
18828 }18867 }
18829 if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_ty, chosen_set_ty)) {18868 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
18830 err_set_ty = candidate_ty;18869 err_set_ty = candidate_ty;
18831 continue;18870 continue;
18832 }18871 }
...@@ -18844,9 +18883,9 @@ fn resolvePeerTypes(...@@ -18844,9 +18883,9 @@ fn resolvePeerTypes(
18844 const chosen_set_ty = err_set_ty orelse chosen_ty;18883 const chosen_set_ty = err_set_ty orelse chosen_ty;
18845 const candidate_set_ty = candidate_ty.errorUnionSet();18884 const candidate_set_ty = candidate_ty.errorUnionSet();
1884618885
18847 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_set_ty)) {18886 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
18848 err_set_ty = chosen_set_ty;18887 err_set_ty = chosen_set_ty;
18849 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_set_ty, chosen_set_ty)) {18888 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
18850 err_set_ty = null;18889 err_set_ty = null;
18851 } else {18890 } else {
18852 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);18891 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
...@@ -18875,9 +18914,9 @@ fn resolvePeerTypes(...@@ -18875,9 +18914,9 @@ fn resolvePeerTypes(
18875 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();18914 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
18876 const candidate_set_ty = chosen_ty.errorUnionSet();18915 const candidate_set_ty = chosen_ty.errorUnionSet();
1887718916
18878 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_set_ty)) {18917 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
18879 err_set_ty = chosen_set_ty;18918 err_set_ty = chosen_set_ty;
18880 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_set_ty, chosen_set_ty)) {18919 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
18881 err_set_ty = candidate_set_ty;18920 err_set_ty = candidate_set_ty;
18882 } else {18921 } else {
18883 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);18922 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
...@@ -18889,9 +18928,9 @@ fn resolvePeerTypes(...@@ -18889,9 +18928,9 @@ fn resolvePeerTypes(
18889 else => {18928 else => {
18890 if (err_set_ty) |chosen_set_ty| {18929 if (err_set_ty) |chosen_set_ty| {
18891 const candidate_set_ty = candidate_ty.errorUnionSet();18930 const candidate_set_ty = candidate_ty.errorUnionSet();
18892 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_set_ty)) {18931 if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
18893 err_set_ty = chosen_set_ty;18932 err_set_ty = chosen_set_ty;
18894 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_set_ty, chosen_set_ty)) {18933 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
18895 err_set_ty = null;18934 err_set_ty = null;
18896 } else {18935 } else {
18897 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);18936 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
...@@ -19458,43 +19497,44 @@ fn resolveBuiltinTypeFields(...@@ -19458,43 +19497,44 @@ fn resolveBuiltinTypeFields(
19458 return sema.resolveTypeFields(block, src, resolved_ty);19497 return sema.resolveTypeFields(block, src, resolved_ty);
19459}19498}
1946019499
19461fn resolveInferredErrorSet(sema: *Sema, inferred_error_set: *Module.Fn.InferredErrorSet) CompileError!void {19500fn resolveInferredErrorSet(
19462 // Ensuring that a particular decl is analyzed does not neccesarily mean that19501 sema: *Sema,
19463 // it's error set is inferred, so traverse all of them to get the complete19502 block: *Block,
19464 // picture.19503 src: LazySrcLoc,
19465 // Note: We want to skip re-resolving the current function, as recursion19504 ies: *Module.Fn.InferredErrorSet,
19466 // doesn't change the error set. We can just check for state == .in_progress for this.19505) CompileError!void {
19467 // TODO: Is that correct?19506 if (ies.is_resolved) return;
1946819507
19469 if (inferred_error_set.is_resolved) {19508 if (ies.func.state == .in_progress) {
19470 return;19509 return sema.fail(block, src, "unable to resolve inferred error set", .{});
19471 }19510 }
19472 inferred_error_set.is_resolved = true;
1947319511
19474 var it = inferred_error_set.inferred_error_sets.keyIterator();19512 // To ensure that all dependencies are properly added to the set.
19475 while (it.next()) |other_error_set_ptr| {19513 try sema.ensureFuncBodyAnalyzed(ies.func);
19476 const func = other_error_set_ptr.*.func;
19477 const decl = func.*.owner_decl;
1947819514
19479 if (func.*.state == .in_progress) {19515 ies.is_resolved = true;
19480 // Recursion, doesn't alter current error set, keep going.
19481 continue;
19482 }
1948319516
19484 try sema.ensureDeclAnalyzed(decl); // To ensure that all dependencies are properly added to the set.19517 var it = ies.inferred_error_sets.keyIterator();
19485 try sema.resolveInferredErrorSet(other_error_set_ptr.*);19518 while (it.next()) |other_error_set_ptr| {
19519 const other_ies: *Module.Fn.InferredErrorSet = other_error_set_ptr.*;
19520 try sema.resolveInferredErrorSet(block, src, other_ies);
1948619521
19487 for (other_error_set_ptr.*.errors.keys()) |key| {19522 for (other_ies.errors.keys()) |key| {
19488 try inferred_error_set.errors.put(sema.gpa, key, {});19523 try ies.errors.put(sema.gpa, key, {});
19489 }19524 }
19490 if (other_error_set_ptr.*.is_anyerror)19525 if (other_ies.is_anyerror)
19491 inferred_error_set.is_anyerror = true;19526 ies.is_anyerror = true;
19492 }19527 }
19493}19528}
1949419529
19495fn resolveInferredErrorSetTy(sema: *Sema, ty: Type) CompileError!void {19530fn resolveInferredErrorSetTy(
19531 sema: *Sema,
19532 block: *Block,
19533 src: LazySrcLoc,
19534 ty: Type,
19535) CompileError!void {
19496 if (ty.castTag(.error_set_inferred)) |inferred| {19536 if (ty.castTag(.error_set_inferred)) |inferred| {
19497 try sema.resolveInferredErrorSet(inferred.data);19537 try sema.resolveInferredErrorSet(block, src, inferred.data);
19498 }19538 }
19499}19539}
1950019540
src/type.zig+5-5
...@@ -559,9 +559,9 @@ pub const Type = extern union {...@@ -559,9 +559,9 @@ pub const Type = extern union {
559 .error_set_inferred => {559 .error_set_inferred => {
560 // Inferred error sets are only equal if both are inferred560 // Inferred error sets are only equal if both are inferred
561 // and they originate from the exact same function.561 // and they originate from the exact same function.
562 const a_set = a.castTag(.error_set_inferred).?.data;562 const a_ies = a.castTag(.error_set_inferred).?.data;
563 const b_set = (b.castTag(.error_set_inferred) orelse return false).data;563 const b_ies = (b.castTag(.error_set_inferred) orelse return false).data;
564 return a_set.func == b_set.func;564 return a_ies == b_ies;
565 },565 },
566566
567 .anyerror => {567 .anyerror => {
...@@ -983,10 +983,10 @@ pub const Type = extern union {...@@ -983,10 +983,10 @@ pub const Type = extern union {
983983
984 .error_set_inferred => {984 .error_set_inferred => {
985 // inferred error sets are compared using their data pointer985 // inferred error sets are compared using their data pointer
986 const set = ty.castTag(.error_set_inferred).?.data;986 const ies: *Module.Fn.InferredErrorSet = ty.castTag(.error_set_inferred).?.data;
987 std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet);987 std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet);
988 std.hash.autoHash(hasher, Tag.error_set_inferred);988 std.hash.autoHash(hasher, Tag.error_set_inferred);
989 std.hash.autoHash(hasher, set.func);989 std.hash.autoHash(hasher, ies);
990 },990 },
991991
992 .@"opaque" => {992 .@"opaque" => {
test/behavior.zig+1
...@@ -61,6 +61,7 @@ test {...@@ -61,6 +61,7 @@ test {
61 _ = @import("behavior/bugs/7250.zig");61 _ = @import("behavior/bugs/7250.zig");
62 _ = @import("behavior/bugs/11100.zig");62 _ = @import("behavior/bugs/11100.zig");
63 _ = @import("behavior/bugs/10970.zig");63 _ = @import("behavior/bugs/10970.zig");
64 _ = @import("behavior/bugs/11046.zig");
64 _ = @import("behavior/call.zig");65 _ = @import("behavior/call.zig");
65 _ = @import("behavior/cast.zig");66 _ = @import("behavior/cast.zig");
66 _ = @import("behavior/comptime_memory.zig");67 _ = @import("behavior/comptime_memory.zig");
test/behavior/array.zig-3
...@@ -538,9 +538,6 @@ test "type coercion of anon struct literal to array" {...@@ -538,9 +538,6 @@ test "type coercion of anon struct literal to array" {
538 try expect(arr1[1] == 56);538 try expect(arr1[1] == 56);
539 try expect(arr1[2] == 54);539 try expect(arr1[2] == 54);
540540
541 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
542 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
543
544 var x2: U = .{ .a = 42 };541 var x2: U = .{ .a = 42 };
545 const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } };542 const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } };
546 var arr2: [3]U = t2;543 var arr2: [3]U = t2;
test/behavior/bugs/11046.zig created+21
...@@ -0,0 +1,21 @@
1const builtin = @import("builtin");
2
3fn foo() !void {
4 var a = true;
5 if (a) return error.Foo;
6 return error.Bar;
7}
8fn bar() !void {
9 try foo();
10}
11
12test "fixed" {
13 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16
17 bar() catch |err| switch (err) {
18 error.Foo => {}, // error: expected (inferred error set of bar), found error{Foo}
19 error.Bar => {},
20 };
21}
test/behavior/error.zig+5-1
...@@ -476,7 +476,11 @@ test "function pointer with return type that is error union with payload which i...@@ -476,7 +476,11 @@ test "function pointer with return type that is error union with payload which i
476}476}
477477
478test "return result loc as peer result loc in inferred error set function" {478test "return result loc as peer result loc in inferred error set function" {
479 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO479 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
480 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
481 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
483 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
480484
481 const S = struct {485 const S = struct {
482 fn doTheTest() !void {486 fn doTheTest() !void {