| ... | ... | @@ -17610,6 +17610,21 @@ fn resolvePeerTypes( |
| 17610 | 17610 | const target = sema.mod.getTarget(); |
| 17611 | 17611 | |
| 17612 | 17612 | var chosen = instructions[0]; |
| 17613 | var err_set_ty: ?Type = blk: { |
| 17614 | const chosen_ty = sema.typeOf(chosen); |
| 17615 | |
| 17616 | // TODO: is this the right handling of generic poison? |
| 17617 | if (chosen_ty.tag() == .generic_poison or chosen_ty.zigTypeTag() != .ErrorSet) |
| 17618 | break :blk null; |
| 17619 | |
| 17620 | // If our chosen type is inferred, we have to resolve it now. |
| 17621 | if (chosen_ty.castTag(.error_set_inferred)) |inferred| { |
| 17622 | try sema.resolveInferredErrorSet(inferred.data); |
| 17623 | } |
| 17624 | |
| 17625 | break :blk chosen_ty; |
| 17626 | }; |
| 17627 | |
| 17613 | 17628 | var any_are_null = false; |
| 17614 | 17629 | var make_the_slice_const = false; |
| 17615 | 17630 | var convert_to_slice = false; |
| ... | ... | @@ -17711,7 +17726,175 @@ fn resolvePeerTypes( |
| 17711 | 17726 | }, |
| 17712 | 17727 | else => {}, |
| 17713 | 17728 | }, |
| 17729 | .ErrorSet => { |
| 17730 | if (chosen_ty_tag == .ErrorSet) { |
| 17731 | assert(err_set_ty != null); |
| 17732 | |
| 17733 | // If chosen type is anyerror, then we can use the prev type |
| 17734 | if (err_set_ty.?.isAnyError()) continue; |
| 17735 | |
| 17736 | // At this point, we must resolve any inferred error sets |
| 17737 | if (candidate_ty.castTag(.error_set_inferred)) |inferred| { |
| 17738 | try sema.resolveInferredErrorSet(inferred.data); |
| 17739 | } |
| 17740 | |
| 17741 | // If candidate is anyerror then we use it because it |
| 17742 | // is trivially a supserset of previous error set |
| 17743 | if (candidate_ty.isAnyError()) { |
| 17744 | err_set_ty = candidate_ty; |
| 17745 | chosen = candidate; |
| 17746 | chosen_i = candidate_i + 1; |
| 17747 | continue; |
| 17748 | } |
| 17749 | |
| 17750 | // If chosen is superset of candidate, keep it. |
| 17751 | // If candidate is superset of chosen, switch it. |
| 17752 | // If neither is a superset, merge errors. |
| 17753 | var prev_is_superset = true; |
| 17754 | for (candidate_ty.errorSetNames()) |name| { |
| 17755 | if (!err_set_ty.?.errorSetHasField(name)) { |
| 17756 | prev_is_superset = false; |
| 17757 | break; |
| 17758 | } |
| 17759 | } |
| 17760 | if (prev_is_superset) continue; // use previous |
| 17761 | |
| 17762 | var cand_is_superset = true; |
| 17763 | for (err_set_ty.?.errorSetNames()) |name| { |
| 17764 | if (!candidate_ty.errorSetHasField(name)) { |
| 17765 | cand_is_superset = false; |
| 17766 | break; |
| 17767 | } |
| 17768 | } |
| 17769 | if (cand_is_superset) { |
| 17770 | // Swap to candidate |
| 17771 | err_set_ty = candidate_ty; |
| 17772 | chosen = candidate; |
| 17773 | chosen_i = candidate_i + 1; |
| 17774 | continue; |
| 17775 | } |
| 17776 | |
| 17777 | // Merge errors |
| 17778 | err_set_ty = try err_set_ty.?.errorSetMerge(sema.arena, candidate_ty); |
| 17779 | chosen = candidate; |
| 17780 | chosen_i = candidate_i + 1; |
| 17781 | continue; |
| 17782 | } |
| 17783 | }, |
| 17714 | 17784 | .ErrorUnion => { |
| 17785 | if (chosen_ty_tag == .ErrorSet) { |
| 17786 | if (err_set_ty.?.isAnyError()) { |
| 17787 | chosen = candidate; |
| 17788 | chosen_i = candidate_i + 1; |
| 17789 | continue; |
| 17790 | } |
| 17791 | |
| 17792 | const eu_set_ty = candidate_ty.errorUnionSet(); |
| 17793 | if (eu_set_ty.castTag(.error_set_inferred)) |inferred| { |
| 17794 | try sema.resolveInferredErrorSet(inferred.data); |
| 17795 | } |
| 17796 | if (eu_set_ty.isAnyError()) { |
| 17797 | err_set_ty = eu_set_ty; |
| 17798 | chosen = candidate; |
| 17799 | chosen_i = candidate_i + 1; |
| 17800 | continue; |
| 17801 | } |
| 17802 | |
| 17803 | // If candidate is a superset of the error type, then use it. |
| 17804 | var cand_is_superset = true; |
| 17805 | for (err_set_ty.?.errorSetNames()) |name| { |
| 17806 | if (!candidate_ty.errorSetHasField(name)) { |
| 17807 | cand_is_superset = false; |
| 17808 | break; |
| 17809 | } |
| 17810 | } |
| 17811 | if (cand_is_superset) { |
| 17812 | // Swap to candidate |
| 17813 | err_set_ty = candidate_ty; |
| 17814 | chosen = candidate; |
| 17815 | chosen_i = candidate_i + 1; |
| 17816 | continue; |
| 17817 | } |
| 17818 | |
| 17819 | // Not a superset, create merged error set |
| 17820 | err_set_ty = try err_set_ty.?.errorSetMerge(sema.arena, eu_set_ty); |
| 17821 | chosen = candidate; |
| 17822 | chosen_i = candidate_i + 1; |
| 17823 | continue; |
| 17824 | } |
| 17825 | |
| 17826 | if (chosen_ty_tag == .ErrorUnion) { |
| 17827 | const chosen_payload_ty = chosen_ty.errorUnionPayload(); |
| 17828 | const candidate_payload_ty = candidate_ty.errorUnionPayload(); |
| 17829 | |
| 17830 | const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok; |
| 17831 | const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok; |
| 17832 | |
| 17833 | if (coerce_chosen or coerce_candidate) { |
| 17834 | // If we can coerce to the candidate, we switch to that |
| 17835 | // type. This is the same logic as the bare (non-union) |
| 17836 | // coercion check we do at the top of this func. |
| 17837 | if (coerce_candidate) { |
| 17838 | chosen = candidate; |
| 17839 | chosen_i = candidate_i + 1; |
| 17840 | } |
| 17841 | |
| 17842 | const chosen_set_ty = chosen_ty.errorUnionSet(); |
| 17843 | const candidate_set_ty = chosen_ty.errorUnionSet(); |
| 17844 | |
| 17845 | // If our error sets match already, then we are done. |
| 17846 | if (chosen_set_ty.eql(candidate_set_ty)) continue; |
| 17847 | |
| 17848 | // They don't match, so we need to figure out if we |
| 17849 | // need to merge them, use the superset, etc. This |
| 17850 | // requires resolution. |
| 17851 | if (chosen_set_ty.castTag(.error_set_inferred)) |inferred| { |
| 17852 | try sema.resolveInferredErrorSet(inferred.data); |
| 17853 | } |
| 17854 | if (candidate_set_ty.castTag(.error_set_inferred)) |inferred| { |
| 17855 | try sema.resolveInferredErrorSet(inferred.data); |
| 17856 | } |
| 17857 | |
| 17858 | if (chosen_set_ty.isAnyError()) { |
| 17859 | err_set_ty = chosen_set_ty; |
| 17860 | continue; |
| 17861 | } |
| 17862 | |
| 17863 | if (candidate_set_ty.isAnyError()) { |
| 17864 | err_set_ty = candidate_set_ty; |
| 17865 | continue; |
| 17866 | } |
| 17867 | |
| 17868 | if (err_set_ty == null) err_set_ty = chosen_set_ty; |
| 17869 | |
| 17870 | // If the previous error set type is a superset, we're done. |
| 17871 | var prev_is_superset = true; |
| 17872 | for (candidate_set_ty.errorSetNames()) |name| { |
| 17873 | if (!chosen_set_ty.errorSetHasField(name)) { |
| 17874 | prev_is_superset = false; |
| 17875 | break; |
| 17876 | } |
| 17877 | } |
| 17878 | if (prev_is_superset) continue; // use previous |
| 17879 | |
| 17880 | var cand_is_superset = true; |
| 17881 | for (chosen_set_ty.errorSetNames()) |name| { |
| 17882 | if (!candidate_set_ty.errorSetHasField(name)) { |
| 17883 | cand_is_superset = false; |
| 17884 | break; |
| 17885 | } |
| 17886 | } |
| 17887 | if (cand_is_superset) { |
| 17888 | err_set_ty = candidate_ty; |
| 17889 | continue; |
| 17890 | } |
| 17891 | |
| 17892 | // Merge errors |
| 17893 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); |
| 17894 | continue; |
| 17895 | } |
| 17896 | } |
| 17897 | |
| 17715 | 17898 | const payload_ty = candidate_ty.errorUnionPayload(); |
| 17716 | 17899 | if (chosen_ty_tag == .Pointer and |
| 17717 | 17900 | chosen_ty.ptrSize() == .One and |
| ... | ... | @@ -17962,6 +18145,24 @@ fn resolvePeerTypes( |
| 17962 | 18145 | return Type.ptr(sema.arena, target, info.data); |
| 17963 | 18146 | } |
| 17964 | 18147 | |
| 18148 | if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) { |
| 18149 | .ErrorSet => return ty, |
| 18150 | |
| 18151 | .ErrorUnion => { |
| 18152 | const payload_ty = chosen_ty.errorUnionPayload(); |
| 18153 | return try Module.errorUnionType(sema.arena, ty, payload_ty); |
| 18154 | }, |
| 18155 | |
| 18156 | .ComptimeInt, .ComptimeFloat => return sema.fail(block, src, "unable to make error union out of number literal", .{}), |
| 18157 | |
| 18158 | .Null => return sema.fail(block, src, "unable to make error union out of null literal", .{}), |
| 18159 | |
| 18160 | else => { |
| 18161 | // Create error union of our error set and the chosen type |
| 18162 | return try Module.errorUnionType(sema.arena, ty, chosen_ty); |
| 18163 | }, |
| 18164 | }; |
| 18165 | |
| 17965 | 18166 | return chosen_ty; |
| 17966 | 18167 | } |
| 17967 | 18168 | |