authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-01 01:22:50-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-01 01:22:50-05:00
logeaf1c97ce80606505768b8dd8daf8b479aec91a7
treea4f38b1e2150b5d2a88c66d2d96c23b9dd39775c
parentd5131e91eba9324eda3a2ae47eb2aa4530c87e83
parent4763fd1a41bc5f6bb59b5c3c079069b84f19305a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11010 from mitchellh/peer-errors

stage2: peer resolve error sets and error unions

4 files changed, 349 insertions(+), 79 deletions(-)

src/Sema.zig+185-77
...@@ -5141,15 +5141,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5141,15 +5141,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
5141 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;5141 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
5142 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };5142 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
5143 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };5143 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
5144 const error_union = try sema.resolveType(block, lhs_src, extra.lhs);5144 const error_set = try sema.resolveType(block, lhs_src, extra.lhs);
5145 const payload = try sema.resolveType(block, rhs_src, extra.rhs);5145 const payload = try sema.resolveType(block, rhs_src, extra.rhs);
51465146
5147 if (error_union.zigTypeTag() != .ErrorSet) {5147 if (error_set.zigTypeTag() != .ErrorSet) {
5148 return sema.fail(block, lhs_src, "expected error set type, found {}", .{5148 return sema.fail(block, lhs_src, "expected error set type, found {}", .{
5149 error_union.elemType(),5149 error_set,
5150 });5150 });
5151 }5151 }
5152 const err_union_ty = try Module.errorUnionType(sema.arena, error_union, payload);5152 const err_union_ty = try Module.errorUnionType(sema.arena, error_set, payload);
5153 return sema.addType(err_union_ty);5153 return sema.addType(err_union_ty);
5154}5154}
51555155
...@@ -5281,31 +5281,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5281,31 +5281,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
5281 }5281 }
5282 }5282 }
52835283
5284 // Resolve both error sets now.5284 const err_set_ty = try lhs_ty.errorSetMerge(sema.arena, rhs_ty);
5285 const lhs_names = lhs_ty.errorSetNames();
5286 const rhs_names = rhs_ty.errorSetNames();
5287
5288 // TODO do we really want to create a Decl for this?
5289 // The reason we do it right now is for memory management.
5290 var anon_decl = try block.startAnonDecl(src);
5291 defer anon_decl.deinit();
5292
5293 var names = Module.ErrorSet.NameMap{};
5294 // TODO: Guess is an upper bound, but maybe this needs to be reduced by computing the exact size first.
5295 try names.ensureUnusedCapacity(anon_decl.arena(), @intCast(u32, lhs_names.len + rhs_names.len));
5296 for (lhs_names) |name| {
5297 names.putAssumeCapacityNoClobber(name, {});
5298 }
5299 for (rhs_names) |name| {
5300 names.putAssumeCapacity(name, {});
5301 }
5302
5303 const err_set_ty = try Type.Tag.error_set_merged.create(anon_decl.arena(), names);
5304 const err_set_decl = try anon_decl.finish(
5305 Type.type,
5306 try Value.Tag.ty.create(anon_decl.arena(), err_set_ty),
5307 );
5308 try sema.mod.declareDeclDependency(sema.owner_decl, err_set_decl);
5309 return sema.addType(err_set_ty);5285 return sema.addType(err_set_ty);
5310}5286}
53115287
...@@ -6858,9 +6834,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -6858,9 +6834,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
6858 }6834 }
6859 }6835 }
68606836
6861 if (operand_ty.castTag(.error_set_inferred)) |inferred| {6837 try sema.resolveInferredErrorSetTy(operand_ty);
6862 try sema.resolveInferredErrorSet(inferred.data);
6863 }
68646838
6865 if (operand_ty.isAnyError()) {6839 if (operand_ty.isAnyError()) {
6866 if (special_prong != .@"else") {6840 if (special_prong != .@"else") {
...@@ -10361,9 +10335,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -10361,9 +10335,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
10361 };10335 };
1036210336
10363 // If the error set is inferred it has to be resolved at this point10337 // If the error set is inferred it has to be resolved at this point
10364 if (ty.castTag(.error_set_inferred)) |payload| {10338 try sema.resolveInferredErrorSetTy(ty);
10365 try sema.resolveInferredErrorSet(payload.data);
10366 }
1036710339
10368 // Build our list of Error values10340 // Build our list of Error values
10369 // Optional value is only null if anyerror10341 // Optional value is only null if anyerror
...@@ -17610,29 +17582,24 @@ fn resolvePeerTypes(...@@ -17610,29 +17582,24 @@ fn resolvePeerTypes(
17610 const target = sema.mod.getTarget();17582 const target = sema.mod.getTarget();
1761117583
17612 var chosen = instructions[0];17584 var chosen = instructions[0];
17585 // If this is non-null then it does the following thing, depending on the chosen zigTypeTag().
17586 // * ErrorSet: this is an override
17587 // * ErrorUnion: this is an override of the error set only
17588 // * other: at the end we make an ErrorUnion with the other thing and this
17589 var err_set_ty: ?Type = null;
17613 var any_are_null = false;17590 var any_are_null = false;
17614 var make_the_slice_const = false;17591 var seen_const = false;
17615 var convert_to_slice = false;17592 var convert_to_slice = false;
17616 var chosen_i: usize = 0;17593 var chosen_i: usize = 0;
17617 for (instructions[1..]) |candidate, candidate_i| {17594 for (instructions[1..]) |candidate, candidate_i| {
17618 const candidate_ty = sema.typeOf(candidate);17595 const candidate_ty = sema.typeOf(candidate);
17619 const chosen_ty = sema.typeOf(chosen);17596 const chosen_ty = sema.typeOf(chosen);
17620 if (candidate_ty.eql(chosen_ty))
17621 continue;
1762217597
17623 // If the candidate can coerce into our chosen type, we're done.17598 const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison();
17624 // If the chosen type can coerce into the candidate, use that.17599 const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison();
17625 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
17626 continue;
17627 }
17628 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
17629 chosen = candidate;
17630 chosen_i = candidate_i + 1;
17631 continue;
17632 }
1763317600
17634 const candidate_ty_tag = candidate_ty.zigTypeTag();17601 if (candidate_ty.eql(chosen_ty))
17635 const chosen_ty_tag = chosen_ty.zigTypeTag();17602 continue;
1763617603
17637 switch (candidate_ty_tag) {17604 switch (candidate_ty_tag) {
17638 .NoReturn, .Undefined => continue,17605 .NoReturn, .Undefined => continue,
...@@ -17711,29 +17678,121 @@ fn resolvePeerTypes(...@@ -17711,29 +17678,121 @@ fn resolvePeerTypes(
17711 },17678 },
17712 else => {},17679 else => {},
17713 },17680 },
17714 .ErrorUnion => {17681 .ErrorSet => switch (chosen_ty_tag) {
17715 const payload_ty = candidate_ty.errorUnionPayload();17682 .ErrorSet => {
17716 if (chosen_ty_tag == .Pointer and17683 // If chosen is superset of candidate, keep it.
17717 chosen_ty.ptrSize() == .One and17684 // If candidate is superset of chosen, switch it.
17718 chosen_ty.childType().zigTypeTag() == .Array and17685 // If neither is a superset, merge errors.
17719 payload_ty.isSlice())17686 const chosen_set_ty = err_set_ty orelse chosen_ty;
17720 {17687
17721 const chosen_child_ty = chosen_ty.childType();17688 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_ty)) {
17722 const chosen_elem_ty = chosen_child_ty.elemType2();17689 continue;
17723 const candidate_elem_ty = payload_ty.elemType2();17690 }
17724 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {17691 if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_ty, chosen_set_ty)) {
17692 err_set_ty = null;
17725 chosen = candidate;17693 chosen = candidate;
17726 chosen_i = candidate_i + 1;17694 chosen_i = candidate_i + 1;
17695 continue;
17696 }
1772717697
17728 convert_to_slice = false; // it already is a slice17698 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
17699 continue;
17700 },
17701 .ErrorUnion => {
17702 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
1772917703
17730 // If the prev pointer is const then we need to const17704 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_ty)) {
17731 if (chosen_child_ty.isConstPtr())17705 continue;
17732 make_the_slice_const = true;17706 }
17707 if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_ty, chosen_set_ty)) {
17708 err_set_ty = candidate_ty;
17709 continue;
17710 }
1773317711
17712 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
17713 continue;
17714 },
17715 else => {
17716 if (err_set_ty) |chosen_set_ty| {
17717 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_ty)) {
17718 continue;
17719 }
17720 if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_ty, chosen_set_ty)) {
17721 err_set_ty = candidate_ty;
17722 continue;
17723 }
17724
17725 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
17726 continue;
17727 } else {
17728 err_set_ty = candidate_ty;
17734 continue;17729 continue;
17735 }17730 }
17736 }17731 },
17732 },
17733 .ErrorUnion => switch (chosen_ty_tag) {
17734 .ErrorSet => {
17735 const chosen_set_ty = err_set_ty orelse chosen_ty;
17736 const candidate_set_ty = candidate_ty.errorUnionSet();
17737
17738 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_set_ty)) {
17739 err_set_ty = chosen_set_ty;
17740 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_set_ty, chosen_set_ty)) {
17741 err_set_ty = null;
17742 } else {
17743 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
17744 }
17745 chosen = candidate;
17746 chosen_i = candidate_i + 1;
17747 continue;
17748 },
17749
17750 .ErrorUnion => {
17751 const chosen_payload_ty = chosen_ty.errorUnionPayload();
17752 const candidate_payload_ty = candidate_ty.errorUnionPayload();
17753
17754 const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok;
17755 const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok;
17756
17757 if (coerce_chosen or coerce_candidate) {
17758 // If we can coerce to the candidate, we switch to that
17759 // type. This is the same logic as the bare (non-union)
17760 // coercion check we do at the top of this func.
17761 if (coerce_candidate) {
17762 chosen = candidate;
17763 chosen_i = candidate_i + 1;
17764 }
17765
17766 const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
17767 const candidate_set_ty = chosen_ty.errorUnionSet();
17768
17769 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_set_ty)) {
17770 err_set_ty = chosen_set_ty;
17771 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_set_ty, chosen_set_ty)) {
17772 err_set_ty = candidate_set_ty;
17773 } else {
17774 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
17775 }
17776 continue;
17777 }
17778 },
17779
17780 else => {
17781 if (err_set_ty) |chosen_set_ty| {
17782 const candidate_set_ty = candidate_ty.errorUnionSet();
17783 if (.ok == try sema.coerceInMemoryAllowedErrorSets(chosen_set_ty, candidate_set_ty)) {
17784 err_set_ty = chosen_set_ty;
17785 } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(candidate_set_ty, chosen_set_ty)) {
17786 err_set_ty = null;
17787 } else {
17788 err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
17789 }
17790 }
17791 seen_const = seen_const or chosen_ty.isConstPtr();
17792 chosen = candidate;
17793 chosen_i = candidate_i + 1;
17794 continue;
17795 },
17737 },17796 },
17738 .Pointer => {17797 .Pointer => {
17739 if (candidate_ty.ptrSize() == .C) {17798 if (candidate_ty.ptrSize() == .C) {
...@@ -17759,7 +17818,7 @@ fn resolvePeerTypes(...@@ -17759,7 +17818,7 @@ fn resolvePeerTypes(
17759 convert_to_slice = false;17818 convert_to_slice = false;
1776017819
17761 if (chosen_ty.childType().isConstPtr() and !candidate_ty.childType().isConstPtr())17820 if (chosen_ty.childType().isConstPtr() and !candidate_ty.childType().isConstPtr())
17762 make_the_slice_const = true;17821 seen_const = true;
1776317822
17764 continue;17823 continue;
17765 }17824 }
...@@ -17771,7 +17830,7 @@ fn resolvePeerTypes(...@@ -17771,7 +17830,7 @@ fn resolvePeerTypes(
17771 chosen_ty.ptrSize() == .Many)17830 chosen_ty.ptrSize() == .Many)
17772 {17831 {
17773 if (candidate_ty.childType().isConstPtr() and !chosen_ty.childType().isConstPtr())17832 if (candidate_ty.childType().isConstPtr() and !chosen_ty.childType().isConstPtr())
17774 make_the_slice_const = true;17833 seen_const = true;
1777517834
17776 continue;17835 continue;
17777 }17836 }
...@@ -17792,7 +17851,7 @@ fn resolvePeerTypes(...@@ -17792,7 +17851,7 @@ fn resolvePeerTypes(
1779217851
17793 // If the pointer is const then we need to const17852 // If the pointer is const then we need to const
17794 if (candidate_ty.childType().isConstPtr())17853 if (candidate_ty.childType().isConstPtr())
17795 make_the_slice_const = true;17854 seen_const = true;
1779617855
17797 continue;17856 continue;
17798 }17857 }
...@@ -17815,7 +17874,7 @@ fn resolvePeerTypes(...@@ -17815,7 +17874,7 @@ fn resolvePeerTypes(
1781517874
17816 // If the prev pointer is const then we need to const17875 // If the prev pointer is const then we need to const
17817 if (chosen_child_ty.isConstPtr())17876 if (chosen_child_ty.isConstPtr())
17818 make_the_slice_const = true;17877 seen_const = true;
1781917878
17820 continue;17879 continue;
17821 }17880 }
...@@ -17851,7 +17910,7 @@ fn resolvePeerTypes(...@@ -17851,7 +17910,7 @@ fn resolvePeerTypes(
17851 // If one of the pointers is to const data, the slice17910 // If one of the pointers is to const data, the slice
17852 // must also be const.17911 // must also be const.
17853 if (candidate_child_ty.isConstPtr() or chosen_child_ty.isConstPtr())17912 if (candidate_child_ty.isConstPtr() or chosen_child_ty.isConstPtr())
17854 make_the_slice_const = true;17913 seen_const = true;
1785517914
17856 continue;17915 continue;
17857 }17916 }
...@@ -17899,9 +17958,26 @@ fn resolvePeerTypes(...@@ -17899,9 +17958,26 @@ fn resolvePeerTypes(
17899 continue;17958 continue;
17900 }17959 }
17901 },17960 },
17961 .ErrorUnion => {
17962 const payload_ty = chosen_ty.errorUnionPayload();
17963 if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) {
17964 continue;
17965 }
17966 },
17902 else => {},17967 else => {},
17903 }17968 }
1790417969
17970 // If the candidate can coerce into our chosen type, we're done.
17971 // If the chosen type can coerce into the candidate, use that.
17972 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
17973 continue;
17974 }
17975 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
17976 chosen = candidate;
17977 chosen_i = candidate_i + 1;
17978 continue;
17979 }
17980
17905 // At this point, we hit a compile error. We need to recover17981 // At this point, we hit a compile error. We need to recover
17906 // the source locations.17982 // the source locations.
17907 const chosen_src = candidate_srcs.resolve(17983 const chosen_src = candidate_srcs.resolve(
...@@ -17945,23 +18021,49 @@ fn resolvePeerTypes(...@@ -17945,23 +18021,49 @@ fn resolvePeerTypes(
17945 var info = chosen_ty.ptrInfo();18021 var info = chosen_ty.ptrInfo();
17946 info.data.sentinel = chosen_child_ty.sentinel();18022 info.data.sentinel = chosen_child_ty.sentinel();
17947 info.data.size = .Slice;18023 info.data.size = .Slice;
17948 info.data.mutable = chosen_child_ty.isConstPtr() or make_the_slice_const;18024 info.data.mutable = seen_const or chosen_child_ty.isConstPtr();
17949 info.data.pointee_type = switch (chosen_child_ty.tag()) {18025 info.data.pointee_type = switch (chosen_child_ty.tag()) {
17950 .array => chosen_child_ty.elemType2(),18026 .array => chosen_child_ty.elemType2(),
17951 .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8),18027 .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8),
17952 else => unreachable,18028 else => unreachable,
17953 };18029 };
1795418030
17955 return Type.ptr(sema.arena, target, info.data);18031 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);
18032 const set_ty = err_set_ty orelse return new_ptr_ty;
18033 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);
17956 }18034 }
1795718035
17958 if (make_the_slice_const) {18036 if (seen_const) {
17959 // turn []T => []const T18037 // turn []T => []const T
17960 var info = chosen_ty.ptrInfo();18038 switch (chosen_ty.zigTypeTag()) {
17961 info.data.mutable = false;18039 .ErrorUnion => {
17962 return Type.ptr(sema.arena, target, info.data);18040 const ptr_ty = chosen_ty.errorUnionPayload();
18041 var info = ptr_ty.ptrInfo();
18042 info.data.mutable = false;
18043 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);
18044 const set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
18045 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);
18046 },
18047 .Pointer => {
18048 var info = chosen_ty.ptrInfo();
18049 info.data.mutable = false;
18050 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);
18051 const set_ty = err_set_ty orelse return new_ptr_ty;
18052 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);
18053 },
18054 else => return chosen_ty,
18055 }
17963 }18056 }
1796418057
18058 if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) {
18059 .ErrorSet => return ty,
18060 .ErrorUnion => {
18061 const payload_ty = chosen_ty.errorUnionPayload();
18062 return try Module.errorUnionType(sema.arena, ty, payload_ty);
18063 },
18064 else => return try Module.errorUnionType(sema.arena, ty, chosen_ty),
18065 };
18066
17965 return chosen_ty;18067 return chosen_ty;
17966}18068}
1796718069
...@@ -18248,6 +18350,12 @@ fn resolveInferredErrorSet(sema: *Sema, inferred_error_set: *Module.Fn.InferredE...@@ -18248,6 +18350,12 @@ fn resolveInferredErrorSet(sema: *Sema, inferred_error_set: *Module.Fn.InferredE
18248 inferred_error_set.is_resolved = true;18350 inferred_error_set.is_resolved = true;
18249}18351}
1825018352
18353fn resolveInferredErrorSetTy(sema: *Sema, ty: Type) CompileError!void {
18354 if (ty.castTag(.error_set_inferred)) |inferred| {
18355 try sema.resolveInferredErrorSet(inferred.data);
18356 }
18357}
18358
18251fn semaStructFields(18359fn semaStructFields(
18252 mod: *Module,18360 mod: *Module,
18253 struct_obj: *Module.Struct,18361 struct_obj: *Module.Struct,
src/type.zig+17
...@@ -4216,6 +4216,23 @@ pub const Type = extern union {...@@ -4216,6 +4216,23 @@ pub const Type = extern union {
4216 };4216 };
4217 }4217 }
42184218
4219 /// Merge lhs with rhs.
4220 /// Asserts that lhs and rhs are both error sets and are resolved.
4221 pub fn errorSetMerge(lhs: Type, arena: Allocator, rhs: Type) !Type {
4222 const lhs_names = lhs.errorSetNames();
4223 const rhs_names = rhs.errorSetNames();
4224 var names: Module.ErrorSet.NameMap = .{};
4225 try names.ensureUnusedCapacity(arena, lhs_names.len);
4226 for (lhs_names) |name| {
4227 names.putAssumeCapacityNoClobber(name, {});
4228 }
4229 for (rhs_names) |name| {
4230 try names.put(arena, name, {});
4231 }
4232
4233 return try Tag.error_set_merged.create(arena, names);
4234 }
4235
4219 pub fn enumFields(ty: Type) Module.EnumFull.NameMap {4236 pub fn enumFields(ty: Type) Module.EnumFull.NameMap {
4220 return switch (ty.tag()) {4237 return switch (ty.tag()) {
4221 .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.fields,4238 .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.fields,
test/behavior/cast.zig+145-1
...@@ -591,7 +591,10 @@ test "@floatCast cast down" {...@@ -591,7 +591,10 @@ test "@floatCast cast down" {
591}591}
592592
593test "peer type resolution: unreachable, error set, unreachable" {593test "peer type resolution: unreachable, error set, unreachable" {
594 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO594 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
595 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
596 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
597 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
595598
596 const Error = error{599 const Error = error{
597 FileDescriptorAlreadyPresentInSet,600 FileDescriptorAlreadyPresentInSet,
...@@ -615,6 +618,147 @@ test "peer type resolution: unreachable, error set, unreachable" {...@@ -615,6 +618,147 @@ test "peer type resolution: unreachable, error set, unreachable" {
615 try expect(transformed_err == error.SystemResources);618 try expect(transformed_err == error.SystemResources);
616}619}
617620
621test "peer cast: error set any anyerror" {
622 const a: error{ One, Two } = undefined;
623 const b: anyerror = undefined;
624 try expect(@TypeOf(a, b) == anyerror);
625 try expect(@TypeOf(b, a) == anyerror);
626}
627
628test "peer type resolution: error set supersets" {
629 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
630 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
631 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
632
633 const a: error{ One, Two } = undefined;
634 const b: error{One} = undefined;
635
636 // A superset of B
637 {
638 const ty = @TypeOf(a, b);
639 const error_set_info = @typeInfo(ty);
640 try expect(error_set_info == .ErrorSet);
641 try expect(error_set_info.ErrorSet.?.len == 2);
642 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
643 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
644 }
645
646 // B superset of A
647 {
648 const ty = @TypeOf(b, a);
649 const error_set_info = @typeInfo(ty);
650 try expect(error_set_info == .ErrorSet);
651 try expect(error_set_info.ErrorSet.?.len == 2);
652 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
653 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
654 }
655}
656
657test "peer type resolution: disjoint error sets" {
658 if (builtin.zig_backend == .stage1) {
659 // stage1 gets the order of the error names wrong after merging the sets.
660 return error.SkipZigTest;
661 }
662
663 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
664 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
665 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
666
667 const a: error{ One, Two } = undefined;
668 const b: error{Three} = undefined;
669
670 {
671 const ty = @TypeOf(a, b);
672 const error_set_info = @typeInfo(ty);
673 try expect(error_set_info == .ErrorSet);
674 try expect(error_set_info.ErrorSet.?.len == 3);
675 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
676 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
677 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three"));
678 }
679
680 {
681 const ty = @TypeOf(b, a);
682 const error_set_info = @typeInfo(ty);
683 try expect(error_set_info == .ErrorSet);
684 try expect(error_set_info.ErrorSet.?.len == 3);
685 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "Three"));
686 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "One"));
687 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two"));
688 }
689}
690
691test "peer type resolution: error union and error set" {
692 if (builtin.zig_backend == .stage1) {
693 // stage1 gets the order of the error names wrong after merging the sets.
694 return error.SkipZigTest;
695 }
696
697 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
698 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
699 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
700
701 const a: error{Three} = undefined;
702 const b: error{ One, Two }!u32 = undefined;
703
704 {
705 const ty = @TypeOf(a, b);
706 const info = @typeInfo(ty);
707 try expect(info == .ErrorUnion);
708
709 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
710 try expect(error_set_info.ErrorSet.?.len == 3);
711 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "Three"));
712 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "One"));
713 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two"));
714 }
715
716 {
717 const ty = @TypeOf(b, a);
718 const info = @typeInfo(ty);
719 try expect(info == .ErrorUnion);
720
721 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
722 try expect(error_set_info.ErrorSet.?.len == 3);
723 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
724 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
725 try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three"));
726 }
727}
728
729test "peer type resolution: error union after non-error" {
730 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
731 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
732 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
733
734 const a: u32 = undefined;
735 const b: error{ One, Two }!u32 = undefined;
736
737 {
738 const ty = @TypeOf(a, b);
739 const info = @typeInfo(ty);
740 try expect(info == .ErrorUnion);
741 try expect(info.ErrorUnion.payload == u32);
742
743 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
744 try expect(error_set_info.ErrorSet.?.len == 2);
745 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
746 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
747 }
748
749 {
750 const ty = @TypeOf(b, a);
751 const info = @typeInfo(ty);
752 try expect(info == .ErrorUnion);
753 try expect(info.ErrorUnion.payload == u32);
754
755 const error_set_info = @typeInfo(info.ErrorUnion.error_set);
756 try expect(error_set_info.ErrorSet.?.len == 2);
757 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
758 try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
759 }
760}
761
618test "peer cast *[0]T to E![]const T" {762test "peer cast *[0]T to E![]const T" {
619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;763 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO764 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
test/behavior/error.zig+2-1
...@@ -264,7 +264,8 @@ fn testErrToIntWithOnePossibleValue(...@@ -264,7 +264,8 @@ fn testErrToIntWithOnePossibleValue(
264}264}
265265
266test "error union peer type resolution" {266test "error union peer type resolution" {
267 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
268269
269 try testErrorUnionPeerTypeResolution(1);270 try testErrorUnionPeerTypeResolution(1);
270}271}