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");
1515const link = @import("link.zig");
1616const tracy = @import("tracy.zig");
1717const trace = tracy.trace;
18const Liveness = @import("Liveness.zig");
1918const build_options = @import("build_options");
2019const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
2120const glibc = @import("glibc.zig");
......@@ -2702,12 +2701,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
27022701 => return,
27032702
27042703 .complete, .codegen_failure_retryable => {
2705 const named_frame = tracy.namedFrame("codegen_decl");
2706 defer named_frame.end();
2707
27082704 if (build_options.omit_stage2)
27092705 @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
27112710 const module = comp.bin_file.options.module.?;
27122711 assert(decl.has_tv);
27132712
......@@ -2722,100 +2721,18 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
27222721 return;
27232722 },
27242723 },
2725 .codegen_func => |func| switch (func.owner_decl.analysis) {
2726 .unreferenced => unreachable,
2727 .in_progress => unreachable,
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 }
2724 .codegen_func => |func| {
2725 if (build_options.omit_stage2)
2726 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
27952727
2796 const named_frame = tracy.namedFrame("codegen");
2797 defer named_frame.end();
2728 const named_frame = tracy.namedFrame("codegen_func");
2729 defer named_frame.end();
27982730
2799 comp.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {
2800 error.OutOfMemory => return error.OutOfMemory,
2801 error.AnalysisFail => {
2802 decl.analysis = .codegen_failure;
2803 return;
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 },
2731 const module = comp.bin_file.options.module.?;
2732 module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
2733 error.OutOfMemory => return error.OutOfMemory,
2734 error.AnalysisFail => return,
2735 };
28192736 },
28202737 .emit_h_decl => |decl| switch (decl.analysis) {
28212738 .unreferenced => unreachable,
......@@ -2831,11 +2748,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
28312748 // emit-h only requires semantic analysis of the Decl to be complete,
28322749 // it does not depend on machine code generation to succeed.
28332750 .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
28342754 const named_frame = tracy.namedFrame("emit_h_decl");
28352755 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");
28392757 const gpa = comp.gpa;
28402758 const module = comp.bin_file.options.module.?;
28412759 const emit_h = module.emit_h.?;
......@@ -2871,11 +2789,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
28712789 },
28722790 },
28732791 .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
28742795 const named_frame = tracy.namedFrame("analyze_decl");
28752796 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");
28792798 const module = comp.bin_file.options.module.?;
28802799 module.ensureDeclAnalyzed(decl) catch |err| switch (err) {
28812800 error.OutOfMemory => return error.OutOfMemory,
......@@ -2883,11 +2802,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
28832802 };
28842803 },
28852804 .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
28862808 const named_frame = tracy.namedFrame("update_embed_file");
28872809 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");
28912811 const module = comp.bin_file.options.module.?;
28922812 module.updateEmbedFile(embed_file) catch |err| switch (err) {
28932813 error.OutOfMemory => return error.OutOfMemory,
......@@ -2895,11 +2815,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
28952815 };
28962816 },
28972817 .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
28982821 const named_frame = tracy.namedFrame("update_line_number");
28992822 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");
29032824 const gpa = comp.gpa;
29042825 const module = comp.bin_file.options.module.?;
29052826 comp.bin_file.updateDeclLineNumber(module, decl) catch |err| {
......@@ -2914,11 +2835,12 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
29142835 };
29152836 },
29162837 .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
29172841 const named_frame = tracy.namedFrame("analyze_pkg");
29182842 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");
29222844 const module = comp.bin_file.options.module.?;
29232845 module.semaPkg(pkg) catch |err| switch (err) {
29242846 error.CurrentWorkingDirectoryUnlinked,
src/Module.zig+106-15
......@@ -3,6 +3,7 @@
33//! there is or is not any zig source code, respectively.
44
55const std = @import("std");
6const builtin = @import("builtin");
67const mem = std.mem;
78const Allocator = std.mem.Allocator;
89const ArrayListUnmanaged = std.ArrayListUnmanaged;
......@@ -28,6 +29,7 @@ const AstGen = @import("AstGen.zig");
2829const Sema = @import("Sema.zig");
2930const target_util = @import("target.zig");
3031const build_options = @import("build_options");
32const Liveness = @import("Liveness.zig");
3133
3234/// General-purpose allocator. Used for both temporary and long-term storage.
3335gpa: Allocator,
......@@ -1438,8 +1440,11 @@ pub const Fn = struct {
14381440 is_cold: bool = false,
14391441 is_noinline: bool = false,
14401442
1441 /// Any inferred error sets that this function owns, both it's own inferred error set and
1442 /// inferred error sets of any inline/comptime functions called.
1443 /// Any inferred error sets that this function owns, both its own inferred error set and
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.
14431448 inferred_error_sets: InferredErrorSetList = .{},
14441449
14451450 pub const Analysis = enum {
......@@ -1457,28 +1462,29 @@ pub const Fn = struct {
14571462 };
14581463
14591464 /// 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,
1461 /// for example an inferred error set which this function returns, but also any inferred error sets
1462 /// of called inline or comptime functions.
1465 /// that return inferred error sets. Note that a function may be associated to
1466 /// multiple different error sets, for example an inferred error set which
1467 /// this function returns, but also any inferred error sets of called inline
1468 /// or comptime functions.
14631469 pub const InferredErrorSet = struct {
14641470 /// The function from which this error set originates.
1465 /// Note: may be the function itself.
14661471 func: *Fn,
14671472
1468 /// All currently known errors that this error set contains. This includes direct additions
1469 /// via `return error.Foo;`, and possibly also errors that are returned from any dependent functions.
1470 /// When the inferred error set is fully resolved, this map contains all the errors that the function might return.
1473 /// All currently known errors that this error set contains. This includes
1474 /// direct additions via `return error.Foo;`, and possibly also errors that
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.
14711477 errors: ErrorSet.NameMap = .{},
14721478
14731479 /// Other inferred error sets which this inferred error set should include.
14741480 inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{},
14751481
1476 /// Whether the function returned anyerror. This is true if either of the dependent functions
1477 /// returns anyerror.
1482 /// Whether the function returned anyerror. This is true if either of
1483 /// the dependent functions returns anyerror.
14781484 is_anyerror: bool = false,
14791485
1480 /// Whether this error set is already fully resolved. If true, resolving can skip resolving any dependents
1481 /// of this inferred error set.
1486 /// Whether this error set is already fully resolved. If true, resolving
1487 /// can skip resolving any dependents of this inferred error set.
14821488 is_resolved: bool = false,
14831489
14841490 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void {
......@@ -1494,8 +1500,8 @@ pub const Fn = struct {
14941500 try self.errors.put(gpa, name, {});
14951501 },
14961502 .error_set_inferred => {
1497 const set = err_set_ty.castTag(.error_set_inferred).?.data;
1498 try self.inferred_error_sets.put(gpa, set, {});
1503 const ies = err_set_ty.castTag(.error_set_inferred).?.data;
1504 try self.inferred_error_sets.put(gpa, ies, {});
14991505 },
15001506 .error_set_merged => {
15011507 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
......@@ -3441,6 +3447,10 @@ pub fn mapOldZirToNew(
34413447 }
34423448}
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.
34443454pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
34453455 const tracy = trace(@src());
34463456 defer tracy.end();
......@@ -3533,6 +3543,87 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
35333543 }
35343544}
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
35363627pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void {
35373628 const tracy = trace(@src());
35383629 defer tracy.end();
src/Sema.zig+105-65
......@@ -5346,14 +5346,14 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
53465346 }
53475347
53485348 if (lhs_ty.castTag(.error_set_inferred)) |payload| {
5349 try sema.resolveInferredErrorSet(payload.data);
5349 try sema.resolveInferredErrorSet(block, src, payload.data);
53505350 // isAnyError might have changed from a false negative to a true positive after resolution.
53515351 if (lhs_ty.isAnyError()) {
53525352 return Air.Inst.Ref.anyerror_type;
53535353 }
53545354 }
53555355 if (rhs_ty.castTag(.error_set_inferred)) |payload| {
5356 try sema.resolveInferredErrorSet(payload.data);
5356 try sema.resolveInferredErrorSet(block, src, payload.data);
53575357 // isAnyError might have changed from a false negative to a true positive after resolution.
53585358 if (rhs_ty.isAnyError()) {
53595359 return Air.Inst.Ref.anyerror_type;
......@@ -6927,7 +6927,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
69276927 }
69286928 }
69296929
6930 try sema.resolveInferredErrorSetTy(operand_ty);
6930 try sema.resolveInferredErrorSetTy(block, src, operand_ty);
69316931
69326932 if (operand_ty.isAnyError()) {
69336933 if (special_prong != .@"else") {
......@@ -10437,7 +10437,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1043710437 };
1043810438
1043910439 // 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
1044210442 // Build our list of Error values
1044310443 // Optional value is only null if anyerror
......@@ -12627,7 +12627,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1262712627 try sema.checkErrorSetType(block, operand_src, operand_ty);
1262812628
1262912629 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
12630 try sema.resolveInferredErrorSetTy(dest_ty);
12630 try sema.resolveInferredErrorSetTy(block, src, dest_ty);
1263112631
1263212632 if (!dest_ty.isAnyError()) {
1263312633 const error_name = val.castTag(.@"error").?.data.name;
......@@ -16616,7 +16616,7 @@ fn coerceInMemoryAllowed(
1661616616
1661716617 // Error Sets
1661816618 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);
1662016620 }
1662116621
1662216622 // Arrays
......@@ -16646,8 +16646,11 @@ fn coerceInMemoryAllowed(
1664616646
1664716647fn coerceInMemoryAllowedErrorSets(
1664816648 sema: *Sema,
16649 block: *Block,
1664916650 dest_ty: Type,
1665016651 src_ty: Type,
16652 dest_src: LazySrcLoc,
16653 src_src: LazySrcLoc,
1665116654) !InMemoryCoercionResult {
1665216655 // Coercion to `anyerror`. Note that this check can return false negatives
1665316656 // in case the error sets did not get resolved.
......@@ -16655,24 +16658,43 @@ fn coerceInMemoryAllowedErrorSets(
1665516658 return .ok;
1665616659 }
1665716660
16658 // If both are inferred error sets of functions, and
16659 // the dest includes the source function, the coercion is OK.
16660 // This check is important because it works without forcing a full resolution
16661 // of inferred error sets.
16662 if (src_ty.castTag(.error_set_inferred)) |src_payload| {
16663 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
16664 const src_func = src_payload.data.func;
16665 const dst_func = dst_payload.data.func;
16666
16667 if (src_func == dst_func or dst_payload.data.inferred_error_sets.contains(src_payload.data)) {
16668 return .ok;
16669 }
16670 return .no_match;
16661 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
16662 const dst_ies = dst_payload.data;
16663 // We will make an effort to return `ok` without resolving either error set, to
16664 // avoid unnecessary "unable to resolve error set" dependency loop errors.
16665 switch (src_ty.tag()) {
16666 .error_set_inferred => {
16667 // If both are inferred error sets of functions, and
16668 // the dest includes the source function, the coercion is OK.
16669 // This check is important because it works without forcing a full resolution
16670 // of inferred error sets.
16671 const src_ies = src_ty.castTag(.error_set_inferred).?.data;
16672
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,
1667116695 }
16672 }
1667316696
16674 if (dest_ty.castTag(.error_set_inferred)) |payload| {
16675 try sema.resolveInferredErrorSet(payload.data);
16697 try sema.resolveInferredErrorSet(block, dest_src, dst_payload.data);
1667616698 // isAnyError might have changed from a false negative to a true positive after resolution.
1667716699 if (dest_ty.isAnyError()) {
1667816700 return .ok;
......@@ -16683,7 +16705,7 @@ fn coerceInMemoryAllowedErrorSets(
1668316705 .error_set_inferred => {
1668416706 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);
1668716709 // src anyerror status might have changed after the resolution.
1668816710 if (src_ty.isAnyError()) {
1668916711 // dest_ty.isAnyError() == true is already checked for at this point.
......@@ -17969,6 +17991,17 @@ fn ensureDeclAnalyzed(sema: *Sema, decl: *Decl) CompileError!void {
1796917991 };
1797017992}
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
1797218005fn refValue(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, val: Value) !Value {
1797318006 var anon_decl = try block.startAnonDecl(src);
1797418007 defer anon_decl.deinit();
......@@ -18635,10 +18668,16 @@ fn wrapErrorUnionSet(
1863518668 },
1863618669 .error_set_inferred => ok: {
1863718670 const expected_name = val.castTag(.@"error").?.data.name;
18638 const data = dest_err_set_ty.castTag(.error_set_inferred).?.data;
18639 try sema.resolveInferredErrorSet(data);
18640 if (data.is_anyerror) break :ok;
18641 if (data.errors.contains(expected_name)) break :ok;
18671 const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data;
18672
18673 // We carefully do this in an order that avoids unnecessarily
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
1864218681 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
1864318682 },
1864418683 .error_set_merged => {
......@@ -18794,10 +18833,10 @@ fn resolvePeerTypes(
1879418833 // If neither is a superset, merge errors.
1879518834 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)) {
1879818837 continue;
1879918838 }
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)) {
1880118840 err_set_ty = null;
1880218841 chosen = candidate;
1880318842 chosen_i = candidate_i + 1;
......@@ -18810,10 +18849,10 @@ fn resolvePeerTypes(
1881018849 .ErrorUnion => {
1881118850 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)) {
1881418853 continue;
1881518854 }
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)) {
1881718856 err_set_ty = candidate_ty;
1881818857 continue;
1881918858 }
......@@ -18823,10 +18862,10 @@ fn resolvePeerTypes(
1882318862 },
1882418863 else => {
1882518864 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)) {
1882718866 continue;
1882818867 }
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)) {
1883018869 err_set_ty = candidate_ty;
1883118870 continue;
1883218871 }
......@@ -18844,9 +18883,9 @@ fn resolvePeerTypes(
1884418883 const chosen_set_ty = err_set_ty orelse chosen_ty;
1884518884 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)) {
1884818887 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)) {
1885018889 err_set_ty = null;
1885118890 } else {
1885218891 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
......@@ -18875,9 +18914,9 @@ fn resolvePeerTypes(
1887518914 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
1887618915 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)) {
1887918918 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)) {
1888118920 err_set_ty = candidate_set_ty;
1888218921 } else {
1888318922 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
......@@ -18889,9 +18928,9 @@ fn resolvePeerTypes(
1888918928 else => {
1889018929 if (err_set_ty) |chosen_set_ty| {
1889118930 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)) {
1889318932 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)) {
1889518934 err_set_ty = null;
1889618935 } else {
1889718936 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
......@@ -19458,43 +19497,44 @@ fn resolveBuiltinTypeFields(
1945819497 return sema.resolveTypeFields(block, src, resolved_ty);
1945919498}
1946019499
19461fn resolveInferredErrorSet(sema: *Sema, inferred_error_set: *Module.Fn.InferredErrorSet) CompileError!void {
19462 // Ensuring that a particular decl is analyzed does not neccesarily mean that
19463 // it's error set is inferred, so traverse all of them to get the complete
19464 // picture.
19465 // Note: We want to skip re-resolving the current function, as recursion
19466 // doesn't change the error set. We can just check for state == .in_progress for this.
19467 // TODO: Is that correct?
19500fn resolveInferredErrorSet(
19501 sema: *Sema,
19502 block: *Block,
19503 src: LazySrcLoc,
19504 ies: *Module.Fn.InferredErrorSet,
19505) CompileError!void {
19506 if (ies.is_resolved) return;
1946819507
19469 if (inferred_error_set.is_resolved) {
19470 return;
19508 if (ies.func.state == .in_progress) {
19509 return sema.fail(block, src, "unable to resolve inferred error set", .{});
1947119510 }
19472 inferred_error_set.is_resolved = true;
1947319511
19474 var it = inferred_error_set.inferred_error_sets.keyIterator();
19475 while (it.next()) |other_error_set_ptr| {
19476 const func = other_error_set_ptr.*.func;
19477 const decl = func.*.owner_decl;
19512 // To ensure that all dependencies are properly added to the set.
19513 try sema.ensureFuncBodyAnalyzed(ies.func);
1947819514
19479 if (func.*.state == .in_progress) {
19480 // Recursion, doesn't alter current error set, keep going.
19481 continue;
19482 }
19515 ies.is_resolved = true;
1948319516
19484 try sema.ensureDeclAnalyzed(decl); // To ensure that all dependencies are properly added to the set.
19485 try sema.resolveInferredErrorSet(other_error_set_ptr.*);
19517 var it = ies.inferred_error_sets.keyIterator();
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| {
19488 try inferred_error_set.errors.put(sema.gpa, key, {});
19522 for (other_ies.errors.keys()) |key| {
19523 try ies.errors.put(sema.gpa, key, {});
1948919524 }
19490 if (other_error_set_ptr.*.is_anyerror)
19491 inferred_error_set.is_anyerror = true;
19525 if (other_ies.is_anyerror)
19526 ies.is_anyerror = true;
1949219527 }
1949319528}
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 {
1949619536 if (ty.castTag(.error_set_inferred)) |inferred| {
19497 try sema.resolveInferredErrorSet(inferred.data);
19537 try sema.resolveInferredErrorSet(block, src, inferred.data);
1949819538 }
1949919539}
1950019540
src/type.zig+5-5
......@@ -559,9 +559,9 @@ pub const Type = extern union {
559559 .error_set_inferred => {
560560 // Inferred error sets are only equal if both are inferred
561561 // and they originate from the exact same function.
562 const a_set = a.castTag(.error_set_inferred).?.data;
563 const b_set = (b.castTag(.error_set_inferred) orelse return false).data;
564 return a_set.func == b_set.func;
562 const a_ies = a.castTag(.error_set_inferred).?.data;
563 const b_ies = (b.castTag(.error_set_inferred) orelse return false).data;
564 return a_ies == b_ies;
565565 },
566566
567567 .anyerror => {
......@@ -983,10 +983,10 @@ pub const Type = extern union {
983983
984984 .error_set_inferred => {
985985 // 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;
987987 std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet);
988988 std.hash.autoHash(hasher, Tag.error_set_inferred);
989 std.hash.autoHash(hasher, set.func);
989 std.hash.autoHash(hasher, ies);
990990 },
991991
992992 .@"opaque" => {
test/behavior.zig+1
......@@ -61,6 +61,7 @@ test {
6161 _ = @import("behavior/bugs/7250.zig");
6262 _ = @import("behavior/bugs/11100.zig");
6363 _ = @import("behavior/bugs/10970.zig");
64 _ = @import("behavior/bugs/11046.zig");
6465 _ = @import("behavior/call.zig");
6566 _ = @import("behavior/cast.zig");
6667 _ = @import("behavior/comptime_memory.zig");
test/behavior/array.zig-3
......@@ -538,9 +538,6 @@ test "type coercion of anon struct literal to array" {
538538 try expect(arr1[1] == 56);
539539 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
544541 var x2: U = .{ .a = 42 };
545542 const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } };
546543 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
476476}
477477
478478test "return result loc as peer result loc in inferred error set function" {
479 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
479 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
481485 const S = struct {
482486 fn doTheTest() !void {