authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-27 11:46:48+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:08+00:00
log334189ce6d20d6d1100f115252d5589fadb064b1
tree489120f03743b1ba7ad5a18b0ed9083e365d8616
parente3e9ae12bd3a7c08f3ed41e801f6cf34bec01af2
signaturelock-open Commit is signed but in an unrecognized format.

compiler: simplify IESes

It is always a bug in Sema to check whether an IES is resolved. This is because whether the IES is resolved depends on whether the function which owns it has been analyzed yet, which depends on the order the compiler analyzes declarations in, which it is incorrect to have any dependency on. Instead, we must always either not look at the resolved set, or resolve it first (with `Sema.ensureFuncIesResolved`) and then look at the definitely-resolved concrete error set. Luckily, removing a bunch of the buggy logic which tried to opportunistically use already-resolved inferred error sets actually didn't regress anything! It seems this logic was mostly left over from before Andrew reworked inferred error sets, and had become essentially dead code. This is because inferred error sets are stricter than they used to be, and in particular, we make no attempt to support mutual recursion. I suspect that most of the logic touching IESes can be simplified even further than I have done here without regressing any existing code; my goal in this commit was just to remove any *buggy* code I could find.

5 files changed, 232 insertions(+), 380 deletions(-)

src/Sema.zig+217-343
...@@ -7870,21 +7870,21 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -7870,21 +7870,21 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
7870 return .anyerror_type;7870 return .anyerror_type;
7871 }7871 }
78727872
7873 if (ip.isInferredErrorSetType(lhs_ty.toIntern())) {7873 switch (ip.indexToKey(lhs_ty.toIntern())) {
7874 switch (try sema.resolveInferredErrorSet(block, src, lhs_ty.toIntern())) {7874 .inferred_error_set_type => |func_index| {
7875 // isAnyError might have changed from a false negative to a true7875 try sema.ensureFuncIesResolved(block, src, func_index);
7876 // positive after resolution.7876 if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type;
7877 .anyerror_type => return .anyerror_type,7877 },
7878 else => {},7878 .error_set_type => {},
7879 }7879 else => unreachable,
7880 }7880 }
7881 if (ip.isInferredErrorSetType(rhs_ty.toIntern())) {7881 switch (ip.indexToKey(rhs_ty.toIntern())) {
7882 switch (try sema.resolveInferredErrorSet(block, src, rhs_ty.toIntern())) {7882 .inferred_error_set_type => |func_index| {
7883 // isAnyError might have changed from a false negative to a true7883 try sema.ensureFuncIesResolved(block, src, func_index);
7884 // positive after resolution.7884 if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type;
7885 .anyerror_type => return .anyerror_type,7885 },
7886 else => {},7886 .error_set_type => {},
7887 }7887 else => unreachable,
7888 }7888 }
78897889
7890 const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty);7890 const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty);
...@@ -12000,7 +12000,7 @@ fn wantSwitchProngBodyAnalysis(...@@ -12000,7 +12000,7 @@ fn wantSwitchProngBodyAnalysis(
12000 if (err_set and prong_is_comptime_unreach) {12000 if (err_set and prong_is_comptime_unreach) {
12001 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;12001 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;
12002 const err_name = item_val.getErrorName(zcu).unwrap().?;12002 const err_name = item_val.getErrorName(zcu).unwrap().?;
12003 if (!Type.errorSetHasFieldIp(&zcu.intern_pool, operand_ty.toIntern(), err_name)) return false;12003 if (!operand_ty.errorSetHasField(err_name, zcu)) return false;
12004 }12004 }
12005 return true;12005 return true;
12006}12006}
...@@ -21023,34 +21023,61 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData...@@ -21023,34 +21023,61 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
21023 else => unreachable,21023 else => unreachable,
21024 };21024 };
2102521025
21026 const disjoint = disjoint: {21026 switch (ip.indexToKey(operand_err_ty.toIntern())) {
21027 // Try avoiding resolving inferred error sets if we can21027 .inferred_error_set_type => |func| try sema.ensureFuncIesResolved(block, src, func),
21028 if (!dest_err_ty.isAnyError(zcu) and dest_err_ty.errorSetIsEmpty(zcu)) break :disjoint true;21028 else => {},
21029 if (!operand_err_ty.isAnyError(zcu) and operand_err_ty.errorSetIsEmpty(zcu)) break :disjoint true;21029 }
21030 if (dest_err_ty.isAnyError(zcu)) break :disjoint false;
21031 if (operand_err_ty.isAnyError(zcu)) break :disjoint false;
21032 const dest_err_names = dest_err_ty.errorSetNames(zcu);
21033 for (0..dest_err_names.len) |dest_err_index| {
21034 if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
21035 break :disjoint false;
21036 }
21037
21038 if (!ip.isInferredErrorSetType(dest_err_ty.toIntern()) and
21039 !ip.isInferredErrorSetType(operand_err_ty.toIntern()))
21040 {
21041 break :disjoint true;
21042 }
21043
21044 _ = try sema.resolveInferredErrorSetTy(block, src, dest_err_ty.toIntern());
21045 _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_err_ty.toIntern());
21046 for (0..dest_err_names.len) |dest_err_index| {
21047 if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
21048 break :disjoint false;
21049 }
2105021030
21051 break :disjoint true;21031 const result: enum {
21032 /// The operand and destination error sets are disjoint, i.e. have no errors in common.
21033 disjoint,
21034 /// The destination error set is a superset of the operand error set, so the operation is
21035 /// effectively equivalent to a coercion.
21036 superset,
21037 /// The operand and destination error sets have *some* errors in common, but the destination
21038 /// is not a superset of the operand, so a safety check may be needed.
21039 overlap,
21040 } = if (operand_err_ty.errorSetIsEmpty(zcu)) res: {
21041 break :res .disjoint;
21042 } else check: switch (dest_err_ty.toIntern()) {
21043 .anyerror_type => .superset,
21044 .adhoc_inferred_error_set_type => {
21045 // `@errorCast` to this function's own error set.
21046 try sema.fn_ret_ty_ies.?.addErrorSet(operand_err_ty, ip, sema.arena);
21047 break :check .superset;
21048 },
21049 else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) {
21050 .inferred_error_set_type => |func_index| {
21051 if (sema.fn_ret_ty_ies) |dst_ies| {
21052 if (dst_ies.func == func_index) {
21053 // `@errorCast` to this function's own error set.
21054 try sema.fn_ret_ty_ies.?.addErrorSet(operand_err_ty, ip, sema.arena);
21055 break :check .superset;
21056 }
21057 }
21058 try sema.ensureFuncIesResolved(block, src, func_index);
21059 continue :check ip.funcIesResolvedUnordered(func_index);
21060 },
21061 .error_set_type => |dest| {
21062 if (operand_err_ty.isAnyError(zcu)) break :check .superset;
21063 var dest_has_all = true;
21064 var dest_has_any = false;
21065 for (operand_err_ty.errorSetNames(zcu).get(ip)) |operand_err_name| {
21066 if (dest.nameIndex(ip, operand_err_name) != null) {
21067 dest_has_any = true;
21068 } else {
21069 dest_has_all = false;
21070 }
21071 }
21072 if (!dest_has_any) break :check .disjoint;
21073 if (dest_has_all) break :check .superset;
21074 break :check .overlap;
21075 },
21076 else => unreachable,
21077 },
21052 };21078 };
21053 if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) {21079
21080 if (result == .disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) {
21054 return sema.fail(block, src, "error sets '{f}' and '{f}' have no common errors", .{21081 return sema.fail(block, src, "error sets '{f}' and '{f}' have no common errors", .{
21055 operand_err_ty.fmt(pt), dest_err_ty.fmt(pt),21082 operand_err_ty.fmt(pt), dest_err_ty.fmt(pt),
21056 });21083 });
...@@ -21058,25 +21085,30 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData...@@ -21058,25 +21085,30 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2105821085
21059 // operand must be defined since it can be an invalid error value21086 // operand must be defined since it can be an invalid error value
21060 if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {21087 if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {
21061 const err_name: InternPool.NullTerminatedString = switch (operand_tag) {21088 const err_name: InternPool.NullTerminatedString = switch (ip.indexToKey(operand_val.toIntern())) {
21062 .error_set => ip.indexToKey(operand_val.toIntern()).err.name,21089 .err => |err| err.name,
21063 .error_union => switch (ip.indexToKey(operand_val.toIntern()).error_union.val) {21090 .error_union => |eu| switch (eu.val) {
21064 .err_name => |name| name,21091 .err_name => |name| name,
21065 .payload => |payload_val| {21092 .payload => |payload_val| {
21066 assert(dest_tag == .error_union); // should be guaranteed from the type checks above21093 assert(dest_tag == .error_union); // should be guaranteed from the type checks above
21067 return sema.coerce(block, dest_ty, Air.internedToRef(payload_val), operand_src);21094 const dest_payload_ty = dest_ty.errorUnionPayload(zcu);
21095 const coerced_payload = try sema.coerce(block, dest_payload_ty, .fromIntern(payload_val), operand_src);
21096 return sema.wrapErrorUnionPayload(block, dest_ty, coerced_payload, operand_src) catch |err| switch (err) {
21097 error.NotCoercible => unreachable,
21098 else => |e| return e,
21099 };
21068 },21100 },
21069 },21101 },
21070 else => unreachable,21102 else => unreachable,
21071 };21103 };
2107221104
21073 if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) {21105 if (!dest_err_ty.isAnyError(zcu) and !dest_err_ty.errorSetHasField(err_name, zcu)) {
21074 return sema.fail(block, src, "'error.{f}' not a member of error set '{f}'", .{21106 return sema.fail(block, src, "'error.{f}' not a member of error set '{f}'", .{
21075 err_name.fmt(ip), dest_err_ty.fmt(pt),21107 err_name.fmt(ip), dest_err_ty.fmt(pt),
21076 });21108 });
21077 }21109 }
2107821110
21079 return Air.internedToRef(try pt.intern(switch (dest_tag) {21111 return .fromIntern(try pt.intern(switch (dest_tag) {
21080 .error_set => .{ .err = .{21112 .error_set => .{ .err = .{
21081 .ty = dest_ty.toIntern(),21113 .ty = dest_ty.toIntern(),
21082 .name = err_name,21114 .name = err_name,
...@@ -21090,21 +21122,17 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData...@@ -21090,21 +21122,17 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
21090 }21122 }
2109121123
21092 const err_int_ty = try pt.errorIntType();21124 const err_int_ty = try pt.errorIntType();
21093 if (block.wantSafety() and !dest_err_ty.isAnyError(zcu) and21125 if (block.wantSafety() and result != .superset and zcu.backendSupportsFeature(.error_set_has_value)) {
21094 dest_err_ty.toIntern() != .adhoc_inferred_error_set_type and
21095 zcu.backendSupportsFeature(.error_set_has_value))
21096 {
21097 const err_code_inst = switch (operand_tag) {21126 const err_code_inst = switch (operand_tag) {
21098 .error_set => operand,21127 .error_set => operand,
21099 .error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand),21128 .error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand),
21100 else => unreachable,21129 else => unreachable,
21101 };21130 };
21102 const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst);21131 const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst);
21103
21104 if (dest_tag == .error_union) {21132 if (dest_tag == .error_union) {
21105 const zero_err = try pt.intRef(err_int_ty, 0);21133 const zero_err = try pt.intRef(err_int_ty, 0);
21106 const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err);21134 const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err);
21107 if (disjoint) {21135 if (result == .disjoint) {
21108 // Error must be zero.21136 // Error must be zero.
21109 try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code);21137 try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code);
21110 } else {21138 } else {
...@@ -25599,31 +25627,28 @@ fn fieldVal(...@@ -25599,31 +25627,28 @@ fn fieldVal(
2559925627
25600 switch (child_type.zigTypeTag(zcu)) {25628 switch (child_type.zigTypeTag(zcu)) {
25601 .error_set => {25629 .error_set => {
25602 switch (ip.indexToKey(child_type.toIntern())) {25630 const err_set_ty: Type = err_set: switch (ip.indexToKey(child_type.toIntern())) {
25603 .error_set_type => |error_set_type| blk: {25631 .inferred_error_set_type => |func_index| {
25604 if (error_set_type.nameIndex(ip, field_name) != null) break :blk;25632 try sema.ensureFuncIesResolved(block, src, func_index);
25633 const resolved_ies = ip.funcIesResolvedUnordered(func_index);
25634 continue :err_set ip.indexToKey(resolved_ies);
25635 },
25636 .error_set_type => |err_set| if (err_set.nameIndex(ip, field_name) == null) {
25605 return sema.fail(block, src, "no error named '{f}' in '{f}'", .{25637 return sema.fail(block, src, "no error named '{f}' in '{f}'", .{
25606 field_name.fmt(ip), child_type.fmt(pt),25638 field_name.fmt(ip), child_type.fmt(pt),
25607 });25639 });
25608 },25640 } else child_type,
25609 .inferred_error_set_type => {
25610 return sema.fail(block, src, "TODO handle inferred error sets here", .{});
25611 },
25612 .simple_type => |t| {25641 .simple_type => |t| {
25613 assert(t == .anyerror);25642 assert(t == .anyerror);
25614 _ = try pt.getErrorValue(field_name);25643 _ = try pt.getErrorValue(field_name);
25644 break :err_set try pt.singleErrorSetType(field_name);
25615 },25645 },
25616 else => unreachable,25646 else => unreachable,
25617 }25647 };
2561825648 return .fromIntern(try pt.intern(.{ .err = .{
25619 const error_set_type = if (!child_type.isAnyError(zcu))25649 .ty = err_set_ty.toIntern(),
25620 child_type
25621 else
25622 try pt.singleErrorSetType(field_name);
25623 return Air.internedToRef((try pt.intern(.{ .err = .{
25624 .ty = error_set_type.toIntern(),
25625 .name = field_name,25650 .name = field_name,
25626 } })));25651 } }));
25627 },25652 },
25628 .@"union" => {25653 .@"union" => {
25629 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25654 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
...@@ -25832,31 +25857,26 @@ fn fieldPtr(...@@ -25832,31 +25857,26 @@ fn fieldPtr(
2583225857
25833 switch (child_type.zigTypeTag(zcu)) {25858 switch (child_type.zigTypeTag(zcu)) {
25834 .error_set => {25859 .error_set => {
25835 switch (ip.indexToKey(child_type.toIntern())) {25860 const err_set_ty: Type = err_set: switch (ip.indexToKey(child_type.toIntern())) {
25836 .error_set_type => |error_set_type| blk: {25861 .inferred_error_set_type => |func_index| {
25837 if (error_set_type.nameIndex(ip, field_name) != null) {25862 try sema.ensureFuncIesResolved(block, src, func_index);
25838 break :blk;25863 const resolved_ies = ip.funcIesResolvedUnordered(func_index);
25839 }25864 continue :err_set ip.indexToKey(resolved_ies);
25865 },
25866 .error_set_type => |err_set| if (err_set.nameIndex(ip, field_name) == null) {
25840 return sema.fail(block, src, "no error named '{f}' in '{f}'", .{25867 return sema.fail(block, src, "no error named '{f}' in '{f}'", .{
25841 field_name.fmt(ip), child_type.fmt(pt),25868 field_name.fmt(ip), child_type.fmt(pt),
25842 });25869 });
25843 },25870 } else child_type,
25844 .inferred_error_set_type => {
25845 return sema.fail(block, src, "TODO handle inferred error sets here", .{});
25846 },
25847 .simple_type => |t| {25871 .simple_type => |t| {
25848 assert(t == .anyerror);25872 assert(t == .anyerror);
25849 _ = try pt.getErrorValue(field_name);25873 _ = try pt.getErrorValue(field_name);
25874 break :err_set try pt.singleErrorSetType(field_name);
25850 },25875 },
25851 else => unreachable,25876 else => unreachable,
25852 }25877 };
25853
25854 const error_set_type = if (!child_type.isAnyError(zcu))
25855 child_type
25856 else
25857 try pt.singleErrorSetType(field_name);
25858 return uavRef(sema, try pt.intern(.{ .err = .{25878 return uavRef(sema, try pt.intern(.{ .err = .{
25859 .ty = error_set_type.toIntern(),25879 .ty = err_set_ty.toIntern(),
25860 .name = field_name,25880 .name = field_name,
25861 } }));25881 } }));
25862 },25882 },
...@@ -27760,23 +27780,27 @@ fn coerceExtra(...@@ -27760,23 +27780,27 @@ fn coerceExtra(
27760 else => {},27780 else => {},
27761 },27781 },
27762 .error_union => switch (inst_ty.zigTypeTag(zcu)) {27782 .error_union => switch (inst_ty.zigTypeTag(zcu)) {
27763 .error_set => {27783 // E to E!T
27764 // E to E!T27784 .error_set => if (sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src)) |res| {
27765 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);27785 return res;
27786 } else |err| switch (err) {
27787 error.NotCoercible => if (in_memory_result == .no_match) {
27788 // Try to give more useful notes
27789 const err_set_type = dest_ty.errorUnionSet(zcu);
27790 in_memory_result = try sema.coerceInMemoryAllowed(block, err_set_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val);
27791 },
27792 else => |e| return e,
27766 },27793 },
27767 else => eu: {27794 // T to E!T
27768 // T to E!T27795 else => if (sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src)) |res| {
27769 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {27796 return res;
27770 error.NotCoercible => {27797 } else |err| switch (err) {
27771 if (in_memory_result == .no_match) {27798 error.NotCoercible => if (in_memory_result == .no_match) {
27772 const payload_type = dest_ty.errorUnionPayload(zcu);27799 // Try to give more useful notes
27773 // Try to give more useful notes27800 const payload_type = dest_ty.errorUnionPayload(zcu);
27774 in_memory_result = try sema.coerceInMemoryAllowed(block, payload_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val);27801 in_memory_result = try sema.coerceInMemoryAllowed(block, payload_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val);
27775 }27802 },
27776 break :eu;27803 else => |e| return e,
27777 },
27778 else => |e| return e,
27779 };
27780 },27804 },
27781 },27805 },
27782 .@"union" => switch (inst_ty.zigTypeTag(zcu)) {27806 .@"union" => switch (inst_ty.zigTypeTag(zcu)) {
...@@ -28542,89 +28566,62 @@ fn coerceInMemoryAllowedErrorSets(...@@ -28542,89 +28566,62 @@ fn coerceInMemoryAllowedErrorSets(
28542 const gpa = sema.gpa;28566 const gpa = sema.gpa;
28543 const ip = &zcu.intern_pool;28567 const ip = &zcu.intern_pool;
2854428568
28545 // Coercion to `anyerror`. Note that this check can return false negatives28569 const dest_set: InternPool.Key.ErrorSetType = err_set: switch (dest_ty.toIntern()) {
28546 // in case the error sets did not get resolved.28570 .anyerror_type => return .ok,
28547 if (dest_ty.isAnyError(zcu)) {28571 .adhoc_inferred_error_set_type => {
28548 return .ok;28572 // We are trying to coerce an error set to the current function's
28549 }28573 // inferred error set.
2855028574 const dst_ies = sema.fn_ret_ty_ies.?;
28551 if (dest_ty.toIntern() == .adhoc_inferred_error_set_type) {28575 try dst_ies.addErrorSet(src_ty, ip, sema.arena);
28552 // We are trying to coerce an error set to the current function's28576 return .ok;
28553 // inferred error set.
28554 const dst_ies = sema.fn_ret_ty_ies.?;
28555 try dst_ies.addErrorSet(src_ty, ip, sema.arena);
28556 return .ok;
28557 }
28558
28559 if (ip.isInferredErrorSetType(dest_ty.toIntern())) {
28560 const dst_ies_func_index = ip.iesFuncIndex(dest_ty.toIntern());
28561 if (sema.fn_ret_ty_ies) |dst_ies| {
28562 if (dst_ies.func == dst_ies_func_index) {
28563 // We are trying to coerce an error set to the current function's
28564 // inferred error set.
28565 try dst_ies.addErrorSet(src_ty, ip, sema.arena);
28566 return .ok;
28567 }
28568 }
28569 switch (try sema.resolveInferredErrorSet(block, dest_src, dest_ty.toIntern())) {
28570 // isAnyError might have changed from a false negative to a true
28571 // positive after resolution.
28572 .anyerror_type => return .ok,
28573 else => {},
28574 }
28575 }
28576
28577 var missing_error_buf = std.array_list.Managed(InternPool.NullTerminatedString).init(gpa);
28578 defer missing_error_buf.deinit();
28579
28580 switch (src_ty.toIntern()) {
28581 .anyerror_type => switch (ip.indexToKey(dest_ty.toIntern())) {
28582 .simple_type => unreachable, // filtered out above
28583 .error_set_type, .inferred_error_set_type => return .from_anyerror,
28584 else => unreachable,
28585 },28577 },
2858628578 else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) {
28587 else => switch (ip.indexToKey(src_ty.toIntern())) {28579 .inferred_error_set_type => |func_index| {
28588 .inferred_error_set_type => {28580 if (sema.fn_ret_ty_ies) |dst_ies| {
28589 const resolved_src_ty = try sema.resolveInferredErrorSet(block, src_src, src_ty.toIntern());28581 if (dst_ies.func == func_index) {
28590 // src anyerror status might have changed after the resolution.28582 // We are trying to coerce an error set to the current function's
28591 if (resolved_src_ty == .anyerror_type) {28583 // inferred error set.
28592 // dest_ty.isAnyError(zcu) == true is already checked for at this point.28584 try dst_ies.addErrorSet(src_ty, ip, sema.arena);
28593 return .from_anyerror;28585 return .ok;
28594 }
28595
28596 for (ip.indexToKey(resolved_src_ty).error_set_type.names.get(ip)) |key| {
28597 if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) {
28598 try missing_error_buf.append(key);
28599 }28586 }
28600 }28587 }
2860128588 try sema.ensureFuncIesResolved(block, dest_src, func_index);
28602 if (missing_error_buf.items.len != 0) {28589 continue :err_set ip.funcIesResolvedUnordered(func_index);
28603 return InMemoryCoercionResult{
28604 .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
28605 };
28606 }
28607
28608 return .ok;
28609 },28590 },
28610 .error_set_type => |error_set_type| {28591 .error_set_type => |err_set| err_set,
28611 for (error_set_type.names.get(ip)) |name| {28592 else => unreachable,
28612 if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) {28593 },
28613 try missing_error_buf.append(name);28594 };
28614 }
28615 }
28616
28617 if (missing_error_buf.items.len != 0) {
28618 return InMemoryCoercionResult{
28619 .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
28620 };
28621 }
2862228595
28623 return .ok;28596 const src_names: InternPool.NullTerminatedString.Slice = err_set: switch (src_ty.toIntern()) {
28597 .anyerror_type => return .from_anyerror,
28598 else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) {
28599 .inferred_error_set_type => |func_index| {
28600 try sema.ensureFuncIesResolved(block, src_src, func_index);
28601 continue :err_set ip.funcIesResolvedUnordered(func_index);
28624 },28602 },
28603 .error_set_type => |err_set| err_set.names,
28625 else => unreachable,28604 else => unreachable,
28626 },28605 },
28606 };
28607
28608 var missing_error_buf: std.ArrayList(InternPool.NullTerminatedString) = .empty;
28609 defer missing_error_buf.deinit(gpa);
28610
28611 for (src_names.get(ip)) |name| {
28612 if (dest_set.nameIndex(ip, name) == null) {
28613 try missing_error_buf.append(gpa, name);
28614 }
28615 }
28616
28617 if (missing_error_buf.items.len != 0) {
28618 return .{ .missing_error = try sema.arena.dupe(
28619 InternPool.NullTerminatedString,
28620 missing_error_buf.items,
28621 ) };
28627 }28622 }
28623
28624 return .ok;
28628}28625}
2862928626
28630fn coerceInMemoryAllowedFns(28627fn coerceInMemoryAllowedFns(
...@@ -30357,76 +30354,34 @@ fn resolveIsNonErrFromType(...@@ -30357,76 +30354,34 @@ fn resolveIsNonErrFromType(
3035730354
30358 // exception if the error union error set is known to be empty,30355 // exception if the error union error set is known to be empty,
30359 // we allow the comparison but always make it comptime-known.30356 // we allow the comparison but always make it comptime-known.
30360 const set_ty = ip.errorUnionSet(operand_ty.toIntern());30357 return err_set: switch (ip.errorUnionSet(operand_ty.toIntern())) {
30361 switch (set_ty) {30358 .anyerror_type => null,
30362 .anyerror_type => {},30359 .adhoc_inferred_error_set_type => {
30363 .adhoc_inferred_error_set_type => if (sema.fn_ret_ty_ies) |ies| blk: {30360 // This is *our* error set; that is, we're currently analyzing the function
30364 // If the error set is empty, we must return a comptime true or false.30361 // which owns it. Trying to resolve it now would cause a dependency loop.
30365 // However we want to avoid unnecessarily resolving an inferred error set30362 // Instead, accept that we don't know.
30366 // in case it is already non-empty.30363 if (true) return null;
30367 switch (ies.resolved) {30364 },
30368 .anyerror_type => break :blk,30365 else => |set_ty| switch (ip.indexToKey(set_ty)) {
30369 .none => {},30366 .error_set_type => |error_set_type| switch (error_set_type.names.len) {
30370 else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk,30367 0 => .true,
30371 }30368 else => null,
30372
30373 if (ies.errors.count() != 0) return null;
30374 switch (ies.resolved) {
30375 .anyerror_type => return null,
30376 .none => {},
30377 else => switch (ip.indexToKey(ies.resolved).error_set_type.names.len) {
30378 0 => return .true,
30379 else => return null,
30380 },
30381 }
30382 // We do not have a comptime answer because this inferred error
30383 // set is not resolved, and an instruction later in this function
30384 // body may or may not cause an error to be added to this set.
30385 return null;
30386 },
30387 else => switch (ip.indexToKey(set_ty)) {
30388 .error_set_type => |error_set_type| {
30389 if (error_set_type.names.len == 0) return .true;
30390 },30369 },
30391 .inferred_error_set_type => |func_index| blk: {30370 .inferred_error_set_type => |func_index| {
30392 // If the error set is empty, we must return a comptime true or false.
30393 // However we want to avoid unnecessarily resolving an inferred error set
30394 // in case it is already non-empty.
30395 try zcu.maybeUnresolveIes(func_index);
30396 switch (ip.funcIesResolvedUnordered(func_index)) {
30397 .anyerror_type => break :blk,
30398 .none => {},
30399 else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk,
30400 }
30401 if (sema.fn_ret_ty_ies) |ies| {30371 if (sema.fn_ret_ty_ies) |ies| {
30402 if (ies.func == func_index) {30372 if (ies.func == func_index) {
30403 // Try to avoid resolving inferred error set if possible.30373 // This is *our* error set; that is, we're currently analyzing the function
30404 if (ies.errors.count() != 0) return null;30374 // which owns it. Trying to resolve it now would cause a dependency loop.
30405 switch (ies.resolved) {30375 // Instead, accept that we don't know.
30406 .anyerror_type => return null,
30407 .none => {},
30408 else => switch (ip.indexToKey(ies.resolved).error_set_type.names.len) {
30409 0 => return .true,
30410 else => return null,
30411 },
30412 }
30413 // We do not have a comptime answer because this inferred error
30414 // set is not resolved, and an instruction later in this function
30415 // body may or may not cause an error to be added to this set.
30416 return null;30376 return null;
30417 }30377 }
30418 }30378 }
30419 const resolved_ty = try sema.resolveInferredErrorSet(block, src, set_ty);30379 try sema.ensureFuncIesResolved(block, src, func_index);
30420 if (resolved_ty == .anyerror_type)30380 continue :err_set ip.funcIesResolvedUnordered(func_index);
30421 break :blk;
30422 if (ip.indexToKey(resolved_ty).error_set_type.names.len == 0)
30423 return .true;
30424 },30381 },
30425 else => unreachable,30382 else => unreachable,
30426 },30383 },
30427 }30384 };
30428
30429 return null;
30430}30385}
3043130386
30432fn analyzeIsNonErr(30387fn analyzeIsNonErr(
...@@ -31384,58 +31339,16 @@ fn wrapErrorUnionSet(...@@ -31384,58 +31339,16 @@ fn wrapErrorUnionSet(
31384 const pt = sema.pt;31339 const pt = sema.pt;
31385 const zcu = pt.zcu;31340 const zcu = pt.zcu;
31386 const ip = &zcu.intern_pool;31341 const ip = &zcu.intern_pool;
31387 const inst_ty = sema.typeOf(inst);
31388 const dest_err_set_ty = dest_ty.errorUnionSet(zcu);31342 const dest_err_set_ty = dest_ty.errorUnionSet(zcu);
31389 if (sema.resolveValue(inst)) |val| {31343 const coerced = try sema.coerceExtra(block, dest_err_set_ty, inst, inst_src, .{ .report_err = false });
31390 const expected_name = zcu.intern_pool.indexToKey(val.toIntern()).err.name;31344 if (try sema.resolveDefinedValue(block, inst_src, coerced)) |error_val| {
31391 switch (dest_err_set_ty.toIntern()) {31345 return .fromIntern(try pt.intern(.{ .error_union = .{
31392 .anyerror_type => {},
31393 .adhoc_inferred_error_set_type => ok: {
31394 const ies = sema.fn_ret_ty_ies.?;
31395 switch (ies.resolved) {
31396 .anyerror_type => break :ok,
31397 .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
31398 break :ok;
31399 },
31400 else => |i| if (ip.indexToKey(i).error_set_type.nameIndex(ip, expected_name) != null) {
31401 break :ok;
31402 },
31403 }
31404 return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty);
31405 },
31406 else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) {
31407 .error_set_type => |error_set_type| ok: {
31408 if (error_set_type.nameIndex(ip, expected_name) != null) break :ok;
31409 return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty);
31410 },
31411 .inferred_error_set_type => |func_index| ok: {
31412 // We carefully do this in an order that avoids unnecessarily
31413 // resolving the destination error set type.
31414 try zcu.maybeUnresolveIes(func_index);
31415 switch (ip.funcIesResolvedUnordered(func_index)) {
31416 .anyerror_type => break :ok,
31417 .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
31418 break :ok;
31419 },
31420 else => |i| if (ip.indexToKey(i).error_set_type.nameIndex(ip, expected_name) != null) {
31421 break :ok;
31422 },
31423 }
31424
31425 return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty);
31426 },
31427 else => unreachable,
31428 },
31429 }
31430 return Air.internedToRef((try pt.intern(.{ .error_union = .{
31431 .ty = dest_ty.toIntern(),31346 .ty = dest_ty.toIntern(),
31432 .val = .{ .err_name = expected_name },31347 .val = .{ .err_name = ip.indexToKey(error_val.toIntern()).err.name },
31433 } })));31348 } }));
31349 } else {
31350 return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
31434 }31351 }
31435
31436 try sema.requireRuntimeBlock(block, inst_src, null);
31437 const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
31438 return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
31439}31352}
3144031353
31441fn unionToTag(31354fn unionToTag(
...@@ -32969,18 +32882,6 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {...@@ -32969,18 +32882,6 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {
32969 };32882 };
32970}32883}
3297132884
32972pub fn resolveIes(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!void {
32973 const pt = sema.pt;
32974 const zcu = pt.zcu;
32975 const ip = &zcu.intern_pool;
32976
32977 if (sema.fn_ret_ty_ies) |ies| {
32978 try sema.resolveInferredErrorSetPtr(block, src, ies);
32979 assert(ies.resolved != .none);
32980 ip.funcIesResolved(sema.func_index).* = ies.resolved;
32981 }
32982}
32983
32984fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {32885fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
32985 const pt = sema.pt;32886 const pt = sema.pt;
32986 if (!ty.isIndexable(pt.zcu)) {32887 if (!ty.isIndexable(pt.zcu)) {
...@@ -33017,63 +32918,31 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void...@@ -33017,63 +32918,31 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
33017 return sema.failWithOwnedErrorMsg(block, msg);32918 return sema.failWithOwnedErrorMsg(block, msg);
33018}32919}
3301932920
33020/// Returns a normal error set corresponding to the fully populated inferred32921/// Resolves the inferred error set of the given function, so that the corresponding concrete error
33021/// error set.32922/// set is available by calling `InternPool.funcIesResolvedUnordered` on `func_index`.
33022fn resolveInferredErrorSet(32923///
32924/// Asserts that `func_index` is a function. Also asserts that it is not a coerced function, because
32925/// coerced functions do not own inferred error sets.
32926fn ensureFuncIesResolved(
33023 sema: *Sema,32927 sema: *Sema,
33024 block: *Block,32928 block: *Block,
33025 src: LazySrcLoc,32929 src: LazySrcLoc,
33026 ies_index: InternPool.Index,32930 func_index: InternPool.Index,
33027) CompileError!InternPool.Index {32931) CompileError!void {
33028 const pt = sema.pt;32932 const pt = sema.pt;
33029 const zcu = pt.zcu;32933 const zcu = pt.zcu;
33030 const ip = &zcu.intern_pool;32934 const ip = &zcu.intern_pool;
33031 const func_index = ip.iesFuncIndex(ies_index);
33032 const func = zcu.funcInfo(func_index);
3303332935
33034 try sema.declareDependency(.{ .func_ies = func_index });32936 assert(ip.unwrapCoercedFunc(func_index) == func_index);
3303532937
33036 // MLUGG TODO: this feels kinda bad now... instead check for outdated whenver we grab this?32938 try sema.declareDependency(.{ .func_ies = func_index });
33037 try zcu.maybeUnresolveIes(func_index);32939 try sema.addReferenceEntry(block, src, .wrap(.{ .func = func_index }));
33038 const resolved_ty = func.resolvedErrorSetUnordered(ip);
33039 if (resolved_ty != .none) return resolved_ty;
3304032940
33041 if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) {32941 if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) {
33042 return sema.fail(block, src, "unable to resolve inferred error set", .{});32942 return sema.fail(block, src, "unable to resolve inferred error set", .{});
33043 }32943 }
3304432944
33045 // In order to ensure that all dependencies are properly added to the set,32945 try pt.ensureFuncBodyUpToDate(func_index);
33046 // we need to ensure the function body is analyzed of the inferred error
33047 // set. However, in the case of comptime/inline function calls with
33048 // inferred error sets, each call gets an adhoc InferredErrorSet object, which
33049 // has no corresponding function body.
33050 const ies_func_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
33051 // if ies declared by a inline function with generic return type, the return_type should be generic_poison,
33052 // because inline function does not create a new declaration, and the ies has been filled with analyzeCall,
33053 // so here we can simply skip this case.
33054 if (ies_func_info.return_type == .generic_poison_type) {
33055 assert(ies_func_info.cc == .@"inline");
33056 } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) {
33057 if (!Type.fromInterned(func.ty).fnHasRuntimeBits(zcu)) {
33058 return sema.failWithOwnedErrorMsg(block, msg: {
33059 const msg = try sema.errMsg(src, "unable to resolve inferred error set of generic function", .{});
33060 errdefer msg.destroy(sema.gpa);
33061 try sema.errNote(zcu.navSrcLoc(func.owner_nav), msg, "generic function declared here", .{});
33062 break :msg msg;
33063 });
33064 }
33065 // In this case we are dealing with the actual InferredErrorSet object that
33066 // corresponds to the function, not one created to track an inline/comptime call.
33067 const orig_func_index = ip.unwrapCoercedFunc(func_index);
33068 try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_func_index }));
33069 try pt.ensureFuncBodyUpToDate(orig_func_index);
33070 }
33071
33072 // This will now have been resolved by the logic at the end of `Zcu.analyzeFnBody`
33073 // which calls `resolveInferredErrorSetPtr`.
33074 const final_resolved_ty = func.resolvedErrorSetUnordered(ip);
33075 assert(final_resolved_ty != .none);
33076 return final_resolved_ty;
33077}32946}
3307832947
33079pub fn resolveInferredErrorSetPtr(32948pub fn resolveInferredErrorSetPtr(
...@@ -33091,7 +32960,9 @@ pub fn resolveInferredErrorSetPtr(...@@ -33091,7 +32960,9 @@ pub fn resolveInferredErrorSetPtr(
3309132960
33092 for (ies.inferred_error_sets.keys()) |other_ies_index| {32961 for (ies.inferred_error_sets.keys()) |other_ies_index| {
33093 if (ies_index == other_ies_index) continue;32962 if (ies_index == other_ies_index) continue;
33094 switch (try sema.resolveInferredErrorSet(block, src, other_ies_index)) {32963 const other_func_index = ip.iesFuncIndex(other_ies_index);
32964 try sema.ensureFuncIesResolved(block, src, other_func_index);
32965 switch (ip.funcIesResolvedUnordered(other_func_index)) {
33095 .anyerror_type => {32966 .anyerror_type => {
33096 ies.resolved = .anyerror_type;32967 ies.resolved = .anyerror_type;
33097 return;32968 return;
...@@ -33164,7 +33035,10 @@ fn resolveInferredErrorSetTy(...@@ -33164,7 +33035,10 @@ fn resolveInferredErrorSetTy(
33164 if (ty == .anyerror_type) return ty;33035 if (ty == .anyerror_type) return ty;
33165 switch (ip.indexToKey(ty)) {33036 switch (ip.indexToKey(ty)) {
33166 .error_set_type => return ty,33037 .error_set_type => return ty,
33167 .inferred_error_set_type => return sema.resolveInferredErrorSet(block, src, ty),33038 .inferred_error_set_type => |func_index| {
33039 try sema.ensureFuncIesResolved(block, src, func_index);
33040 return ip.funcIesResolvedUnordered(func_index);
33041 },
33168 else => unreachable,33042 else => unreachable,
33169 }33043 }
33170}33044}
src/Sema/type_resolution.zig+6-4
...@@ -132,7 +132,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -132,7 +132,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
132 .src_base_inst = struct_obj.zir_index,132 .src_base_inst = struct_obj.zir_index,
133 .type_name_ctx = struct_obj.name,133 .type_name_ctx = struct_obj.name,
134 };134 };
135 defer assert(block.instructions.items.len == 0);135 defer block.instructions.deinit(gpa);
136136
137 // There may be old field names in here from a previous update.137 // There may be old field names in here from a previous update.
138 struct_obj.field_name_map.get(ip).clearRetainingCapacity();138 struct_obj.field_name_map.get(ip).clearRetainingCapacity();
...@@ -452,6 +452,8 @@ fn resolvePackedStructLayout(...@@ -452,6 +452,8 @@ fn resolvePackedStructLayout(
452pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {452pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
453 const pt = sema.pt;453 const pt = sema.pt;
454 const zcu = pt.zcu;454 const zcu = pt.zcu;
455 const comp = zcu.comp;
456 const gpa = comp.gpa;
455 const ip = &zcu.intern_pool;457 const ip = &zcu.intern_pool;
456458
457 assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern());459 assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern());
...@@ -490,7 +492,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -490,7 +492,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
490 .src_base_inst = struct_obj.zir_index,492 .src_base_inst = struct_obj.zir_index,
491 .type_name_ctx = struct_obj.name,493 .type_name_ctx = struct_obj.name,
492 };494 };
493 defer assert(block.instructions.items.len == 0);495 defer block.instructions.deinit(gpa);
494496
495 return resolveStructDefaultsInner(sema, &block, &struct_obj);497 return resolveStructDefaultsInner(sema, &block, &struct_obj);
496}498}
...@@ -565,7 +567,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -565,7 +567,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
565 .src_base_inst = union_obj.zir_index,567 .src_base_inst = union_obj.zir_index,
566 .type_name_ctx = union_obj.name,568 .type_name_ctx = union_obj.name,
567 };569 };
568 defer assert(block.instructions.items.len == 0);570 defer block.instructions.deinit(gpa);
569571
570 // MLUGG TODO: this is fucking ugly bro572 // MLUGG TODO: this is fucking ugly bro
571 const explicit_enum_tag_ty: ?Type = if (union_obj.is_reified) ty: {573 const explicit_enum_tag_ty: ?Type = if (union_obj.is_reified) ty: {
...@@ -1011,7 +1013,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {...@@ -1011,7 +1013,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
1011 .src_base_inst = tracked_inst,1013 .src_base_inst = tracked_inst,
1012 .type_name_ctx = enum_obj.name,1014 .type_name_ctx = enum_obj.name,
1013 };1015 };
1014 defer assert(block.instructions.items.len == 0);1016 defer block.instructions.deinit(gpa);
10151017
1016 // There may be old field names in the map from a previous update.1018 // There may be old field names in the map from a previous update.
1017 enum_obj.field_name_map.get(ip).clearRetainingCapacity();1019 enum_obj.field_name_map.get(ip).clearRetainingCapacity();
src/Type.zig+6-5
...@@ -1472,14 +1472,15 @@ pub fn isError(ty: Type, zcu: *const Zcu) bool {...@@ -1472,14 +1472,15 @@ pub fn isError(ty: Type, zcu: *const Zcu) bool {
1472/// Returns whether ty, which must be an error set, includes an error `name`.1472/// Returns whether ty, which must be an error set, includes an error `name`.
1473/// Might return a false negative if `ty` is an inferred error set and not fully1473/// Might return a false negative if `ty` is an inferred error set and not fully
1474/// resolved yet.1474/// resolved yet.
1475pub fn errorSetHasFieldIp(1475pub fn errorSetHasField(
1476 ip: *const InternPool,1476 ty: Type,
1477 ty: InternPool.Index,
1478 name: InternPool.NullTerminatedString,1477 name: InternPool.NullTerminatedString,
1478 zcu: *const Zcu,
1479) bool {1479) bool {
1480 return switch (ty) {1480 const ip = &zcu.intern_pool;
1481 return switch (ty.toIntern()) {
1481 .anyerror_type => true,1482 .anyerror_type => true,
1482 else => switch (ip.indexToKey(ty)) {1483 else => switch (ip.indexToKey(ty.toIntern())) {
1483 .error_set_type => |error_set_type| error_set_type.nameIndex(ip, name) != null,1484 .error_set_type => |error_set_type| error_set_type.nameIndex(ip, name) != null,
1484 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) {1485 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) {
1485 .anyerror_type => true,1486 .anyerror_type => true,
src/Value.zig+2-2
...@@ -641,9 +641,9 @@ pub fn readFromPackedMemory(...@@ -641,9 +641,9 @@ pub fn readFromPackedMemory(
641 .optional => {641 .optional => {
642 assert(ty.isPtrLikeOptional(zcu));642 assert(ty.isPtrLikeOptional(zcu));
643 const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu);643 const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu);
644 return Value.fromInterned(try pt.intern(.{ .opt = .{644 return .fromInterned(try pt.intern(.{ .opt = .{
645 .ty = ty.toIntern(),645 .ty = ty.toIntern(),
646 .val = (try pt.ptrIntValue(ty.childType(zcu), addr)).toIntern(),646 .val = if (addr == 0) .none else (try pt.ptrIntValue(ty.childType(zcu), addr)).toIntern(),
647 } }));647 } }));
648 },648 },
649 else => @panic("TODO implement readFromPackedMemory for more types"),649 else => @panic("TODO implement readFromPackedMemory for more types"),
src/Zcu.zig+1-26
...@@ -4059,6 +4059,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4059,6 +4059,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4059 implicit_tag: {4059 implicit_tag: {
4060 const loaded_union = zcu.typeToUnion(.fromInterned(ty)) orelse break :implicit_tag;4060 const loaded_union = zcu.typeToUnion(.fromInterned(ty)) orelse break :implicit_tag;
4061 const tag_ty = loaded_union.enum_tag_type;4061 const tag_ty = loaded_union.enum_tag_type;
4062 if (tag_ty == .none) break :implicit_tag;
4062 if (ip.indexToKey(tag_ty).enum_type != .generated_union_tag) break :implicit_tag;4063 if (ip.indexToKey(tag_ty).enum_type != .generated_union_tag) break :implicit_tag;
4063 const gop = try types.getOrPut(gpa, tag_ty);4064 const gop = try types.getOrPut(gpa, tag_ty);
4064 if (gop.found_existing) break :implicit_tag;4065 if (gop.found_existing) break :implicit_tag;
...@@ -4383,32 +4384,6 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void...@@ -4383,32 +4384,6 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void
4383 }4384 }
4384}4385}
43854386
4386/// Given the `InternPool.Index` of a function, set its resolved IES to `.none` if it
4387/// may be outdated. `Sema` should do this before ever loading a resolved IES.
4388pub fn maybeUnresolveIes(zcu: *Zcu, func_index: InternPool.Index) !void {
4389 const unit = AnalUnit.wrap(.{ .func = func_index });
4390 if (zcu.outdated.contains(unit) or zcu.potentially_outdated.contains(unit)) {
4391 // We're consulting the resolved IES now, but the function is outdated, so its
4392 // IES may have changed. We have to assume the IES is outdated and set the resolved
4393 // set back to `.none`.
4394 //
4395 // This will cause `PerThread.analyzeFnBody` to mark the IES as outdated when it's
4396 // eventually hit.
4397 //
4398 // Since the IES needs to be resolved, the function body will now definitely need
4399 // re-analysis (even if the IES turns out to be the same!), so mark it as
4400 // definitely-outdated if it's only PO.
4401 if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| {
4402 const gpa = zcu.gpa;
4403 try zcu.outdated.putNoClobber(gpa, unit, kv.value);
4404 if (kv.value == 0) {
4405 try zcu.outdated_ready.put(gpa, unit, {});
4406 }
4407 }
4408 zcu.intern_pool.funcSetIesResolved(zcu.comp.io, func_index, .none);
4409 }
4410}
4411
4412pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enum) {4387pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enum) {
4413 ok,4388 ok,
4414 bad_arch: []const std.Target.Cpu.Arch, // value is allowed archs for cc4389 bad_arch: []const std.Target.Cpu.Arch, // value is allowed archs for cc