| ... | ... | @@ -7870,21 +7870,21 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 7870 | 7870 | return .anyerror_type; |
| 7871 | 7871 | } |
| 7872 | 7872 | |
| 7873 | | if (ip.isInferredErrorSetType(lhs_ty.toIntern())) { |
| 7874 | | switch (try sema.resolveInferredErrorSet(block, src, lhs_ty.toIntern())) { |
| 7875 | | // isAnyError might have changed from a false negative to a true |
| 7876 | | // positive after resolution. |
| 7877 | | .anyerror_type => return .anyerror_type, |
| 7878 | | else => {}, |
| 7879 | | } |
| 7873 | switch (ip.indexToKey(lhs_ty.toIntern())) { |
| 7874 | .inferred_error_set_type => |func_index| { |
| 7875 | try sema.ensureFuncIesResolved(block, src, func_index); |
| 7876 | if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type; |
| 7877 | }, |
| 7878 | .error_set_type => {}, |
| 7879 | else => unreachable, |
| 7880 | 7880 | } |
| 7881 | | if (ip.isInferredErrorSetType(rhs_ty.toIntern())) { |
| 7882 | | switch (try sema.resolveInferredErrorSet(block, src, rhs_ty.toIntern())) { |
| 7883 | | // isAnyError might have changed from a false negative to a true |
| 7884 | | // positive after resolution. |
| 7885 | | .anyerror_type => return .anyerror_type, |
| 7886 | | else => {}, |
| 7887 | | } |
| 7881 | switch (ip.indexToKey(rhs_ty.toIntern())) { |
| 7882 | .inferred_error_set_type => |func_index| { |
| 7883 | try sema.ensureFuncIesResolved(block, src, func_index); |
| 7884 | if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type; |
| 7885 | }, |
| 7886 | .error_set_type => {}, |
| 7887 | else => unreachable, |
| 7888 | 7888 | } |
| 7889 | 7889 | |
| 7890 | 7890 | const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty); |
| ... | ... | @@ -12000,7 +12000,7 @@ fn wantSwitchProngBodyAnalysis( |
| 12000 | 12000 | if (err_set and prong_is_comptime_unreach) { |
| 12001 | 12001 | const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable; |
| 12002 | 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 | 12005 | return true; |
| 12006 | 12006 | } |
| ... | ... | @@ -21023,34 +21023,61 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 21023 | 21023 | else => unreachable, |
| 21024 | 21024 | }; |
| 21025 | 21025 | |
| 21026 | | const disjoint = disjoint: { |
| 21027 | | // Try avoiding resolving inferred error sets if we can |
| 21028 | | if (!dest_err_ty.isAnyError(zcu) and dest_err_ty.errorSetIsEmpty(zcu)) break :disjoint true; |
| 21029 | | if (!operand_err_ty.isAnyError(zcu) and operand_err_ty.errorSetIsEmpty(zcu)) break :disjoint true; |
| 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 | | } |
| 21026 | switch (ip.indexToKey(operand_err_ty.toIntern())) { |
| 21027 | .inferred_error_set_type => |func| try sema.ensureFuncIesResolved(block, src, func), |
| 21028 | else => {}, |
| 21029 | } |
| 21050 | 21030 | |
| 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 | 21081 | return sema.fail(block, src, "error sets '{f}' and '{f}' have no common errors", .{ |
| 21055 | 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 | 21085 | |
| 21059 | 21086 | // operand must be defined since it can be an invalid error value |
| 21060 | 21087 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { |
| 21061 | | const err_name: InternPool.NullTerminatedString = switch (operand_tag) { |
| 21062 | | .error_set => ip.indexToKey(operand_val.toIntern()).err.name, |
| 21063 | | .error_union => switch (ip.indexToKey(operand_val.toIntern()).error_union.val) { |
| 21088 | const err_name: InternPool.NullTerminatedString = switch (ip.indexToKey(operand_val.toIntern())) { |
| 21089 | .err => |err| err.name, |
| 21090 | .error_union => |eu| switch (eu.val) { |
| 21064 | 21091 | .err_name => |name| name, |
| 21065 | 21092 | .payload => |payload_val| { |
| 21066 | 21093 | 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 | 21102 | else => unreachable, |
| 21071 | 21103 | }; |
| 21072 | 21104 | |
| 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 | 21106 | return sema.fail(block, src, "'error.{f}' not a member of error set '{f}'", .{ |
| 21075 | 21107 | err_name.fmt(ip), dest_err_ty.fmt(pt), |
| 21076 | 21108 | }); |
| 21077 | 21109 | } |
| 21078 | 21110 | |
| 21079 | | return Air.internedToRef(try pt.intern(switch (dest_tag) { |
| 21111 | return .fromIntern(try pt.intern(switch (dest_tag) { |
| 21080 | 21112 | .error_set => .{ .err = .{ |
| 21081 | 21113 | .ty = dest_ty.toIntern(), |
| 21082 | 21114 | .name = err_name, |
| ... | ... | @@ -21090,21 +21122,17 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 21090 | 21122 | } |
| 21091 | 21123 | |
| 21092 | 21124 | const err_int_ty = try pt.errorIntType(); |
| 21093 | | if (block.wantSafety() and !dest_err_ty.isAnyError(zcu) and |
| 21094 | | dest_err_ty.toIntern() != .adhoc_inferred_error_set_type and |
| 21095 | | zcu.backendSupportsFeature(.error_set_has_value)) |
| 21096 | | { |
| 21125 | if (block.wantSafety() and result != .superset and zcu.backendSupportsFeature(.error_set_has_value)) { |
| 21097 | 21126 | const err_code_inst = switch (operand_tag) { |
| 21098 | 21127 | .error_set => operand, |
| 21099 | 21128 | .error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand), |
| 21100 | 21129 | else => unreachable, |
| 21101 | 21130 | }; |
| 21102 | 21131 | const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst); |
| 21103 | | |
| 21104 | 21132 | if (dest_tag == .error_union) { |
| 21105 | 21133 | const zero_err = try pt.intRef(err_int_ty, 0); |
| 21106 | 21134 | const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err); |
| 21107 | | if (disjoint) { |
| 21135 | if (result == .disjoint) { |
| 21108 | 21136 | // Error must be zero. |
| 21109 | 21137 | try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code); |
| 21110 | 21138 | } else { |
| ... | ... | @@ -25599,31 +25627,28 @@ fn fieldVal( |
| 25599 | 25627 | |
| 25600 | 25628 | switch (child_type.zigTypeTag(zcu)) { |
| 25601 | 25629 | .error_set => { |
| 25602 | | switch (ip.indexToKey(child_type.toIntern())) { |
| 25603 | | .error_set_type => |error_set_type| blk: { |
| 25604 | | if (error_set_type.nameIndex(ip, field_name) != null) break :blk; |
| 25630 | const err_set_ty: Type = err_set: switch (ip.indexToKey(child_type.toIntern())) { |
| 25631 | .inferred_error_set_type => |func_index| { |
| 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 | 25637 | return sema.fail(block, src, "no error named '{f}' in '{f}'", .{ |
| 25606 | 25638 | field_name.fmt(ip), child_type.fmt(pt), |
| 25607 | 25639 | }); |
| 25608 | | }, |
| 25609 | | .inferred_error_set_type => { |
| 25610 | | return sema.fail(block, src, "TODO handle inferred error sets here", .{}); |
| 25611 | | }, |
| 25640 | } else child_type, |
| 25612 | 25641 | .simple_type => |t| { |
| 25613 | 25642 | assert(t == .anyerror); |
| 25614 | 25643 | _ = try pt.getErrorValue(field_name); |
| 25644 | break :err_set try pt.singleErrorSetType(field_name); |
| 25615 | 25645 | }, |
| 25616 | 25646 | else => unreachable, |
| 25617 | | } |
| 25618 | | |
| 25619 | | const error_set_type = if (!child_type.isAnyError(zcu)) |
| 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(), |
| 25647 | }; |
| 25648 | return .fromIntern(try pt.intern(.{ .err = .{ |
| 25649 | .ty = err_set_ty.toIntern(), |
| 25625 | 25650 | .name = field_name, |
| 25626 | | } }))); |
| 25651 | } })); |
| 25627 | 25652 | }, |
| 25628 | 25653 | .@"union" => { |
| 25629 | 25654 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| ... | ... | @@ -25832,31 +25857,26 @@ fn fieldPtr( |
| 25832 | 25857 | |
| 25833 | 25858 | switch (child_type.zigTypeTag(zcu)) { |
| 25834 | 25859 | .error_set => { |
| 25835 | | switch (ip.indexToKey(child_type.toIntern())) { |
| 25836 | | .error_set_type => |error_set_type| blk: { |
| 25837 | | if (error_set_type.nameIndex(ip, field_name) != null) { |
| 25838 | | break :blk; |
| 25839 | | } |
| 25860 | const err_set_ty: Type = err_set: switch (ip.indexToKey(child_type.toIntern())) { |
| 25861 | .inferred_error_set_type => |func_index| { |
| 25862 | try sema.ensureFuncIesResolved(block, src, func_index); |
| 25863 | const resolved_ies = ip.funcIesResolvedUnordered(func_index); |
| 25864 | continue :err_set ip.indexToKey(resolved_ies); |
| 25865 | }, |
| 25866 | .error_set_type => |err_set| if (err_set.nameIndex(ip, field_name) == null) { |
| 25840 | 25867 | return sema.fail(block, src, "no error named '{f}' in '{f}'", .{ |
| 25841 | 25868 | field_name.fmt(ip), child_type.fmt(pt), |
| 25842 | 25869 | }); |
| 25843 | | }, |
| 25844 | | .inferred_error_set_type => { |
| 25845 | | return sema.fail(block, src, "TODO handle inferred error sets here", .{}); |
| 25846 | | }, |
| 25870 | } else child_type, |
| 25847 | 25871 | .simple_type => |t| { |
| 25848 | 25872 | assert(t == .anyerror); |
| 25849 | 25873 | _ = try pt.getErrorValue(field_name); |
| 25874 | break :err_set try pt.singleErrorSetType(field_name); |
| 25850 | 25875 | }, |
| 25851 | 25876 | else => unreachable, |
| 25852 | | } |
| 25853 | | |
| 25854 | | const error_set_type = if (!child_type.isAnyError(zcu)) |
| 25855 | | child_type |
| 25856 | | else |
| 25857 | | try pt.singleErrorSetType(field_name); |
| 25877 | }; |
| 25858 | 25878 | return uavRef(sema, try pt.intern(.{ .err = .{ |
| 25859 | | .ty = error_set_type.toIntern(), |
| 25879 | .ty = err_set_ty.toIntern(), |
| 25860 | 25880 | .name = field_name, |
| 25861 | 25881 | } })); |
| 25862 | 25882 | }, |
| ... | ... | @@ -27760,23 +27780,27 @@ fn coerceExtra( |
| 27760 | 27780 | else => {}, |
| 27761 | 27781 | }, |
| 27762 | 27782 | .error_union => switch (inst_ty.zigTypeTag(zcu)) { |
| 27763 | | .error_set => { |
| 27764 | | // E to E!T |
| 27765 | | return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src); |
| 27783 | // E to E!T |
| 27784 | .error_set => if (sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src)) |res| { |
| 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: { |
| 27768 | | // T to E!T |
| 27769 | | return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) { |
| 27770 | | error.NotCoercible => { |
| 27771 | | if (in_memory_result == .no_match) { |
| 27772 | | const payload_type = dest_ty.errorUnionPayload(zcu); |
| 27773 | | // Try to give more useful notes |
| 27774 | | in_memory_result = try sema.coerceInMemoryAllowed(block, payload_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val); |
| 27775 | | } |
| 27776 | | break :eu; |
| 27777 | | }, |
| 27778 | | else => |e| return e, |
| 27779 | | }; |
| 27794 | // T to E!T |
| 27795 | else => if (sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src)) |res| { |
| 27796 | return res; |
| 27797 | } else |err| switch (err) { |
| 27798 | error.NotCoercible => if (in_memory_result == .no_match) { |
| 27799 | // Try to give more useful notes |
| 27800 | const payload_type = dest_ty.errorUnionPayload(zcu); |
| 27801 | in_memory_result = try sema.coerceInMemoryAllowed(block, payload_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val); |
| 27802 | }, |
| 27803 | else => |e| return e, |
| 27780 | 27804 | }, |
| 27781 | 27805 | }, |
| 27782 | 27806 | .@"union" => switch (inst_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -28542,89 +28566,62 @@ fn coerceInMemoryAllowedErrorSets( |
| 28542 | 28566 | const gpa = sema.gpa; |
| 28543 | 28567 | const ip = &zcu.intern_pool; |
| 28544 | 28568 | |
| 28545 | | // Coercion to `anyerror`. Note that this check can return false negatives |
| 28546 | | // in case the error sets did not get resolved. |
| 28547 | | if (dest_ty.isAnyError(zcu)) { |
| 28548 | | return .ok; |
| 28549 | | } |
| 28550 | | |
| 28551 | | if (dest_ty.toIntern() == .adhoc_inferred_error_set_type) { |
| 28552 | | // We are trying to coerce an error set to the current function's |
| 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, |
| 28569 | const dest_set: InternPool.Key.ErrorSetType = err_set: switch (dest_ty.toIntern()) { |
| 28570 | .anyerror_type => return .ok, |
| 28571 | .adhoc_inferred_error_set_type => { |
| 28572 | // We are trying to coerce an error set to the current function's |
| 28573 | // inferred error set. |
| 28574 | const dst_ies = sema.fn_ret_ty_ies.?; |
| 28575 | try dst_ies.addErrorSet(src_ty, ip, sema.arena); |
| 28576 | return .ok; |
| 28585 | 28577 | }, |
| 28586 | | |
| 28587 | | else => switch (ip.indexToKey(src_ty.toIntern())) { |
| 28588 | | .inferred_error_set_type => { |
| 28589 | | const resolved_src_ty = try sema.resolveInferredErrorSet(block, src_src, src_ty.toIntern()); |
| 28590 | | // src anyerror status might have changed after the resolution. |
| 28591 | | if (resolved_src_ty == .anyerror_type) { |
| 28592 | | // dest_ty.isAnyError(zcu) == true is already checked for at this point. |
| 28593 | | return .from_anyerror; |
| 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); |
| 28578 | else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) { |
| 28579 | .inferred_error_set_type => |func_index| { |
| 28580 | if (sema.fn_ret_ty_ies) |dst_ies| { |
| 28581 | if (dst_ies.func == func_index) { |
| 28582 | // We are trying to coerce an error set to the current function's |
| 28583 | // inferred error set. |
| 28584 | try dst_ies.addErrorSet(src_ty, ip, sema.arena); |
| 28585 | return .ok; |
| 28599 | 28586 | } |
| 28600 | 28587 | } |
| 28601 | | |
| 28602 | | if (missing_error_buf.items.len != 0) { |
| 28603 | | return InMemoryCoercionResult{ |
| 28604 | | .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), |
| 28605 | | }; |
| 28606 | | } |
| 28607 | | |
| 28608 | | return .ok; |
| 28588 | try sema.ensureFuncIesResolved(block, dest_src, func_index); |
| 28589 | continue :err_set ip.funcIesResolvedUnordered(func_index); |
| 28609 | 28590 | }, |
| 28610 | | .error_set_type => |error_set_type| { |
| 28611 | | for (error_set_type.names.get(ip)) |name| { |
| 28612 | | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) { |
| 28613 | | try missing_error_buf.append(name); |
| 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 | | } |
| 28591 | .error_set_type => |err_set| err_set, |
| 28592 | else => unreachable, |
| 28593 | }, |
| 28594 | }; |
| 28622 | 28595 | |
| 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 | 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 | } |
| 28629 | 28626 | |
| 28630 | 28627 | fn coerceInMemoryAllowedFns( |
| ... | ... | @@ -30357,76 +30354,34 @@ fn resolveIsNonErrFromType( |
| 30357 | 30354 | |
| 30358 | 30355 | // exception if the error union error set is known to be empty, |
| 30359 | 30356 | // we allow the comparison but always make it comptime-known. |
| 30360 | | const set_ty = ip.errorUnionSet(operand_ty.toIntern()); |
| 30361 | | switch (set_ty) { |
| 30362 | | .anyerror_type => {}, |
| 30363 | | .adhoc_inferred_error_set_type => if (sema.fn_ret_ty_ies) |ies| blk: { |
| 30364 | | // If the error set is empty, we must return a comptime true or false. |
| 30365 | | // However we want to avoid unnecessarily resolving an inferred error set |
| 30366 | | // in case it is already non-empty. |
| 30367 | | switch (ies.resolved) { |
| 30368 | | .anyerror_type => break :blk, |
| 30369 | | .none => {}, |
| 30370 | | else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk, |
| 30371 | | } |
| 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; |
| 30357 | return err_set: switch (ip.errorUnionSet(operand_ty.toIntern())) { |
| 30358 | .anyerror_type => null, |
| 30359 | .adhoc_inferred_error_set_type => { |
| 30360 | // This is *our* error set; that is, we're currently analyzing the function |
| 30361 | // which owns it. Trying to resolve it now would cause a dependency loop. |
| 30362 | // Instead, accept that we don't know. |
| 30363 | if (true) return null; |
| 30364 | }, |
| 30365 | else => |set_ty| switch (ip.indexToKey(set_ty)) { |
| 30366 | .error_set_type => |error_set_type| switch (error_set_type.names.len) { |
| 30367 | 0 => .true, |
| 30368 | else => null, |
| 30390 | 30369 | }, |
| 30391 | | .inferred_error_set_type => |func_index| blk: { |
| 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 | | } |
| 30370 | .inferred_error_set_type => |func_index| { |
| 30401 | 30371 | if (sema.fn_ret_ty_ies) |ies| { |
| 30402 | 30372 | if (ies.func == func_index) { |
| 30403 | | // Try to avoid resolving inferred error set if possible. |
| 30404 | | if (ies.errors.count() != 0) return null; |
| 30405 | | switch (ies.resolved) { |
| 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. |
| 30373 | // This is *our* error set; that is, we're currently analyzing the function |
| 30374 | // which owns it. Trying to resolve it now would cause a dependency loop. |
| 30375 | // Instead, accept that we don't know. |
| 30416 | 30376 | return null; |
| 30417 | 30377 | } |
| 30418 | 30378 | } |
| 30419 | | const resolved_ty = try sema.resolveInferredErrorSet(block, src, set_ty); |
| 30420 | | if (resolved_ty == .anyerror_type) |
| 30421 | | break :blk; |
| 30422 | | if (ip.indexToKey(resolved_ty).error_set_type.names.len == 0) |
| 30423 | | return .true; |
| 30379 | try sema.ensureFuncIesResolved(block, src, func_index); |
| 30380 | continue :err_set ip.funcIesResolvedUnordered(func_index); |
| 30424 | 30381 | }, |
| 30425 | 30382 | else => unreachable, |
| 30426 | 30383 | }, |
| 30427 | | } |
| 30428 | | |
| 30429 | | return null; |
| 30384 | }; |
| 30430 | 30385 | } |
| 30431 | 30386 | |
| 30432 | 30387 | fn analyzeIsNonErr( |
| ... | ... | @@ -31384,58 +31339,16 @@ fn wrapErrorUnionSet( |
| 31384 | 31339 | const pt = sema.pt; |
| 31385 | 31340 | const zcu = pt.zcu; |
| 31386 | 31341 | const ip = &zcu.intern_pool; |
| 31387 | | const inst_ty = sema.typeOf(inst); |
| 31388 | 31342 | const dest_err_set_ty = dest_ty.errorUnionSet(zcu); |
| 31389 | | if (sema.resolveValue(inst)) |val| { |
| 31390 | | const expected_name = zcu.intern_pool.indexToKey(val.toIntern()).err.name; |
| 31391 | | switch (dest_err_set_ty.toIntern()) { |
| 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 = .{ |
| 31343 | const coerced = try sema.coerceExtra(block, dest_err_set_ty, inst, inst_src, .{ .report_err = false }); |
| 31344 | if (try sema.resolveDefinedValue(block, inst_src, coerced)) |error_val| { |
| 31345 | return .fromIntern(try pt.intern(.{ .error_union = .{ |
| 31431 | 31346 | .ty = dest_ty.toIntern(), |
| 31432 | | .val = .{ .err_name = expected_name }, |
| 31433 | | } }))); |
| 31347 | .val = .{ .err_name = ip.indexToKey(error_val.toIntern()).err.name }, |
| 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 | } |
| 31440 | 31353 | |
| 31441 | 31354 | fn unionToTag( |
| ... | ... | @@ -32969,18 +32882,6 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike { |
| 32969 | 32882 | }; |
| 32970 | 32883 | } |
| 32971 | 32884 | |
| 32972 | | pub 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 | | |
| 32984 | 32885 | fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 32985 | 32886 | const pt = sema.pt; |
| 32986 | 32887 | if (!ty.isIndexable(pt.zcu)) { |
| ... | ... | @@ -33017,63 +32918,31 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void |
| 33017 | 32918 | return sema.failWithOwnedErrorMsg(block, msg); |
| 33018 | 32919 | } |
| 33019 | 32920 | |
| 33020 | | /// Returns a normal error set corresponding to the fully populated inferred |
| 33021 | | /// error set. |
| 33022 | | fn resolveInferredErrorSet( |
| 32921 | /// Resolves the inferred error set of the given function, so that the corresponding concrete error |
| 32922 | /// set is available by calling `InternPool.funcIesResolvedUnordered` on `func_index`. |
| 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. |
| 32926 | fn ensureFuncIesResolved( |
| 33023 | 32927 | sema: *Sema, |
| 33024 | 32928 | block: *Block, |
| 33025 | 32929 | src: LazySrcLoc, |
| 33026 | | ies_index: InternPool.Index, |
| 33027 | | ) CompileError!InternPool.Index { |
| 32930 | func_index: InternPool.Index, |
| 32931 | ) CompileError!void { |
| 33028 | 32932 | const pt = sema.pt; |
| 33029 | 32933 | const zcu = pt.zcu; |
| 33030 | 32934 | const ip = &zcu.intern_pool; |
| 33031 | | const func_index = ip.iesFuncIndex(ies_index); |
| 33032 | | const func = zcu.funcInfo(func_index); |
| 33033 | 32935 | |
| 33034 | | try sema.declareDependency(.{ .func_ies = func_index }); |
| 32936 | assert(ip.unwrapCoercedFunc(func_index) == func_index); |
| 33035 | 32937 | |
| 33036 | | // MLUGG TODO: this feels kinda bad now... instead check for outdated whenver we grab this? |
| 33037 | | try zcu.maybeUnresolveIes(func_index); |
| 33038 | | const resolved_ty = func.resolvedErrorSetUnordered(ip); |
| 33039 | | if (resolved_ty != .none) return resolved_ty; |
| 32938 | try sema.declareDependency(.{ .func_ies = func_index }); |
| 32939 | try sema.addReferenceEntry(block, src, .wrap(.{ .func = func_index })); |
| 33040 | 32940 | |
| 33041 | 32941 | if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) { |
| 33042 | 32942 | return sema.fail(block, src, "unable to resolve inferred error set", .{}); |
| 33043 | 32943 | } |
| 33044 | 32944 | |
| 33045 | | // In order to ensure that all dependencies are properly added to the set, |
| 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; |
| 32945 | try pt.ensureFuncBodyUpToDate(func_index); |
| 33077 | 32946 | } |
| 33078 | 32947 | |
| 33079 | 32948 | pub fn resolveInferredErrorSetPtr( |
| ... | ... | @@ -33091,7 +32960,9 @@ pub fn resolveInferredErrorSetPtr( |
| 33091 | 32960 | |
| 33092 | 32961 | for (ies.inferred_error_sets.keys()) |other_ies_index| { |
| 33093 | 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 | 32966 | .anyerror_type => { |
| 33096 | 32967 | ies.resolved = .anyerror_type; |
| 33097 | 32968 | return; |
| ... | ... | @@ -33164,7 +33035,10 @@ fn resolveInferredErrorSetTy( |
| 33164 | 33035 | if (ty == .anyerror_type) return ty; |
| 33165 | 33036 | switch (ip.indexToKey(ty)) { |
| 33166 | 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 | 33042 | else => unreachable, |
| 33169 | 33043 | } |
| 33170 | 33044 | } |