authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-09-02 00:44:11+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-09-02 00:44:11+01:00
log6d2945f1fe387c55eff003ada6e72146daff10f2
tree5265ef17dbd7e3c95ed22f578da42307222dddfc
parent227fb4875f5084cdb3436c40c4a08809bd3e4f50
parent0b9fccf508dc85fa522947d1cf6ff84f78f2dcb4
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21264 from mlugg/decl-literals

compiler: implement decl literals

17 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` is511/// 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.
513pub fn ArrayHashMapUnmanaged(515pub 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 = .{},
540542
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.
621pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {623pub 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,
640642
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;
642650
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 enough721/// 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.
724pub fn HashMapUnmanaged(726pub 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;
764766
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;
767776
lib/std/heap/general_purpose_allocator.zig+11
...@@ -157,6 +157,7 @@ pub const Config = struct {...@@ -157,6 +157,7 @@ pub const Config = struct {
157157
158pub const Check = enum { ok, leak };158pub const Check = enum { ok, leak };
159159
160/// Default initialization of this struct is deprecated; use `.init` instead.
160pub fn GeneralPurposeAllocator(comptime config: Config) type {161pub 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 {
174175
175 const Self = @This();176 const Self = @This();
176177
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 {};
179190
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/60251044 // 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,
29182933
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 };
58895904
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);
58995922
...@@ -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;
99079930
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) {
10033fn calleeExpr(10056fn 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,
687703
688 // The following tags all relate to struct initialization expressions.704 // The following tags all relate to struct initialization expressions.
689705
...@@ -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,
13281350
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,
17011729
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),
11801184
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}
44254445
4446fn 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
4426fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {4499fn 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}
88058878
8879fn 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
8806fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {8927fn 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}
34733473
3474// *(E!T) => *T
3474fn airErrUnionPayloadPtrSet(func: *Func, inst: Air.Inst.Index) !void {3475fn 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}
34793518
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),
281283
282 .ref,284 .ref,
...@@ -460,6 +462,8 @@ const Writer = struct {...@@ -460,6 +462,8 @@ const Writer = struct {
460462
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),
464468
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};
165165
166test "load non byte-sized optional value" {166test "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/14200167 // 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;
171169
...@@ -181,8 +179,6 @@ test "load non byte-sized optional value" {...@@ -181,8 +179,6 @@ test "load non byte-sized optional value" {
181}179}
182180
183test "load non byte-sized value in struct" {181test "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 TODO182 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;
188184
test/behavior/decl_literals.zig created+38
...@@ -0,0 +1,38 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4
5test "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
15test "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
27test "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; // TODO1214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1215 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;
12181217
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" {
6767
68 try std.testing.expectError(error.Test, S.getError2());68 try std.testing.expectError(error.Test, S.getError2());
69}69}
70
71test "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; // TODO347 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO348 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;
351350
352 // Test coverage for https://github.com/ziglang/zig/issues/13546351 // 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=stage211// backend=stage2
12// target=native12// 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 here15// :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=stage217// backend=stage2
18// target=native18// 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 here21// :?:?: note: enum declared here