authorgravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-02-27 18:04:26-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-28 20:42:13-07:00
log38aae2cb7cc1dfa906336392a422153b9a345401
tree3e14f922761d1846e46ce9a0f15b4893a38e4296
parentbfada7c5144ce7f99ab92a76f65ca310440a2df9

stage2: peer resolve error sets and unions, add more tests


2 files changed, 148 insertions(+), 14 deletions(-)

src/Sema.zig+58-14
...@@ -17635,20 +17635,8 @@ fn resolvePeerTypes(...@@ -17635,20 +17635,8 @@ fn resolvePeerTypes(
17635 if (candidate_ty.eql(chosen_ty))17635 if (candidate_ty.eql(chosen_ty))
17636 continue;17636 continue;
1763717637
17638 // If the candidate can coerce into our chosen type, we're done.
17639 // If the chosen type can coerce into the candidate, use that.
17640 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
17641 continue;
17642 }
17643 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
17644 chosen = candidate;
17645 chosen_i = candidate_i + 1;
17646 continue;
17647 }
17648
17649 const candidate_ty_tag = candidate_ty.zigTypeTag();17638 const candidate_ty_tag = candidate_ty.zigTypeTag();
17650 const chosen_ty_tag = chosen_ty.zigTypeTag();17639 const chosen_ty_tag = chosen_ty.zigTypeTag();
17651
17652 switch (candidate_ty_tag) {17640 switch (candidate_ty_tag) {
17653 .NoReturn, .Undefined => continue,17641 .NoReturn, .Undefined => continue,
1765417642
...@@ -17780,6 +17768,51 @@ fn resolvePeerTypes(...@@ -17780,6 +17768,51 @@ fn resolvePeerTypes(
17780 chosen_i = candidate_i + 1;17768 chosen_i = candidate_i + 1;
17781 continue;17769 continue;
17782 }17770 }
17771
17772 // At this point, we must resolve any inferred error sets
17773 if (candidate_ty.castTag(.error_set_inferred)) |inferred| {
17774 try sema.resolveInferredErrorSet(inferred.data);
17775 }
17776
17777 // If anything is anyerror, we use anyerror always
17778 if (candidate_ty.isAnyError()) {
17779 err_set_ty = candidate_ty;
17780 continue;
17781 }
17782 if (err_set_ty) |ty|
17783 if (ty.isAnyError()) continue;
17784
17785 if (err_set_ty == null) {
17786 // Error unions are lazy, we're forced to resolve now.
17787 // Otherwise, our candidate type cause we've never seen
17788 // error sets up to this point
17789 if (chosen_ty_tag == .ErrorUnion) {
17790 err_set_ty = chosen_ty.errorUnionSet();
17791
17792 if (err_set_ty.?.castTag(.error_set_inferred)) |inferred| {
17793 try sema.resolveInferredErrorSet(inferred.data);
17794 }
17795
17796 if (err_set_ty.?.isAnyError()) continue;
17797 } else {
17798 err_set_ty = candidate_ty;
17799 continue;
17800 }
17801 }
17802
17803 // If previous is superset, keep the previous
17804 var prev_is_superset = true;
17805 for (candidate_ty.errorSetNames()) |name| {
17806 if (!err_set_ty.?.errorSetHasField(name)) {
17807 prev_is_superset = false;
17808 break;
17809 }
17810 }
17811 if (prev_is_superset) continue; // use previous
17812
17813 // Merge
17814 err_set_ty = try err_set_ty.?.errorSetMerge(sema.arena, candidate_ty);
17815 continue;
17783 },17816 },
17784 .ErrorUnion => {17817 .ErrorUnion => {
17785 if (chosen_ty_tag == .ErrorSet) {17818 if (chosen_ty_tag == .ErrorSet) {
...@@ -17803,14 +17836,14 @@ fn resolvePeerTypes(...@@ -17803,14 +17836,14 @@ fn resolvePeerTypes(
17803 // If candidate is a superset of the error type, then use it.17836 // If candidate is a superset of the error type, then use it.
17804 var cand_is_superset = true;17837 var cand_is_superset = true;
17805 for (err_set_ty.?.errorSetNames()) |name| {17838 for (err_set_ty.?.errorSetNames()) |name| {
17806 if (!candidate_ty.errorSetHasField(name)) {17839 if (!eu_set_ty.errorSetHasField(name)) {
17807 cand_is_superset = false;17840 cand_is_superset = false;
17808 break;17841 break;
17809 }17842 }
17810 }17843 }
17811 if (cand_is_superset) {17844 if (cand_is_superset) {
17812 // Swap to candidate17845 // Swap to candidate
17813 err_set_ty = candidate_ty;17846 err_set_ty = eu_set_ty;
17814 chosen = candidate;17847 chosen = candidate;
17815 chosen_i = candidate_i + 1;17848 chosen_i = candidate_i + 1;
17816 continue;17849 continue;
...@@ -18085,6 +18118,17 @@ fn resolvePeerTypes(...@@ -18085,6 +18118,17 @@ fn resolvePeerTypes(
18085 else => {},18118 else => {},
18086 }18119 }
1808718120
18121 // If the candidate can coerce into our chosen type, we're done.
18122 // If the chosen type can coerce into the candidate, use that.
18123 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
18124 continue;
18125 }
18126 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
18127 chosen = candidate;
18128 chosen_i = candidate_i + 1;
18129 continue;
18130 }
18131
18088 // At this point, we hit a compile error. We need to recover18132 // At this point, we hit a compile error. We need to recover
18089 // the source locations.18133 // the source locations.
18090 const chosen_src = candidate_srcs.resolve(18134 const chosen_src = candidate_srcs.resolve(
test/behavior/cast.zig+90
...@@ -615,6 +615,96 @@ test "peer type resolution: unreachable, error set, unreachable" {...@@ -615,6 +615,96 @@ test "peer type resolution: unreachable, error set, unreachable" {
615 try expect(transformed_err == error.SystemResources);615 try expect(transformed_err == error.SystemResources);
616}616}
617617
618test "peer cast: error set any anyerror" {
619 const a: error{ One, Two } = undefined;
620 const b: anyerror = undefined;
621 try expect(@TypeOf(a, b) == anyerror);
622 try expect(@TypeOf(b, a) == anyerror);
623}
624
625test "peer type resolution: error set supersets" {
626 const a: error{ One, Two } = undefined;
627 const b: error{One} = undefined;
628
629 // A superset of B
630 {
631 const ty = @TypeOf(a, b);
632 const error_set_info = @typeInfo(ty);
633 try expect(error_set_info == .ErrorSet);
634 try expect(error_set_info.ErrorSet.?.len == 2);
635 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
636 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
637 }
638
639 // B superset of A
640 {
641 const ty = @TypeOf(b, a);
642 const error_set_info = @typeInfo(ty);
643 try expect(error_set_info == .ErrorSet);
644 try expect(error_set_info.ErrorSet.?.len == 2);
645 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
646 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
647 }
648}
649
650test "peer type resolution: disjoint error sets" {
651 const a: error{ One, Two } = undefined;
652 const b: error{Three} = undefined;
653
654 // note: order of error set members doesn't member, may want to sort
655
656 {
657 const ty = @TypeOf(a, b);
658 const error_set_info = @typeInfo(ty);
659 try expect(error_set_info == .ErrorSet);
660 try expect(error_set_info.ErrorSet.?.len == 3);
661 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
662 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
663 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three"));
664 }
665
666 {
667 const ty = @TypeOf(b, a);
668 const error_set_info = @typeInfo(ty);
669 try expect(error_set_info == .ErrorSet);
670 try expect(error_set_info.ErrorSet.?.len == 3);
671 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "Three"));
672 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "One"));
673 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two"));
674 }
675}
676
677test "peer type resolution: error union and error set" {
678 const a: error{Three} = undefined;
679 const b: error{ One, Two }!u32 = undefined;
680
681 // note: order of error set members doesn't member, may want to sort
682
683 {
684 const ty = @TypeOf(a, b);
685 const info = @typeInfo(ty);
686 try expect(info == .ErrorUnion);
687
688 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
689 try expect(error_set_info.ErrorSet.?.len == 3);
690 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "Three"));
691 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "One"));
692 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two"));
693 }
694
695 {
696 const ty = @TypeOf(b, a);
697 const info = @typeInfo(ty);
698 try expect(info == .ErrorUnion);
699
700 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
701 try expect(error_set_info.ErrorSet.?.len == 3);
702 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
703 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
704 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three"));
705 }
706}
707
618test "peer cast *[0]T to E![]const T" {708test "peer cast *[0]T to E![]const T" {
619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO710 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO