| author | |
| committer | |
| log | 6d2945f1fe387c55eff003ada6e72146daff10f2 |
| tree | 5265ef17dbd7e3c95ed22f578da42307222dddfc |
| parent | 227fb4875f5084cdb3436c40c4a08809bd3e4f50 |
| parent | 0b9fccf508dc85fa522947d1cf6ff84f78f2dcb4 |
| signature |
compiler: implement decl literals17 files changed, 336 insertions(+), 15 deletions(-)
lib/std/array_hash_map.zig+8| ... | @@ -510,6 +510,8 @@ pub fn ArrayHashMap( | ... | @@ -510,6 +510,8 @@ pub fn ArrayHashMap( |
| 510 | /// `store_hash` is `false` and the number of entries in the map is less than 9, | 510 | /// `store_hash` is `false` and the number of entries in the map is less than 9, |
| 511 | /// the overhead cost of using `ArrayHashMapUnmanaged` rather than `std.ArrayList` is | 511 | /// the overhead cost of using `ArrayHashMapUnmanaged` rather than `std.ArrayList` is |
| 512 | /// only a single pointer-sized integer. | 512 | /// only a single pointer-sized integer. |
| 513 | /// | ||
| 514 | /// Default initialization of this struct is deprecated; use `.empty` instead. | ||
| 513 | pub fn ArrayHashMapUnmanaged( | 515 | pub fn ArrayHashMapUnmanaged( |
| 514 | comptime K: type, | 516 | comptime K: type, |
| 515 | comptime V: type, | 517 | comptime V: type, |
| ... | @@ -538,6 +540,12 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -538,6 +540,12 @@ pub fn ArrayHashMapUnmanaged( |
| 538 | /// Used to detect memory safety violations. | 540 | /// Used to detect memory safety violations. |
| 539 | pointer_stability: std.debug.SafetyLock = .{}, | 541 | pointer_stability: std.debug.SafetyLock = .{}, |
| 540 | 542 | ||
| 543 | /// A map containing no keys or values. | ||
| 544 | pub const empty: Self = .{ | ||
| 545 | .entries = .{}, | ||
| 546 | .index_header = null, | ||
| 547 | }; | ||
| 548 | |||
| 541 | /// Modifying the key is allowed only if it does not change the hash. | 549 | /// Modifying the key is allowed only if it does not change the hash. |
| 542 | /// Modifying the value is allowed. | 550 | /// Modifying the value is allowed. |
| 543 | /// Entry pointers become invalid whenever this ArrayHashMap is modified, | 551 | /// Entry pointers become invalid whenever this ArrayHashMap is modified, |
lib/std/array_list.zig+8| ... | @@ -618,6 +618,8 @@ pub fn ArrayListUnmanaged(comptime T: type) type { | ... | @@ -618,6 +618,8 @@ pub fn ArrayListUnmanaged(comptime T: type) type { |
| 618 | /// Functions that potentially allocate memory accept an `Allocator` parameter. | 618 | /// Functions that potentially allocate memory accept an `Allocator` parameter. |
| 619 | /// Initialize directly or with `initCapacity`, and deinitialize with `deinit` | 619 | /// Initialize directly or with `initCapacity`, and deinitialize with `deinit` |
| 620 | /// or use `toOwnedSlice`. | 620 | /// or use `toOwnedSlice`. |
| 621 | /// | ||
| 622 | /// Default initialization of this struct is deprecated; use `.empty` instead. | ||
| 621 | pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type { | 623 | pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type { |
| 622 | if (alignment) |a| { | 624 | if (alignment) |a| { |
| 623 | if (a == @alignOf(T)) { | 625 | if (a == @alignOf(T)) { |
| ... | @@ -638,6 +640,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -638,6 +640,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 638 | /// additional memory. | 640 | /// additional memory. |
| 639 | capacity: usize = 0, | 641 | capacity: usize = 0, |
| 640 | 642 | ||
| 643 | /// An ArrayList containing no elements. | ||
| 644 | pub const empty: Self = .{ | ||
| 645 | .items = &.{}, | ||
| 646 | .capacity = 0, | ||
| 647 | }; | ||
| 648 | |||
| 641 | pub const Slice = if (alignment) |a| ([]align(a) T) else []T; | 649 | pub const Slice = if (alignment) |a| ([]align(a) T) else []T; |
| 642 | 650 | ||
| 643 | pub fn SentinelSlice(comptime s: T) type { | 651 | pub fn SentinelSlice(comptime s: T) type { |
lib/std/hash_map.zig+9| ... | @@ -721,6 +721,8 @@ pub fn HashMap( | ... | @@ -721,6 +721,8 @@ pub fn HashMap( |
| 721 | /// the price of handling size with u32, which should be reasonable enough | 721 | /// the price of handling size with u32, which should be reasonable enough |
| 722 | /// for almost all uses. | 722 | /// for almost all uses. |
| 723 | /// Deletions are achieved with tombstones. | 723 | /// Deletions are achieved with tombstones. |
| 724 | /// | ||
| 725 | /// Default initialization of this struct is deprecated; use `.empty` instead. | ||
| 724 | pub fn HashMapUnmanaged( | 726 | pub fn HashMapUnmanaged( |
| 725 | comptime K: type, | 727 | comptime K: type, |
| 726 | comptime V: type, | 728 | comptime V: type, |
| ... | @@ -762,6 +764,13 @@ pub fn HashMapUnmanaged( | ... | @@ -762,6 +764,13 @@ pub fn HashMapUnmanaged( |
| 762 | /// Capacity of the first grow when bootstrapping the hashmap. | 764 | /// Capacity of the first grow when bootstrapping the hashmap. |
| 763 | const minimal_capacity = 8; | 765 | const minimal_capacity = 8; |
| 764 | 766 | ||
| 767 | /// A map containing no keys or values. | ||
| 768 | pub const empty: Self = .{ | ||
| 769 | .metadata = null, | ||
| 770 | .size = 0, | ||
| 771 | .available = 0, | ||
| 772 | }; | ||
| 773 | |||
| 765 | // This hashmap is specially designed for sizes that fit in a u32. | 774 | // This hashmap is specially designed for sizes that fit in a u32. |
| 766 | pub const Size = u32; | 775 | pub const Size = u32; |
| 767 | 776 |
lib/std/heap/general_purpose_allocator.zig+11| ... | @@ -157,6 +157,7 @@ pub const Config = struct { | ... | @@ -157,6 +157,7 @@ pub const Config = struct { |
| 157 | 157 | ||
| 158 | pub const Check = enum { ok, leak }; | 158 | pub const Check = enum { ok, leak }; |
| 159 | 159 | ||
| 160 | /// Default initialization of this struct is deprecated; use `.init` instead. | ||
| 160 | pub fn GeneralPurposeAllocator(comptime config: Config) type { | 161 | pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 161 | return struct { | 162 | return struct { |
| 162 | backing_allocator: Allocator = std.heap.page_allocator, | 163 | backing_allocator: Allocator = std.heap.page_allocator, |
| ... | @@ -174,6 +175,16 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -174,6 +175,16 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 174 | 175 | ||
| 175 | const Self = @This(); | 176 | const Self = @This(); |
| 176 | 177 | ||
| 178 | /// The initial state of a `GeneralPurposeAllocator`, containing no allocations and backed by the system page allocator. | ||
| 179 | pub const init: Self = .{ | ||
| 180 | .backing_allocator = std.heap.page_allocator, | ||
| 181 | .buckets = [1]Buckets{.{}} ** small_bucket_count, | ||
| 182 | .cur_buckets = [1]?*BucketHeader{null} ** small_bucket_count, | ||
| 183 | .large_allocations = .{}, | ||
| 184 | .empty_buckets = if (config.retain_metadata) .{} else {}, | ||
| 185 | .bucket_node_pool = .init(std.heap.page_allocator), | ||
| 186 | }; | ||
| 187 | |||
| 177 | const total_requested_bytes_init = if (config.enable_memory_limit) @as(usize, 0) else {}; | 188 | const total_requested_bytes_init = if (config.enable_memory_limit) @as(usize, 0) else {}; |
| 178 | const requested_memory_limit_init = if (config.enable_memory_limit) @as(usize, math.maxInt(usize)) else {}; | 189 | const requested_memory_limit_init = if (config.enable_memory_limit) @as(usize, math.maxInt(usize)) else {}; |
| 179 | 190 |
lib/std/zig/AstGen.zig+43-6| ... | @@ -1028,7 +1028,18 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE | ... | @@ -1028,7 +1028,18 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 1028 | const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; | 1028 | const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; |
| 1029 | return blockExpr(gz, scope, ri, node, statements, .normal); | 1029 | return blockExpr(gz, scope, ri, node, statements, .normal); |
| 1030 | }, | 1030 | }, |
| 1031 | .enum_literal => return simpleStrTok(gz, ri, main_tokens[node], node, .enum_literal), | 1031 | .enum_literal => if (try ri.rl.resultType(gz, node)) |res_ty| { |
| 1032 | const str_index = try astgen.identAsString(main_tokens[node]); | ||
| 1033 | const res = try gz.addPlNode(.decl_literal, node, Zir.Inst.Field{ | ||
| 1034 | .lhs = res_ty, | ||
| 1035 | .field_name_start = str_index, | ||
| 1036 | }); | ||
| 1037 | switch (ri.rl) { | ||
| 1038 | .discard, .none, .ref => unreachable, // no result type | ||
| 1039 | .ty, .coerced_ty => return res, // `decl_literal` does the coercion for us | ||
| 1040 | .ref_coerced_ty, .ptr, .inferred_ptr, .destructure => return rvalue(gz, ri, res, node), | ||
| 1041 | } | ||
| 1042 | } else return simpleStrTok(gz, ri, main_tokens[node], node, .enum_literal), | ||
| 1032 | .error_value => return simpleStrTok(gz, ri, node_datas[node].rhs, node, .error_value), | 1043 | .error_value => return simpleStrTok(gz, ri, node_datas[node].rhs, node, .error_value), |
| 1033 | // TODO restore this when implementing https://github.com/ziglang/zig/issues/6025 | 1044 | // TODO restore this when implementing https://github.com/ziglang/zig/issues/6025 |
| 1034 | // .anyframe_literal => return rvalue(gz, ri, .anyframe_type, node), | 1045 | // .anyframe_literal => return rvalue(gz, ri, .anyframe_type, node), |
| ... | @@ -2752,6 +2763,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2752,6 +2763,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2752 | .err_union_code_ptr, | 2763 | .err_union_code_ptr, |
| 2753 | .ptr_type, | 2764 | .ptr_type, |
| 2754 | .enum_literal, | 2765 | .enum_literal, |
| 2766 | .decl_literal, | ||
| 2767 | .decl_literal_no_coerce, | ||
| 2755 | .merge_error_sets, | 2768 | .merge_error_sets, |
| 2756 | .error_union_type, | 2769 | .error_union_type, |
| 2757 | .bit_not, | 2770 | .bit_not, |
| ... | @@ -2914,6 +2927,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2914,6 +2927,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2914 | .validate_array_init_result_ty, | 2927 | .validate_array_init_result_ty, |
| 2915 | .validate_ptr_array_init, | 2928 | .validate_ptr_array_init, |
| 2916 | .validate_ref_ty, | 2929 | .validate_ref_ty, |
| 2930 | .try_operand_ty, | ||
| 2931 | .try_ref_operand_ty, | ||
| 2917 | => break :b true, | 2932 | => break :b true, |
| 2918 | 2933 | ||
| 2919 | .@"defer" => unreachable, | 2934 | .@"defer" => unreachable, |
| ... | @@ -5887,13 +5902,21 @@ fn tryExpr( | ... | @@ -5887,13 +5902,21 @@ fn tryExpr( |
| 5887 | } | 5902 | } |
| 5888 | const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; | 5903 | const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; |
| 5889 | 5904 | ||
| 5890 | const operand_ri: ResultInfo = switch (ri.rl) { | 5905 | const operand_rl: ResultInfo.Loc, const block_tag: Zir.Inst.Tag = switch (ri.rl) { |
| 5891 | .ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = .error_handling_expr }, | 5906 | .ref => .{ .ref, .try_ptr }, |
| 5892 | else => .{ .rl = .none, .ctx = .error_handling_expr }, | 5907 | .ref_coerced_ty => |payload_ptr_ty| .{ |
| 5908 | .{ .ref_coerced_ty = try parent_gz.addUnNode(.try_ref_operand_ty, payload_ptr_ty, node) }, | ||
| 5909 | .try_ptr, | ||
| 5910 | }, | ||
| 5911 | else => if (try ri.rl.resultType(parent_gz, node)) |payload_ty| .{ | ||
| 5912 | // `coerced_ty` is OK due to the `rvalue` call below | ||
| 5913 | .{ .coerced_ty = try parent_gz.addUnNode(.try_operand_ty, payload_ty, node) }, | ||
| 5914 | .@"try", | ||
| 5915 | } else .{ .none, .@"try" }, | ||
| 5893 | }; | 5916 | }; |
| 5917 | const operand_ri: ResultInfo = .{ .rl = operand_rl, .ctx = .error_handling_expr }; | ||
| 5894 | // This could be a pointer or value depending on the `ri` parameter. | 5918 | // This could be a pointer or value depending on the `ri` parameter. |
| 5895 | const operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, node); | 5919 | const operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, node); |
| 5896 | const block_tag: Zir.Inst.Tag = if (operand_ri.rl == .ref) .try_ptr else .@"try"; | ||
| 5897 | const try_inst = try parent_gz.makeBlockInst(block_tag, node); | 5920 | const try_inst = try parent_gz.makeBlockInst(block_tag, node); |
| 5898 | try parent_gz.instructions.append(astgen.gpa, try_inst); | 5921 | try parent_gz.instructions.append(astgen.gpa, try_inst); |
| 5899 | 5922 | ||
| ... | @@ -9905,7 +9928,7 @@ fn callExpr( | ... | @@ -9905,7 +9928,7 @@ fn callExpr( |
| 9905 | ) InnerError!Zir.Inst.Ref { | 9928 | ) InnerError!Zir.Inst.Ref { |
| 9906 | const astgen = gz.astgen; | 9929 | const astgen = gz.astgen; |
| 9907 | 9930 | ||
| 9908 | const callee = try calleeExpr(gz, scope, call.ast.fn_expr); | 9931 | const callee = try calleeExpr(gz, scope, ri.rl, call.ast.fn_expr); |
| 9909 | const modifier: std.builtin.CallModifier = blk: { | 9932 | const modifier: std.builtin.CallModifier = blk: { |
| 9910 | if (gz.is_comptime) { | 9933 | if (gz.is_comptime) { |
| 9911 | break :blk .compile_time; | 9934 | break :blk .compile_time; |
| ... | @@ -10033,6 +10056,7 @@ const Callee = union(enum) { | ... | @@ -10033,6 +10056,7 @@ const Callee = union(enum) { |
| 10033 | fn calleeExpr( | 10056 | fn calleeExpr( |
| 10034 | gz: *GenZir, | 10057 | gz: *GenZir, |
| 10035 | scope: *Scope, | 10058 | scope: *Scope, |
| 10059 | call_rl: ResultInfo.Loc, | ||
| 10036 | node: Ast.Node.Index, | 10060 | node: Ast.Node.Index, |
| 10037 | ) InnerError!Callee { | 10061 | ) InnerError!Callee { |
| 10038 | const astgen = gz.astgen; | 10062 | const astgen = gz.astgen; |
| ... | @@ -10059,6 +10083,19 @@ fn calleeExpr( | ... | @@ -10059,6 +10083,19 @@ fn calleeExpr( |
| 10059 | .field_name_start = str_index, | 10083 | .field_name_start = str_index, |
| 10060 | } }; | 10084 | } }; |
| 10061 | }, | 10085 | }, |
| 10086 | .enum_literal => if (try call_rl.resultType(gz, node)) |res_ty| { | ||
| 10087 | // Decl literal call syntax, e.g. | ||
| 10088 | // `const foo: T = .init();` | ||
| 10089 | // Look up `init` in `T`, but don't try and coerce it. | ||
| 10090 | const str_index = try astgen.identAsString(tree.nodes.items(.main_token)[node]); | ||
| 10091 | const callee = try gz.addPlNode(.decl_literal_no_coerce, node, Zir.Inst.Field{ | ||
| 10092 | .lhs = res_ty, | ||
| 10093 | .field_name_start = str_index, | ||
| 10094 | }); | ||
| 10095 | return .{ .direct = callee }; | ||
| 10096 | } else { | ||
| 10097 | return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) }; | ||
| 10098 | }, | ||
| 10062 | else => return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) }, | 10099 | else => return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) }, |
| 10063 | } | 10100 | } |
| 10064 | } | 10101 | } |
lib/std/zig/Zir.zig+32| ... | @@ -651,6 +651,14 @@ pub const Inst = struct { | ... | @@ -651,6 +651,14 @@ pub const Inst = struct { |
| 651 | err_union_code_ptr, | 651 | err_union_code_ptr, |
| 652 | /// An enum literal. Uses the `str_tok` union field. | 652 | /// An enum literal. Uses the `str_tok` union field. |
| 653 | enum_literal, | 653 | enum_literal, |
| 654 | /// A decl literal. This is similar to `field`, but unwraps error unions and optionals, | ||
| 655 | /// and coerces the result to the given type. | ||
| 656 | /// Uses the `pl_node` union field. Payload is `Field`. | ||
| 657 | decl_literal, | ||
| 658 | /// The same as `decl_literal`, but the coercion is omitted. This is used for decl literal | ||
| 659 | /// function call syntax, i.e. `.foo()`. | ||
| 660 | /// Uses the `pl_node` union field. Payload is `Field`. | ||
| 661 | decl_literal_no_coerce, | ||
| 654 | /// A switch expression. Uses the `pl_node` union field. | 662 | /// A switch expression. Uses the `pl_node` union field. |
| 655 | /// AST node is the switch, payload is `SwitchBlock`. | 663 | /// AST node is the switch, payload is `SwitchBlock`. |
| 656 | switch_block, | 664 | switch_block, |
| ... | @@ -684,6 +692,14 @@ pub const Inst = struct { | ... | @@ -684,6 +692,14 @@ pub const Inst = struct { |
| 684 | /// operator. Emit a compile error if not. | 692 | /// operator. Emit a compile error if not. |
| 685 | /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type. | 693 | /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type. |
| 686 | validate_ref_ty, | 694 | validate_ref_ty, |
| 695 | /// Given a type `T`, construct the type `E!T`, where `E` is this function's error set, to be used | ||
| 696 | /// as the result type of a `try` operand. Generic poison is propagated. | ||
| 697 | /// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `T`. | ||
| 698 | try_operand_ty, | ||
| 699 | /// Given a type `*T`, construct the type `*E!T`, where `E` is this function's error set, to be used | ||
| 700 | /// as the result type of a `try` operand whose address is taken with `&`. Generic poison is propagated. | ||
| 701 | /// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `*T`. | ||
| 702 | try_ref_operand_ty, | ||
| 687 | 703 | ||
| 688 | // The following tags all relate to struct initialization expressions. | 704 | // The following tags all relate to struct initialization expressions. |
| 689 | 705 | ||
| ... | @@ -1136,6 +1152,8 @@ pub const Inst = struct { | ... | @@ -1136,6 +1152,8 @@ pub const Inst = struct { |
| 1136 | .err_union_code_ptr, | 1152 | .err_union_code_ptr, |
| 1137 | .ptr_type, | 1153 | .ptr_type, |
| 1138 | .enum_literal, | 1154 | .enum_literal, |
| 1155 | .decl_literal, | ||
| 1156 | .decl_literal_no_coerce, | ||
| 1139 | .merge_error_sets, | 1157 | .merge_error_sets, |
| 1140 | .error_union_type, | 1158 | .error_union_type, |
| 1141 | .bit_not, | 1159 | .bit_not, |
| ... | @@ -1254,6 +1272,8 @@ pub const Inst = struct { | ... | @@ -1254,6 +1272,8 @@ pub const Inst = struct { |
| 1254 | .array_init_elem_type, | 1272 | .array_init_elem_type, |
| 1255 | .array_init_elem_ptr, | 1273 | .array_init_elem_ptr, |
| 1256 | .validate_ref_ty, | 1274 | .validate_ref_ty, |
| 1275 | .try_operand_ty, | ||
| 1276 | .try_ref_operand_ty, | ||
| 1257 | .restore_err_ret_index_unconditional, | 1277 | .restore_err_ret_index_unconditional, |
| 1258 | .restore_err_ret_index_fn_entry, | 1278 | .restore_err_ret_index_fn_entry, |
| 1259 | => false, | 1279 | => false, |
| ... | @@ -1324,6 +1344,8 @@ pub const Inst = struct { | ... | @@ -1324,6 +1344,8 @@ pub const Inst = struct { |
| 1324 | .validate_array_init_result_ty, | 1344 | .validate_array_init_result_ty, |
| 1325 | .validate_ptr_array_init, | 1345 | .validate_ptr_array_init, |
| 1326 | .validate_ref_ty, | 1346 | .validate_ref_ty, |
| 1347 | .try_operand_ty, | ||
| 1348 | .try_ref_operand_ty, | ||
| 1327 | => true, | 1349 | => true, |
| 1328 | 1350 | ||
| 1329 | .param, | 1351 | .param, |
| ... | @@ -1430,6 +1452,8 @@ pub const Inst = struct { | ... | @@ -1430,6 +1452,8 @@ pub const Inst = struct { |
| 1430 | .err_union_code_ptr, | 1452 | .err_union_code_ptr, |
| 1431 | .ptr_type, | 1453 | .ptr_type, |
| 1432 | .enum_literal, | 1454 | .enum_literal, |
| 1455 | .decl_literal, | ||
| 1456 | .decl_literal_no_coerce, | ||
| 1433 | .merge_error_sets, | 1457 | .merge_error_sets, |
| 1434 | .error_union_type, | 1458 | .error_union_type, |
| 1435 | .bit_not, | 1459 | .bit_not, |
| ... | @@ -1685,6 +1709,8 @@ pub const Inst = struct { | ... | @@ -1685,6 +1709,8 @@ pub const Inst = struct { |
| 1685 | .err_union_code = .un_node, | 1709 | .err_union_code = .un_node, |
| 1686 | .err_union_code_ptr = .un_node, | 1710 | .err_union_code_ptr = .un_node, |
| 1687 | .enum_literal = .str_tok, | 1711 | .enum_literal = .str_tok, |
| 1712 | .decl_literal = .pl_node, | ||
| 1713 | .decl_literal_no_coerce = .pl_node, | ||
| 1688 | .switch_block = .pl_node, | 1714 | .switch_block = .pl_node, |
| 1689 | .switch_block_ref = .pl_node, | 1715 | .switch_block_ref = .pl_node, |
| 1690 | .switch_block_err_union = .pl_node, | 1716 | .switch_block_err_union = .pl_node, |
| ... | @@ -1698,6 +1724,8 @@ pub const Inst = struct { | ... | @@ -1698,6 +1724,8 @@ pub const Inst = struct { |
| 1698 | .opt_eu_base_ptr_init = .un_node, | 1724 | .opt_eu_base_ptr_init = .un_node, |
| 1699 | .coerce_ptr_elem_ty = .pl_node, | 1725 | .coerce_ptr_elem_ty = .pl_node, |
| 1700 | .validate_ref_ty = .un_tok, | 1726 | .validate_ref_ty = .un_tok, |
| 1727 | .try_operand_ty = .un_node, | ||
| 1728 | .try_ref_operand_ty = .un_node, | ||
| 1701 | 1729 | ||
| 1702 | .int_from_ptr = .un_node, | 1730 | .int_from_ptr = .un_node, |
| 1703 | .compile_error = .un_node, | 1731 | .compile_error = .un_node, |
| ... | @@ -3828,12 +3856,16 @@ fn findDeclsInner( | ... | @@ -3828,12 +3856,16 @@ fn findDeclsInner( |
| 3828 | .err_union_code, | 3856 | .err_union_code, |
| 3829 | .err_union_code_ptr, | 3857 | .err_union_code_ptr, |
| 3830 | .enum_literal, | 3858 | .enum_literal, |
| 3859 | .decl_literal, | ||
| 3860 | .decl_literal_no_coerce, | ||
| 3831 | .validate_deref, | 3861 | .validate_deref, |
| 3832 | .validate_destructure, | 3862 | .validate_destructure, |
| 3833 | .field_type_ref, | 3863 | .field_type_ref, |
| 3834 | .opt_eu_base_ptr_init, | 3864 | .opt_eu_base_ptr_init, |
| 3835 | .coerce_ptr_elem_ty, | 3865 | .coerce_ptr_elem_ty, |
| 3836 | .validate_ref_ty, | 3866 | .validate_ref_ty, |
| 3867 | .try_operand_ty, | ||
| 3868 | .try_ref_operand_ty, | ||
| 3837 | .struct_init_empty, | 3869 | .struct_init_empty, |
| 3838 | .struct_init_empty_result, | 3870 | .struct_init_empty_result, |
| 3839 | .struct_init_empty_ref_result, | 3871 | .struct_init_empty_ref_result, |
src/Sema.zig+121| ... | @@ -1072,6 +1072,8 @@ fn analyzeBodyInner( | ... | @@ -1072,6 +1072,8 @@ fn analyzeBodyInner( |
| 1072 | .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst), | 1072 | .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst), |
| 1073 | .vector_elem_type => try sema.zirVectorElemType(block, inst), | 1073 | .vector_elem_type => try sema.zirVectorElemType(block, inst), |
| 1074 | .enum_literal => try sema.zirEnumLiteral(block, inst), | 1074 | .enum_literal => try sema.zirEnumLiteral(block, inst), |
| 1075 | .decl_literal => try sema.zirDeclLiteral(block, inst, true), | ||
| 1076 | .decl_literal_no_coerce => try sema.zirDeclLiteral(block, inst, false), | ||
| 1075 | .int_from_enum => try sema.zirIntFromEnum(block, inst), | 1077 | .int_from_enum => try sema.zirIntFromEnum(block, inst), |
| 1076 | .enum_from_int => try sema.zirEnumFromInt(block, inst), | 1078 | .enum_from_int => try sema.zirEnumFromInt(block, inst), |
| 1077 | .err_union_code => try sema.zirErrUnionCode(block, inst), | 1079 | .err_union_code => try sema.zirErrUnionCode(block, inst), |
| ... | @@ -1177,6 +1179,8 @@ fn analyzeBodyInner( | ... | @@ -1177,6 +1179,8 @@ fn analyzeBodyInner( |
| 1177 | .validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst), | 1179 | .validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst), |
| 1178 | .opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst), | 1180 | .opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst), |
| 1179 | .coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(block, inst), | 1181 | .coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(block, inst), |
| 1182 | .try_operand_ty => try sema.zirTryOperandTy(block, inst, false), | ||
| 1183 | .try_ref_operand_ty => try sema.zirTryOperandTy(block, inst, true), | ||
| 1180 | 1184 | ||
| 1181 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), | 1185 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), |
| 1182 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), | 1186 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), |
| ... | @@ -2024,6 +2028,22 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi | ... | @@ -2024,6 +2028,22 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi |
| 2024 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; | 2028 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 2025 | cur = un_node.operand; | 2029 | cur = un_node.operand; |
| 2026 | }, | 2030 | }, |
| 2031 | .try_operand_ty => { | ||
| 2032 | // Either the input type was itself poison, or it was a slice, which we cannot translate | ||
| 2033 | // to an overall result type. | ||
| 2034 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; | ||
| 2035 | const operand_ref = sema.resolveInst(un_node.operand) catch |err| switch (err) { | ||
| 2036 | error.GenericPoison => unreachable, // this is a type, not a value | ||
| 2037 | }; | ||
| 2038 | if (operand_ref == .generic_poison_type) { | ||
| 2039 | // The input was poison -- keep looking. | ||
| 2040 | cur = un_node.operand; | ||
| 2041 | continue; | ||
| 2042 | } | ||
| 2043 | // We got a poison because the result type was a slice. This is a tricky case -- let's just | ||
| 2044 | // not bother explaining it to the user for now... | ||
| 2045 | return .unknown; | ||
| 2046 | }, | ||
| 2027 | .struct_init_field_type => { | 2047 | .struct_init_field_type => { |
| 2028 | const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; | 2048 | const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 2029 | const extra = sema.code.extraData(Zir.Inst.FieldType, pl_node.payload_index).data; | 2049 | const extra = sema.code.extraData(Zir.Inst.FieldType, pl_node.payload_index).data; |
| ... | @@ -4423,6 +4443,59 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -4423,6 +4443,59 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 4423 | } | 4443 | } |
| 4424 | } | 4444 | } |
| 4425 | 4445 | ||
| 4446 | fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref { | ||
| 4447 | const pt = sema.pt; | ||
| 4448 | const zcu = pt.zcu; | ||
| 4449 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; | ||
| 4450 | const src = block.nodeOffset(un_node.src_node); | ||
| 4451 | |||
| 4452 | const operand_ty = sema.resolveType(block, src, un_node.operand) catch |err| switch (err) { | ||
| 4453 | error.GenericPoison => return .generic_poison_type, | ||
| 4454 | else => |e| return e, | ||
| 4455 | }; | ||
| 4456 | |||
| 4457 | const payload_ty = if (is_ref) ty: { | ||
| 4458 | if (!operand_ty.isSinglePointer(zcu)) { | ||
| 4459 | return .generic_poison_type; // we can't get a meaningful result type here, since it will be `*E![n]T`, and we don't know `n`. | ||
| 4460 | } | ||
| 4461 | break :ty operand_ty.childType(zcu); | ||
| 4462 | } else operand_ty; | ||
| 4463 | |||
| 4464 | const err_set_ty = err_set: { | ||
| 4465 | // There are awkward cases, like `?E`. Our strategy is to repeatedly unwrap optionals | ||
| 4466 | // until we hit an error union or set. | ||
| 4467 | var cur_ty = sema.fn_ret_ty; | ||
| 4468 | while (true) { | ||
| 4469 | switch (cur_ty.zigTypeTag(zcu)) { | ||
| 4470 | .error_set => break :err_set cur_ty, | ||
| 4471 | .error_union => break :err_set cur_ty.errorUnionSet(zcu), | ||
| 4472 | .optional => cur_ty = cur_ty.optionalChild(zcu), | ||
| 4473 | else => return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 4474 | const msg = try sema.errMsg(src, "expected '{}', found error set", .{sema.fn_ret_ty.fmt(pt)}); | ||
| 4475 | errdefer msg.destroy(sema.gpa); | ||
| 4476 | const ret_ty_src: LazySrcLoc = .{ | ||
| 4477 | .base_node_inst = sema.getOwnerFuncDeclInst(), | ||
| 4478 | .offset = .{ .node_offset_fn_type_ret_ty = 0 }, | ||
| 4479 | }; | ||
| 4480 | try sema.errNote(ret_ty_src, msg, "function cannot return an error", .{}); | ||
| 4481 | break :msg msg; | ||
| 4482 | }), | ||
| 4483 | } | ||
| 4484 | } | ||
| 4485 | }; | ||
| 4486 | |||
| 4487 | const eu_ty = try pt.errorUnionType(err_set_ty, payload_ty); | ||
| 4488 | |||
| 4489 | if (is_ref) { | ||
| 4490 | var ptr_info = operand_ty.ptrInfo(zcu); | ||
| 4491 | ptr_info.child = eu_ty.toIntern(); | ||
| 4492 | const eu_ptr_ty = try pt.ptrTypeSema(ptr_info); | ||
| 4493 | return Air.internedToRef(eu_ptr_ty.toIntern()); | ||
| 4494 | } else { | ||
| 4495 | return Air.internedToRef(eu_ty.toIntern()); | ||
| 4496 | } | ||
| 4497 | } | ||
| 4498 | |||
| 4426 | fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 4499 | fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 4427 | const pt = sema.pt; | 4500 | const pt = sema.pt; |
| 4428 | const zcu = pt.zcu; | 4501 | const zcu = pt.zcu; |
| ... | @@ -8803,6 +8876,54 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -8803,6 +8876,54 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8803 | }))); | 8876 | }))); |
| 8804 | } | 8877 | } |
| 8805 | 8878 | ||
| 8879 | fn zirDeclLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index, do_coerce: bool) CompileError!Air.Inst.Ref { | ||
| 8880 | const tracy = trace(@src()); | ||
| 8881 | defer tracy.end(); | ||
| 8882 | |||
| 8883 | const pt = sema.pt; | ||
| 8884 | const zcu = pt.zcu; | ||
| 8885 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; | ||
| 8886 | const src = block.nodeOffset(inst_data.src_node); | ||
| 8887 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; | ||
| 8888 | const name = try zcu.intern_pool.getOrPutString( | ||
| 8889 | sema.gpa, | ||
| 8890 | pt.tid, | ||
| 8891 | sema.code.nullTerminatedString(extra.field_name_start), | ||
| 8892 | .no_embedded_nulls, | ||
| 8893 | ); | ||
| 8894 | const orig_ty = sema.resolveType(block, src, extra.lhs) catch |err| switch (err) { | ||
| 8895 | error.GenericPoison => { | ||
| 8896 | // Treat this as a normal enum literal. | ||
| 8897 | return Air.internedToRef(try pt.intern(.{ .enum_literal = name })); | ||
| 8898 | }, | ||
| 8899 | else => |e| return e, | ||
| 8900 | }; | ||
| 8901 | |||
| 8902 | var ty = orig_ty; | ||
| 8903 | while (true) switch (ty.zigTypeTag(zcu)) { | ||
| 8904 | .error_union => ty = ty.errorUnionPayload(zcu), | ||
| 8905 | .optional => ty = ty.optionalChild(zcu), | ||
| 8906 | .enum_literal, .error_set => { | ||
| 8907 | // Treat this as a normal enum literal. | ||
| 8908 | return Air.internedToRef(try pt.intern(.{ .enum_literal = name })); | ||
| 8909 | }, | ||
| 8910 | else => break, | ||
| 8911 | }; | ||
| 8912 | |||
| 8913 | const result = try sema.fieldVal(block, src, Air.internedToRef(ty.toIntern()), name, src); | ||
| 8914 | |||
| 8915 | // Decl literals cannot lookup runtime `var`s. | ||
| 8916 | if (!try sema.isComptimeKnown(result)) { | ||
| 8917 | return sema.fail(block, src, "decl literal must be comptime-known", .{}); | ||
| 8918 | } | ||
| 8919 | |||
| 8920 | if (do_coerce) { | ||
| 8921 | return sema.coerce(block, orig_ty, result, src); | ||
| 8922 | } else { | ||
| 8923 | return result; | ||
| 8924 | } | ||
| 8925 | } | ||
| 8926 | |||
| 8806 | fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 8927 | fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8807 | const pt = sema.pt; | 8928 | const pt = sema.pt; |
| 8808 | const zcu = pt.zcu; | 8929 | const zcu = pt.zcu; |
src/arch/riscv64/CodeGen.zig+40-1| ... | @@ -3471,9 +3471,48 @@ fn airUnwrapErrPayloadPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3471,9 +3471,48 @@ fn airUnwrapErrPayloadPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 3471 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3471 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3472 | } | 3472 | } |
| 3473 | 3473 | ||
| 3474 | // *(E!T) => *T | ||
| 3474 | fn airErrUnionPayloadPtrSet(func: *Func, inst: Air.Inst.Index) !void { | 3475 | fn airErrUnionPayloadPtrSet(func: *Func, inst: Air.Inst.Index) !void { |
| 3475 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3476 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3476 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement .errunion_payload_ptr_set for {}", .{func.target.cpu.arch}); | 3477 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 3478 | const zcu = func.pt.zcu; | ||
| 3479 | const src_ty = func.typeOf(ty_op.operand); | ||
| 3480 | const src_mcv = try func.resolveInst(ty_op.operand); | ||
| 3481 | |||
| 3482 | // `src_reg` contains the pointer to the error union | ||
| 3483 | const src_reg = switch (src_mcv) { | ||
| 3484 | .register => |reg| reg, | ||
| 3485 | else => try func.copyToTmpRegister(src_ty, src_mcv), | ||
| 3486 | }; | ||
| 3487 | const src_lock = func.register_manager.lockRegAssumeUnused(src_reg); | ||
| 3488 | defer func.register_manager.unlockReg(src_lock); | ||
| 3489 | |||
| 3490 | // we set the place of where the error would have been to 0 | ||
| 3491 | const eu_ty = src_ty.childType(zcu); | ||
| 3492 | const pl_ty = eu_ty.errorUnionPayload(zcu); | ||
| 3493 | const err_ty = eu_ty.errorUnionSet(zcu); | ||
| 3494 | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); | ||
| 3495 | try func.genSetMem(.{ .reg = src_reg }, err_off, err_ty, .{ .immediate = 0 }); | ||
| 3496 | |||
| 3497 | const dst_reg, const dst_lock = if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | ||
| 3498 | .{ src_reg, null } | ||
| 3499 | else | ||
| 3500 | try func.allocReg(.int); | ||
| 3501 | defer if (dst_lock) |lock| func.register_manager.unlockReg(lock); | ||
| 3502 | |||
| 3503 | // move the pointer to be at the payload | ||
| 3504 | const pl_off = errUnionPayloadOffset(pl_ty, zcu); | ||
| 3505 | try func.genBinOp( | ||
| 3506 | .add, | ||
| 3507 | .{ .register = src_reg }, | ||
| 3508 | Type.u64, | ||
| 3509 | .{ .immediate = pl_off }, | ||
| 3510 | Type.u64, | ||
| 3511 | dst_reg, | ||
| 3512 | ); | ||
| 3513 | |||
| 3514 | break :result .{ .register = dst_reg }; | ||
| 3515 | }; | ||
| 3477 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3516 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3478 | } | 3517 | } |
| 3479 | 3518 |
src/print_zir.zig+4| ... | @@ -277,6 +277,8 @@ const Writer = struct { | ... | @@ -277,6 +277,8 @@ const Writer = struct { |
| 277 | .opt_eu_base_ptr_init, | 277 | .opt_eu_base_ptr_init, |
| 278 | .restore_err_ret_index_unconditional, | 278 | .restore_err_ret_index_unconditional, |
| 279 | .restore_err_ret_index_fn_entry, | 279 | .restore_err_ret_index_fn_entry, |
| 280 | .try_operand_ty, | ||
| 281 | .try_ref_operand_ty, | ||
| 280 | => try self.writeUnNode(stream, inst), | 282 | => try self.writeUnNode(stream, inst), |
| 281 | 283 | ||
| 282 | .ref, | 284 | .ref, |
| ... | @@ -460,6 +462,8 @@ const Writer = struct { | ... | @@ -460,6 +462,8 @@ const Writer = struct { |
| 460 | 462 | ||
| 461 | .field_val, | 463 | .field_val, |
| 462 | .field_ptr, | 464 | .field_ptr, |
| 465 | .decl_literal, | ||
| 466 | .decl_literal_no_coerce, | ||
| 463 | => try self.writePlNodeField(stream, inst), | 467 | => try self.writePlNodeField(stream, inst), |
| 464 | 468 | ||
| 465 | .field_ptr_named, | 469 | .field_ptr_named, |
test/behavior.zig+1| ... | @@ -21,6 +21,7 @@ test { | ... | @@ -21,6 +21,7 @@ test { |
| 21 | _ = @import("behavior/cast_int.zig"); | 21 | _ = @import("behavior/cast_int.zig"); |
| 22 | _ = @import("behavior/comptime_memory.zig"); | 22 | _ = @import("behavior/comptime_memory.zig"); |
| 23 | _ = @import("behavior/const_slice_child.zig"); | 23 | _ = @import("behavior/const_slice_child.zig"); |
| 24 | _ = @import("behavior/decl_literals.zig"); | ||
| 24 | _ = @import("behavior/decltest.zig"); | 25 | _ = @import("behavior/decltest.zig"); |
| 25 | _ = @import("behavior/duplicated_test_names.zig"); | 26 | _ = @import("behavior/duplicated_test_names.zig"); |
| 26 | _ = @import("behavior/defer.zig"); | 27 | _ = @import("behavior/defer.zig"); |
test/behavior/cast_int.zig-4| ... | @@ -164,8 +164,6 @@ const Piece = packed struct { | ... | @@ -164,8 +164,6 @@ const Piece = packed struct { |
| 164 | }; | 164 | }; |
| 165 | 165 | ||
| 166 | test "load non byte-sized optional value" { | 166 | test "load non byte-sized optional value" { |
| 167 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 168 | |||
| 169 | // Originally reported at https://github.com/ziglang/zig/issues/14200 | 167 | // Originally reported at https://github.com/ziglang/zig/issues/14200 |
| 170 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 168 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 171 | 169 | ||
| ... | @@ -181,8 +179,6 @@ test "load non byte-sized optional value" { | ... | @@ -181,8 +179,6 @@ test "load non byte-sized optional value" { |
| 181 | } | 179 | } |
| 182 | 180 | ||
| 183 | test "load non byte-sized value in struct" { | 181 | test "load non byte-sized value in struct" { |
| 184 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 185 | |||
| 186 | if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO | 182 | if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO |
| 187 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 183 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 188 | 184 |
test/behavior/decl_literals.zig created+38| ... | @@ -0,0 +1,38 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | test "decl literal" { | ||
| 6 | const S = struct { | ||
| 7 | x: u32, | ||
| 8 | const foo: @This() = .{ .x = 123 }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | const val: S = .foo; | ||
| 12 | try expect(val.x == 123); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "call decl literal" { | ||
| 16 | const S = struct { | ||
| 17 | x: u32, | ||
| 18 | fn init() @This() { | ||
| 19 | return .{ .x = 123 }; | ||
| 20 | } | ||
| 21 | }; | ||
| 22 | |||
| 23 | const val: S = .init(); | ||
| 24 | try expect(val.x == 123); | ||
| 25 | } | ||
| 26 | |||
| 27 | test "call decl literal with error union" { | ||
| 28 | const S = struct { | ||
| 29 | x: u32, | ||
| 30 | fn init(err: bool) !@This() { | ||
| 31 | if (err) return error.Bad; | ||
| 32 | return .{ .x = 123 }; | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | const val: S = try .init(false); | ||
| 37 | try expect(val.x == 123); | ||
| 38 | } | ||
test/behavior/struct.zig-1| ... | @@ -1214,7 +1214,6 @@ test "anon init through error union" { | ... | @@ -1214,7 +1214,6 @@ test "anon init through error union" { |
| 1214 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1214 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1216 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 1216 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 1217 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1218 | 1217 | ||
| 1219 | const S = struct { | 1218 | const S = struct { |
| 1220 | a: u32, | 1219 | a: u32, |
test/behavior/try.zig+19| ... | @@ -67,3 +67,22 @@ test "`try`ing an if/else expression" { | ... | @@ -67,3 +67,22 @@ test "`try`ing an if/else expression" { |
| 67 | 67 | ||
| 68 | try std.testing.expectError(error.Test, S.getError2()); | 68 | try std.testing.expectError(error.Test, S.getError2()); |
| 69 | } | 69 | } |
| 70 | |||
| 71 | test "try forwards result location" { | ||
| 72 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO | ||
| 73 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 74 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 75 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 76 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 77 | |||
| 78 | const S = struct { | ||
| 79 | fn foo(err: bool) error{Foo}!u32 { | ||
| 80 | const result: error{ Foo, Bar }!u32 = if (err) error.Foo else 123; | ||
| 81 | const res_int: u32 = try @errorCast(result); | ||
| 82 | return res_int; | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | |||
| 86 | try expect((S.foo(false) catch return error.TestUnexpectedResult) == 123); | ||
| 87 | try std.testing.expectError(error.Foo, S.foo(true)); | ||
| 88 | } |
test/behavior/while.zig-1| ... | @@ -347,7 +347,6 @@ test "try terminating an infinite loop" { | ... | @@ -347,7 +347,6 @@ test "try terminating an infinite loop" { |
| 347 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 347 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 348 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 348 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 349 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 349 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 350 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 351 | 350 | ||
| 352 | // Test coverage for https://github.com/ziglang/zig/issues/13546 | 351 | // Test coverage for https://github.com/ziglang/zig/issues/13546 |
| 353 | const Foo = struct { | 352 | const Foo = struct { |
test/cases/compile_errors/cast_enum_literal_to_enum_but_it_doesnt_match.zig+1-1| ... | @@ -11,5 +11,5 @@ export fn entry() void { | ... | @@ -11,5 +11,5 @@ export fn entry() void { |
| 11 | // backend=stage2 | 11 | // backend=stage2 |
| 12 | // target=native | 12 | // target=native |
| 13 | // | 13 | // |
| 14 | // :6:21: error: no field named 'c' in enum 'tmp.Foo' | 14 | // :6:21: error: enum 'tmp.Foo' has no member named 'c' |
| 15 | // :1:13: note: enum declared here | 15 | // :1:13: note: enum declared here |
test/cases/compile_errors/comptime_arg_to_generic_fn_callee_error.zig+1-1| ... | @@ -17,5 +17,5 @@ pub export fn entry() void { | ... | @@ -17,5 +17,5 @@ pub export fn entry() void { |
| 17 | // backend=stage2 | 17 | // backend=stage2 |
| 18 | // target=native | 18 | // target=native |
| 19 | // | 19 | // |
| 20 | // :7:28: error: no field named 'c' in enum 'meta.FieldEnum(tmp.MyStruct)' | 20 | // :7:28: error: enum 'meta.FieldEnum(tmp.MyStruct)' has no member named 'c' |
| 21 | // :?:?: note: enum declared here | 21 | // :?:?: note: enum declared here |