| ... | @@ -17610,6 +17610,21 @@ fn resolvePeerTypes( | ... | @@ -17610,6 +17610,21 @@ fn resolvePeerTypes( |
| 17610 | const target = sema.mod.getTarget(); | 17610 | const target = sema.mod.getTarget(); |
| 17611 | | 17611 | |
| 17612 | var chosen = instructions[0]; | 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 | var any_are_null = false; | 17628 | var any_are_null = false; |
| 17614 | var make_the_slice_const = false; | 17629 | var make_the_slice_const = false; |
| 17615 | var convert_to_slice = false; | 17630 | var convert_to_slice = false; |
| ... | @@ -17711,7 +17726,175 @@ fn resolvePeerTypes( | ... | @@ -17711,7 +17726,175 @@ fn resolvePeerTypes( |
| 17711 | }, | 17726 | }, |
| 17712 | else => {}, | 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 | .ErrorUnion => { | 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 | const payload_ty = candidate_ty.errorUnionPayload(); | 17898 | const payload_ty = candidate_ty.errorUnionPayload(); |
| 17716 | if (chosen_ty_tag == .Pointer and | 17899 | if (chosen_ty_tag == .Pointer and |
| 17717 | chosen_ty.ptrSize() == .One and | 17900 | chosen_ty.ptrSize() == .One and |
| ... | @@ -17962,6 +18145,24 @@ fn resolvePeerTypes( | ... | @@ -17962,6 +18145,24 @@ fn resolvePeerTypes( |
| 17962 | return Type.ptr(sema.arena, target, info.data); | 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 | return chosen_ty; | 18166 | return chosen_ty; |
| 17966 | } | 18167 | } |
| 17967 | | 18168 | |