authorgravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-02-27 19:00:16-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-28 20:42:13-07:00
logb4ce8557884bd8f2b3fa621c3564f9d0ff789699
treecca72056f4eb39aabb787a0e3744ec7c6db7f167
parent38aae2cb7cc1dfa906336392a422153b9a345401

stage2: error union and non-error set/union peer cast resolution


2 files changed, 84 insertions(+), 20 deletions(-)

src/Sema.zig+53-20
......@@ -17814,8 +17814,8 @@ fn resolvePeerTypes(
1781417814 err_set_ty = try err_set_ty.?.errorSetMerge(sema.arena, candidate_ty);
1781517815 continue;
1781617816 },
17817 .ErrorUnion => {
17818 if (chosen_ty_tag == .ErrorSet) {
17817 .ErrorUnion => switch (chosen_ty_tag) {
17818 .ErrorSet => {
1781917819 if (err_set_ty.?.isAnyError()) {
1782017820 chosen = candidate;
1782117821 chosen_i = candidate_i + 1;
......@@ -17854,9 +17854,9 @@ fn resolvePeerTypes(
1785417854 chosen = candidate;
1785517855 chosen_i = candidate_i + 1;
1785617856 continue;
17857 }
17857 },
1785817858
17859 if (chosen_ty_tag == .ErrorUnion) {
17859 .ErrorUnion => {
1786017860 const chosen_payload_ty = chosen_ty.errorUnionPayload();
1786117861 const candidate_payload_ty = candidate_ty.errorUnionPayload();
1786217862
......@@ -17926,30 +17926,57 @@ fn resolvePeerTypes(
1792617926 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
1792717927 continue;
1792817928 }
17929 }
17929 },
1793017930
17931 const payload_ty = candidate_ty.errorUnionPayload();
17932 if (chosen_ty_tag == .Pointer and
17933 chosen_ty.ptrSize() == .One and
17934 chosen_ty.childType().zigTypeTag() == .Array and
17935 payload_ty.isSlice())
17936 {
17937 const chosen_child_ty = chosen_ty.childType();
17938 const chosen_elem_ty = chosen_child_ty.elemType2();
17939 const candidate_elem_ty = payload_ty.elemType2();
17940 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
17931 .Pointer => {
17932 const payload_ty = candidate_ty.errorUnionPayload();
17933 if (chosen_ty.ptrSize() == .One and
17934 chosen_ty.childType().zigTypeTag() == .Array and
17935 payload_ty.isSlice())
17936 {
17937 const chosen_child_ty = chosen_ty.childType();
17938 const chosen_elem_ty = chosen_child_ty.elemType2();
17939 const candidate_elem_ty = payload_ty.elemType2();
17940 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
17941 chosen = candidate;
17942 chosen_i = candidate_i + 1;
17943
17944 convert_to_slice = false; // it already is a slice
17945
17946 // If the prev pointer is const then we need to const
17947 if (chosen_child_ty.isConstPtr())
17948 make_the_slice_const = true;
17949
17950 continue;
17951 }
17952 }
17953 },
17954
17955 else => {
17956 // Chosen coercing into payload type
17957 // Then merge error sets (if any)
17958 const payload_ty = candidate_ty.errorUnionPayload();
17959 if ((try sema.coerceInMemoryAllowed(block, payload_ty, chosen_ty, false, target, src, src)) == .ok) {
1794117960 chosen = candidate;
1794217961 chosen_i = candidate_i + 1;
1794317962
17944 convert_to_slice = false; // it already is a slice
17963 if (err_set_ty) |ty| {
17964 const cand_set_ty = candidate_ty.errorUnionSet();
17965 if (cand_set_ty.castTag(.error_set_inferred)) |inferred| {
17966 try sema.resolveInferredErrorSet(inferred.data);
17967 }
17968 if (cand_set_ty.isAnyError()) {
17969 err_set_ty = cand_set_ty;
17970 continue;
17971 }
17972 if (ty.isAnyError()) continue;
1794517973
17946 // If the prev pointer is const then we need to const
17947 if (chosen_child_ty.isConstPtr())
17948 make_the_slice_const = true;
17974 err_set_ty = try err_set_ty.?.errorSetMerge(sema.arena, cand_set_ty);
17975 }
1794917976
1795017977 continue;
1795117978 }
17952 }
17979 },
1795317980 },
1795417981 .Pointer => {
1795517982 if (candidate_ty.ptrSize() == .C) {
......@@ -18115,6 +18142,12 @@ fn resolvePeerTypes(
1811518142 continue;
1811618143 }
1811718144 },
18145 .ErrorUnion => {
18146 const payload_ty = chosen_ty.errorUnionPayload();
18147 if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) {
18148 continue;
18149 }
18150 },
1811818151 else => {},
1811918152 }
1812018153
test/behavior/cast.zig+31
......@@ -705,6 +705,37 @@ test "peer type resolution: error union and error set" {
705705 }
706706}
707707
708test "peer type resolution: error union after non-error" {
709 const a: u32 = undefined;
710 const b: error{ One, Two }!u32 = undefined;
711
712 // note: order of error set members doesn't member, may want to sort
713
714 {
715 const ty = @TypeOf(a, b);
716 const info = @typeInfo(ty);
717 try expect(info == .ErrorUnion);
718 try expect(info.ErrorUnion.payload == u32);
719
720 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
721 try expect(error_set_info.ErrorSet.?.len == 2);
722 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
723 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
724 }
725
726 {
727 const ty = @TypeOf(b, a);
728 const info = @typeInfo(ty);
729 try expect(info == .ErrorUnion);
730 try expect(info.ErrorUnion.payload == u32);
731
732 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
733 try expect(error_set_info.ErrorSet.?.len == 2);
734 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
735 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
736 }
737}
738
708739test "peer cast *[0]T to E![]const T" {
709740 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
710741 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO