| author | |
| committer | |
| log | 38aae2cb7cc1dfa906336392a422153b9a345401 |
| tree | 3e14f922761d1846e46ce9a0f15b4893a38e4296 |
| parent | bfada7c5144ce7f99ab92a76f65ca310440a2df9 |
2 files changed, 148 insertions(+), 14 deletions(-)
src/Sema.zig+58-14| ... | ... | @@ -17635,20 +17635,8 @@ fn resolvePeerTypes( |
| 17635 | 17635 | if (candidate_ty.eql(chosen_ty)) |
| 17636 | 17636 | continue; |
| 17637 | 17637 | |
| 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 | 17638 | const candidate_ty_tag = candidate_ty.zigTypeTag(); |
| 17650 | 17639 | const chosen_ty_tag = chosen_ty.zigTypeTag(); |
| 17651 | ||
| 17652 | 17640 | switch (candidate_ty_tag) { |
| 17653 | 17641 | .NoReturn, .Undefined => continue, |
| 17654 | 17642 | |
| ... | ... | @@ -17780,6 +17768,51 @@ fn resolvePeerTypes( |
| 17780 | 17768 | chosen_i = candidate_i + 1; |
| 17781 | 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 | 17817 | .ErrorUnion => { |
| 17785 | 17818 | if (chosen_ty_tag == .ErrorSet) { |
| ... | ... | @@ -17803,14 +17836,14 @@ fn resolvePeerTypes( |
| 17803 | 17836 | // If candidate is a superset of the error type, then use it. |
| 17804 | 17837 | var cand_is_superset = true; |
| 17805 | 17838 | for (err_set_ty.?.errorSetNames()) |name| { |
| 17806 | if (!candidate_ty.errorSetHasField(name)) { | |
| 17839 | if (!eu_set_ty.errorSetHasField(name)) { | |
| 17807 | 17840 | cand_is_superset = false; |
| 17808 | 17841 | break; |
| 17809 | 17842 | } |
| 17810 | 17843 | } |
| 17811 | 17844 | if (cand_is_superset) { |
| 17812 | 17845 | // Swap to candidate |
| 17813 | err_set_ty = candidate_ty; | |
| 17846 | err_set_ty = eu_set_ty; | |
| 17814 | 17847 | chosen = candidate; |
| 17815 | 17848 | chosen_i = candidate_i + 1; |
| 17816 | 17849 | continue; |
| ... | ... | @@ -18085,6 +18118,17 @@ fn resolvePeerTypes( |
| 18085 | 18118 | else => {}, |
| 18086 | 18119 | } |
| 18087 | 18120 | |
| 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 | 18132 | // At this point, we hit a compile error. We need to recover |
| 18089 | 18133 | // the source locations. |
| 18090 | 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 | 615 | try expect(transformed_err == error.SystemResources); |
| 616 | 616 | } |
| 617 | 617 | |
| 618 | test "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 | ||
| 625 | test "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 | ||
| 650 | test "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 | ||
| 677 | test "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 | ||
| 618 | 708 | test "peer cast *[0]T to E![]const T" { |
| 619 | 709 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 620 | 710 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |