authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-08 02:04:53-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-07-08 02:04:53-04:00
log62d27fcfb687e3ab1f10c72513e19529d8ffceed
tree2885da99ca325959e40f417346aca63ddef4fb31
parent7935e83b1d5d29cca058597ebdac6dfd012a790a
parentc2e66d9bab396a69514ec7c3c41fb0404e542f21
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9325 from ziglang/stage2-inferred-error-sets

Stage2 inferred error sets and `@panic`

17 files changed, 1074 insertions(+), 384 deletions(-)

lib/std/builtin.zig+7
...@@ -677,6 +677,13 @@ pub const panic: PanicFn = if (@hasDecl(root, "panic")) root.panic else default_...@@ -677,6 +677,13 @@ pub const panic: PanicFn = if (@hasDecl(root, "panic")) root.panic else default_
677/// therefore must be kept in sync with the compiler implementation.677/// therefore must be kept in sync with the compiler implementation.
678pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn {678pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn {
679 @setCold(true);679 @setCold(true);
680 // Until self-hosted catches up with stage1 language features, we have a simpler
681 // default panic function:
682 if (builtin.zig_is_stage2) {
683 while (true) {
684 @breakpoint();
685 }
686 }
680 if (@hasDecl(root, "os") and @hasDecl(root.os, "panic")) {687 if (@hasDecl(root, "os") and @hasDecl(root.os, "panic")) {
681 root.os.panic(msg, error_return_trace);688 root.os.panic(msg, error_return_trace);
682 unreachable;689 unreachable;
lib/std/hash_map.zig+26-6
...@@ -483,10 +483,20 @@ pub fn HashMap(...@@ -483,10 +483,20 @@ pub fn HashMap(
483 return self.unmanaged.getOrPutValueContext(self.allocator, key, value, self.ctx);483 return self.unmanaged.getOrPutValueContext(self.allocator, key, value, self.ctx);
484 }484 }
485485
486 /// Deprecated: call `ensureUnusedCapacity` or `ensureTotalCapacity`.
487 pub const ensureCapacity = ensureTotalCapacity;
488
486 /// Increases capacity, guaranteeing that insertions up until the489 /// Increases capacity, guaranteeing that insertions up until the
487 /// `expected_count` will not cause an allocation, and therefore cannot fail.490 /// `expected_count` will not cause an allocation, and therefore cannot fail.
488 pub fn ensureCapacity(self: *Self, expected_count: Size) !void {491 pub fn ensureTotalCapacity(self: *Self, expected_count: Size) !void {
489 return self.unmanaged.ensureCapacityContext(self.allocator, expected_count, self.ctx);492 return self.unmanaged.ensureTotalCapacityContext(self.allocator, expected_count, self.ctx);
493 }
494
495 /// Increases capacity, guaranteeing that insertions up until
496 /// `additional_count` **more** items will not cause an allocation, and
497 /// therefore cannot fail.
498 pub fn ensureUnusedCapacity(self: *Self, additional_count: Size) !void {
499 return self.unmanaged.ensureUnusedCapacityContext(self.allocator, additional_count, self.ctx);
490 }500 }
491501
492 /// Returns the number of total elements which may be present before it is502 /// Returns the number of total elements which may be present before it is
...@@ -821,16 +831,26 @@ pub fn HashMapUnmanaged(...@@ -821,16 +831,26 @@ pub fn HashMapUnmanaged(
821 return new_cap;831 return new_cap;
822 }832 }
823833
824 pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_size: Size) !void {834 /// Deprecated: call `ensureUnusedCapacity` or `ensureTotalCapacity`.
835 pub const ensureCapacity = ensureTotalCapacity;
836
837 pub fn ensureTotalCapacity(self: *Self, allocator: *Allocator, new_size: Size) !void {
825 if (@sizeOf(Context) != 0)838 if (@sizeOf(Context) != 0)
826 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureCapacityContext instead.");839 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead.");
827 return ensureCapacityContext(self, allocator, new_size, undefined);840 return ensureTotalCapacityContext(self, allocator, new_size, undefined);
828 }841 }
829 pub fn ensureCapacityContext(self: *Self, allocator: *Allocator, new_size: Size, ctx: Context) !void {842 pub fn ensureTotalCapacityContext(self: *Self, allocator: *Allocator, new_size: Size, ctx: Context) !void {
830 if (new_size > self.size)843 if (new_size > self.size)
831 try self.growIfNeeded(allocator, new_size - self.size, ctx);844 try self.growIfNeeded(allocator, new_size - self.size, ctx);
832 }845 }
833846
847 pub fn ensureUnusedCapacity(self: *Self, allocator: *Allocator, additional_size: Size) !void {
848 return ensureUnusedCapacityContext(self, allocator, additional_size, undefined);
849 }
850 pub fn ensureUnusedCapacityContext(self: *Self, allocator: *Allocator, additional_size: Size, ctx: Context) !void {
851 return ensureTotalCapacityContext(self, allocator, self.capacity() + additional_size, ctx);
852 }
853
834 pub fn clearRetainingCapacity(self: *Self) void {854 pub fn clearRetainingCapacity(self: *Self) void {
835 if (self.metadata) |_| {855 if (self.metadata) |_| {
836 self.initMetadatas();856 self.initMetadatas();
src/AstGen.zig+164-57
...@@ -786,7 +786,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr...@@ -786,7 +786,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr
786 rl,786 rl,
787 node,787 node,
788 node_datas[node].lhs,788 node_datas[node].lhs,
789 .is_err_ptr,789 .is_non_err_ptr,
790 .err_union_payload_unsafe_ptr,790 .err_union_payload_unsafe_ptr,
791 .err_union_code_ptr,791 .err_union_code_ptr,
792 node_datas[node].rhs,792 node_datas[node].rhs,
...@@ -798,7 +798,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr...@@ -798,7 +798,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr
798 rl,798 rl,
799 node,799 node,
800 node_datas[node].lhs,800 node_datas[node].lhs,
801 .is_err,801 .is_non_err,
802 .err_union_payload_unsafe,802 .err_union_payload_unsafe,
803 .err_union_code,803 .err_union_code,
804 node_datas[node].rhs,804 node_datas[node].rhs,
...@@ -813,7 +813,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr...@@ -813,7 +813,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr
813 rl,813 rl,
814 node,814 node,
815 node_datas[node].lhs,815 node_datas[node].lhs,
816 .is_null_ptr,816 .is_non_null_ptr,
817 .optional_payload_unsafe_ptr,817 .optional_payload_unsafe_ptr,
818 undefined,818 undefined,
819 node_datas[node].rhs,819 node_datas[node].rhs,
...@@ -825,7 +825,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr...@@ -825,7 +825,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr
825 rl,825 rl,
826 node,826 node,
827 node_datas[node].lhs,827 node_datas[node].lhs,
828 .is_null,828 .is_non_null,
829 .optional_payload_unsafe,829 .optional_payload_unsafe,
830 undefined,830 undefined,
831 node_datas[node].rhs,831 node_datas[node].rhs,
...@@ -1860,7 +1860,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod...@@ -1860,7 +1860,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
1860 }1860 }
1861 }1861 }
18621862
1863 try genDefers(gz, parent_scope, scope, .none);1863 try genDefers(gz, parent_scope, scope, .normal_only);
1864 try checkUsed(gz, parent_scope, scope);1864 try checkUsed(gz, parent_scope, scope);
1865}1865}
18661866
...@@ -1948,11 +1948,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -1948,11 +1948,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
1948 .float128,1948 .float128,
1949 .int_type,1949 .int_type,
1950 .is_non_null,1950 .is_non_null,
1951 .is_null,
1952 .is_non_null_ptr,1951 .is_non_null_ptr,
1953 .is_null_ptr,1952 .is_non_err,
1954 .is_err,1953 .is_non_err_ptr,
1955 .is_err_ptr,
1956 .mod_rem,1954 .mod_rem,
1957 .mul,1955 .mul,
1958 .mulwrap,1956 .mulwrap,
...@@ -2102,6 +2100,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -2102,6 +2100,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
2102 .@"resume",2100 .@"resume",
2103 .@"await",2101 .@"await",
2104 .await_nosuspend,2102 .await_nosuspend,
2103 .ret_err_value_code,
2105 .extended,2104 .extended,
2106 => break :b false,2105 => break :b false,
21072106
...@@ -2113,6 +2112,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -2113,6 +2112,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
2113 .compile_error,2112 .compile_error,
2114 .ret_node,2113 .ret_node,
2115 .ret_coerce,2114 .ret_coerce,
2115 .ret_err_value,
2116 .@"unreachable",2116 .@"unreachable",
2117 .repeat,2117 .repeat,
2118 .repeat_inline,2118 .repeat_inline,
...@@ -2162,13 +2162,63 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -2162,13 +2162,63 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
2162 return noreturn_src_node;2162 return noreturn_src_node;
2163}2163}
21642164
2165fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct {
2166 have_any: bool,
2167 have_normal: bool,
2168 have_err: bool,
2169 need_err_code: bool,
2170} {
2171 const tree = astgen.tree;
2172 const node_datas = tree.nodes.items(.data);
2173
2174 var have_normal = false;
2175 var have_err = false;
2176 var need_err_code = false;
2177 var scope = inner_scope;
2178 while (scope != outer_scope) {
2179 switch (scope.tag) {
2180 .gen_zir => scope = scope.cast(GenZir).?.parent,
2181 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2182 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2183 .defer_normal => {
2184 const defer_scope = scope.cast(Scope.Defer).?;
2185 scope = defer_scope.parent;
2186
2187 have_normal = true;
2188 },
2189 .defer_error => {
2190 const defer_scope = scope.cast(Scope.Defer).?;
2191 scope = defer_scope.parent;
2192
2193 have_err = true;
2194
2195 const have_err_payload = node_datas[defer_scope.defer_node].lhs != 0;
2196 need_err_code = need_err_code or have_err_payload;
2197 },
2198 .namespace => unreachable,
2199 .top => unreachable,
2200 }
2201 }
2202 return .{
2203 .have_any = have_normal or have_err,
2204 .have_normal = have_normal,
2205 .have_err = have_err,
2206 .need_err_code = need_err_code,
2207 };
2208}
2209
2210const DefersToEmit = union(enum) {
2211 both: Zir.Inst.Ref, // err code
2212 both_sans_err,
2213 normal_only,
2214};
2215
2165fn genDefers(2216fn genDefers(
2166 gz: *GenZir,2217 gz: *GenZir,
2167 outer_scope: *Scope,2218 outer_scope: *Scope,
2168 inner_scope: *Scope,2219 inner_scope: *Scope,
2169 err_code: Zir.Inst.Ref,2220 which_ones: DefersToEmit,
2170) InnerError!void {2221) InnerError!void {
2171 _ = err_code;
2172 const astgen = gz.astgen;2222 const astgen = gz.astgen;
2173 const tree = astgen.tree;2223 const tree = astgen.tree;
2174 const node_datas = tree.nodes.items(.data);2224 const node_datas = tree.nodes.items(.data);
...@@ -2191,12 +2241,37 @@ fn genDefers(...@@ -2191,12 +2241,37 @@ fn genDefers(
2191 .defer_error => {2241 .defer_error => {
2192 const defer_scope = scope.cast(Scope.Defer).?;2242 const defer_scope = scope.cast(Scope.Defer).?;
2193 scope = defer_scope.parent;2243 scope = defer_scope.parent;
2194 if (err_code == .none) continue;2244 switch (which_ones) {
2195 const expr_node = node_datas[defer_scope.defer_node].rhs;2245 .both_sans_err => {
2196 const prev_in_defer = gz.in_defer;2246 const expr_node = node_datas[defer_scope.defer_node].rhs;
2197 gz.in_defer = true;2247 const prev_in_defer = gz.in_defer;
2198 defer gz.in_defer = prev_in_defer;2248 gz.in_defer = true;
2199 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);2249 defer gz.in_defer = prev_in_defer;
2250 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
2251 },
2252 .both => |err_code| {
2253 const expr_node = node_datas[defer_scope.defer_node].rhs;
2254 const payload_token = node_datas[defer_scope.defer_node].lhs;
2255 const prev_in_defer = gz.in_defer;
2256 gz.in_defer = true;
2257 defer gz.in_defer = prev_in_defer;
2258 var local_val_scope: Scope.LocalVal = undefined;
2259 const sub_scope = if (payload_token == 0) defer_scope.parent else blk: {
2260 const ident_name = try astgen.identAsString(payload_token);
2261 local_val_scope = .{
2262 .parent = defer_scope.parent,
2263 .gen_zir = gz,
2264 .name = ident_name,
2265 .inst = err_code,
2266 .token_src = payload_token,
2267 .id_cat = .@"capture",
2268 };
2269 break :blk &local_val_scope.base;
2270 };
2271 _ = try unusedResultExpr(gz, sub_scope, expr_node);
2272 },
2273 .normal_only => continue,
2274 }
2200 },2275 },
2201 .namespace => unreachable,2276 .namespace => unreachable,
2202 .top => unreachable,2277 .top => unreachable,
...@@ -4544,8 +4619,8 @@ fn tryExpr(...@@ -4544,8 +4619,8 @@ fn tryExpr(
4544 };4619 };
4545 const err_ops = switch (rl) {4620 const err_ops = switch (rl) {
4546 // zig fmt: off4621 // zig fmt: off
4547 .ref => [3]Zir.Inst.Tag{ .is_err_ptr, .err_union_code_ptr, .err_union_payload_unsafe_ptr },4622 .ref => [3]Zir.Inst.Tag{ .is_non_err_ptr, .err_union_code_ptr, .err_union_payload_unsafe_ptr },
4548 else => [3]Zir.Inst.Tag{ .is_err, .err_union_code, .err_union_payload_unsafe },4623 else => [3]Zir.Inst.Tag{ .is_non_err, .err_union_code, .err_union_payload_unsafe },
4549 // zig fmt: on4624 // zig fmt: on
4550 };4625 };
4551 // This could be a pointer or value depending on the `operand_rl` parameter.4626 // This could be a pointer or value depending on the `operand_rl` parameter.
...@@ -4563,21 +4638,21 @@ fn tryExpr(...@@ -4563,21 +4638,21 @@ fn tryExpr(
4563 var then_scope = parent_gz.makeSubBlock(scope);4638 var then_scope = parent_gz.makeSubBlock(scope);
4564 defer then_scope.instructions.deinit(astgen.gpa);4639 defer then_scope.instructions.deinit(astgen.gpa);
45654640
4566 const err_code = try then_scope.addUnNode(err_ops[1], operand, node);
4567 try genDefers(&then_scope, &fn_block.base, scope, err_code);
4568 const then_result = try then_scope.addUnNode(.ret_node, err_code, node);
4569
4570 var else_scope = parent_gz.makeSubBlock(scope);
4571 defer else_scope.instructions.deinit(astgen.gpa);
4572
4573 block_scope.break_count += 1;4641 block_scope.break_count += 1;
4574 // This could be a pointer or value depending on `err_ops[2]`.4642 // This could be a pointer or value depending on `err_ops[2]`.
4575 const unwrapped_payload = try else_scope.addUnNode(err_ops[2], operand, node);4643 const unwrapped_payload = try then_scope.addUnNode(err_ops[2], operand, node);
4576 const else_result = switch (rl) {4644 const then_result = switch (rl) {
4577 .ref => unwrapped_payload,4645 .ref => unwrapped_payload,
4578 else => try rvalue(&else_scope, block_scope.break_result_loc, unwrapped_payload, node),4646 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),
4579 };4647 };
45804648
4649 var else_scope = parent_gz.makeSubBlock(scope);
4650 defer else_scope.instructions.deinit(astgen.gpa);
4651
4652 const err_code = try else_scope.addUnNode(err_ops[1], operand, node);
4653 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
4654 const else_result = try else_scope.addUnNode(.ret_node, err_code, node);
4655
4581 return finishThenElseBlock(4656 return finishThenElseBlock(
4582 parent_gz,4657 parent_gz,
4583 rl,4658 rl,
...@@ -4634,18 +4709,28 @@ fn orelseCatchExpr(...@@ -4634,18 +4709,28 @@ fn orelseCatchExpr(
4634 var then_scope = parent_gz.makeSubBlock(scope);4709 var then_scope = parent_gz.makeSubBlock(scope);
4635 defer then_scope.instructions.deinit(astgen.gpa);4710 defer then_scope.instructions.deinit(astgen.gpa);
46364711
4712 // This could be a pointer or value depending on `unwrap_op`.
4713 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
4714 const then_result = switch (rl) {
4715 .ref => unwrapped_payload,
4716 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),
4717 };
4718
4719 var else_scope = parent_gz.makeSubBlock(scope);
4720 defer else_scope.instructions.deinit(astgen.gpa);
4721
4637 var err_val_scope: Scope.LocalVal = undefined;4722 var err_val_scope: Scope.LocalVal = undefined;
4638 const then_sub_scope = blk: {4723 const else_sub_scope = blk: {
4639 const payload = payload_token orelse break :blk &then_scope.base;4724 const payload = payload_token orelse break :blk &else_scope.base;
4640 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {4725 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
4641 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});4726 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
4642 }4727 }
4643 const err_name = try astgen.identAsString(payload);4728 const err_name = try astgen.identAsString(payload);
4644 err_val_scope = .{4729 err_val_scope = .{
4645 .parent = &then_scope.base,4730 .parent = &else_scope.base,
4646 .gen_zir = &then_scope,4731 .gen_zir = &else_scope,
4647 .name = err_name,4732 .name = err_name,
4648 .inst = try then_scope.addUnNode(unwrap_code_op, operand, node),4733 .inst = try else_scope.addUnNode(unwrap_code_op, operand, node),
4649 .token_src = payload,4734 .token_src = payload,
4650 .id_cat = .@"capture",4735 .id_cat = .@"capture",
4651 };4736 };
...@@ -4653,23 +4738,13 @@ fn orelseCatchExpr(...@@ -4653,23 +4738,13 @@ fn orelseCatchExpr(
4653 };4738 };
46544739
4655 block_scope.break_count += 1;4740 block_scope.break_count += 1;
4656 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, rhs);4741 const else_result = try expr(&else_scope, else_sub_scope, block_scope.break_result_loc, rhs);
4657 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);4742 try checkUsed(parent_gz, &else_scope.base, else_sub_scope);
46584743
4659 // We hold off on the break instructions as well as copying the then/else4744 // We hold off on the break instructions as well as copying the then/else
4660 // instructions into place until we know whether to keep store_to_block_ptr4745 // instructions into place until we know whether to keep store_to_block_ptr
4661 // instructions or not.4746 // instructions or not.
46624747
4663 var else_scope = parent_gz.makeSubBlock(scope);
4664 defer else_scope.instructions.deinit(astgen.gpa);
4665
4666 // This could be a pointer or value depending on `unwrap_op`.
4667 const unwrapped_payload = try else_scope.addUnNode(unwrap_op, operand, node);
4668 const else_result = switch (rl) {
4669 .ref => unwrapped_payload,
4670 else => try rvalue(&else_scope, block_scope.break_result_loc, unwrapped_payload, node),
4671 };
4672
4673 return finishThenElseBlock(4748 return finishThenElseBlock(
4674 parent_gz,4749 parent_gz,
4675 rl,4750 rl,
...@@ -4887,7 +4962,7 @@ fn ifExpr(...@@ -4887,7 +4962,7 @@ fn ifExpr(
4887 if (if_full.error_token) |_| {4962 if (if_full.error_token) |_| {
4888 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;4963 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
4889 const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr);4964 const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr);
4890 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_err_ptr else .is_err;4965 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
4891 break :c .{4966 break :c .{
4892 .inst = err_union,4967 .inst = err_union,
4893 .bool_bit = try block_scope.addUnNode(tag, err_union, node),4968 .bool_bit = try block_scope.addUnNode(tag, err_union, node),
...@@ -5144,7 +5219,7 @@ fn whileExpr(...@@ -5144,7 +5219,7 @@ fn whileExpr(
5144 if (while_full.error_token) |_| {5219 if (while_full.error_token) |_| {
5145 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;5220 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
5146 const err_union = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr);5221 const err_union = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr);
5147 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_err_ptr else .is_err;5222 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
5148 break :c .{5223 break :c .{
5149 .inst = err_union,5224 .inst = err_union,
5150 .bool_bit = try continue_scope.addUnNode(tag, err_union, node),5225 .bool_bit = try continue_scope.addUnNode(tag, err_union, node),
...@@ -6090,17 +6165,37 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6090,17 +6165,37 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref
6090 const astgen = gz.astgen;6165 const astgen = gz.astgen;
6091 const tree = astgen.tree;6166 const tree = astgen.tree;
6092 const node_datas = tree.nodes.items(.data);6167 const node_datas = tree.nodes.items(.data);
6168 const node_tags = tree.nodes.items(.tag);
60936169
6094 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});6170 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});
60956171
6172 const defer_outer = &astgen.fn_block.?.base;
6173
6096 const operand_node = node_datas[node].lhs;6174 const operand_node = node_datas[node].lhs;
6097 if (operand_node == 0) {6175 if (operand_node == 0) {
6098 // Returning a void value; skip error defers.6176 // Returning a void value; skip error defers.
6099 try genDefers(gz, &astgen.fn_block.?.base, scope, .none);6177 try genDefers(gz, defer_outer, scope, .normal_only);
6100 _ = try gz.addUnNode(.ret_node, .void_value, node);6178 _ = try gz.addUnNode(.ret_node, .void_value, node);
6101 return Zir.Inst.Ref.unreachable_value;6179 return Zir.Inst.Ref.unreachable_value;
6102 }6180 }
61036181
6182 if (node_tags[operand_node] == .error_value) {
6183 // Hot path for `return error.Foo`. This bypasses result location logic as well as logic
6184 // for detecting whether to add something to the function's inferred error set.
6185 const ident_token = node_datas[operand_node].rhs;
6186 const err_name_str_index = try astgen.identAsString(ident_token);
6187 const defer_counts = countDefers(astgen, defer_outer, scope);
6188 if (!defer_counts.need_err_code) {
6189 try genDefers(gz, defer_outer, scope, .both_sans_err);
6190 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
6191 return Zir.Inst.Ref.unreachable_value;
6192 }
6193 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
6194 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6195 _ = try gz.addUnNode(.ret_node, err_code, node);
6196 return Zir.Inst.Ref.unreachable_value;
6197 }
6198
6104 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{6199 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{
6105 .ptr = try gz.addNodeExtended(.ret_ptr, node),6200 .ptr = try gz.addNodeExtended(.ret_ptr, node),
6106 } else .{6201 } else .{
...@@ -6111,34 +6206,46 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6111,34 +6206,46 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref
6111 switch (nodeMayEvalToError(tree, operand_node)) {6206 switch (nodeMayEvalToError(tree, operand_node)) {
6112 .never => {6207 .never => {
6113 // Returning a value that cannot be an error; skip error defers.6208 // Returning a value that cannot be an error; skip error defers.
6114 try genDefers(gz, &astgen.fn_block.?.base, scope, .none);6209 try genDefers(gz, defer_outer, scope, .normal_only);
6115 _ = try gz.addUnNode(.ret_node, operand, node);6210 _ = try gz.addUnNode(.ret_node, operand, node);
6116 return Zir.Inst.Ref.unreachable_value;6211 return Zir.Inst.Ref.unreachable_value;
6117 },6212 },
6118 .always => {6213 .always => {
6119 // Value is always an error. Emit both error defers and regular defers.6214 // Value is always an error. Emit both error defers and regular defers.
6120 const err_code = try gz.addUnNode(.err_union_code, operand, node);6215 const err_code = try gz.addUnNode(.err_union_code, operand, node);
6121 try genDefers(gz, &astgen.fn_block.?.base, scope, err_code);6216 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6122 _ = try gz.addUnNode(.ret_node, operand, node);6217 _ = try gz.addUnNode(.ret_node, operand, node);
6123 return Zir.Inst.Ref.unreachable_value;6218 return Zir.Inst.Ref.unreachable_value;
6124 },6219 },
6125 .maybe => {6220 .maybe => {
6221 const defer_counts = countDefers(astgen, defer_outer, scope);
6222 if (!defer_counts.have_err) {
6223 // Only regular defers; no branch needed.
6224 try genDefers(gz, defer_outer, scope, .normal_only);
6225 _ = try gz.addUnNode(.ret_node, operand, node);
6226 return Zir.Inst.Ref.unreachable_value;
6227 }
6228
6126 // Emit conditional branch for generating errdefers.6229 // Emit conditional branch for generating errdefers.
6127 const is_err = try gz.addUnNode(.is_err, operand, node);6230 const is_non_err = try gz.addUnNode(.is_non_err, operand, node);
6128 const condbr = try gz.addCondBr(.condbr, node);6231 const condbr = try gz.addCondBr(.condbr, node);
61296232
6130 var then_scope = gz.makeSubBlock(scope);6233 var then_scope = gz.makeSubBlock(scope);
6131 defer then_scope.instructions.deinit(astgen.gpa);6234 defer then_scope.instructions.deinit(astgen.gpa);
6132 const err_code = try then_scope.addUnNode(.err_union_code, operand, node);6235
6133 try genDefers(&then_scope, &astgen.fn_block.?.base, scope, err_code);6236 try genDefers(&then_scope, defer_outer, scope, .normal_only);
6134 _ = try then_scope.addUnNode(.ret_node, operand, node);6237 _ = try then_scope.addUnNode(.ret_node, operand, node);
61356238
6136 var else_scope = gz.makeSubBlock(scope);6239 var else_scope = gz.makeSubBlock(scope);
6137 defer else_scope.instructions.deinit(astgen.gpa);6240 defer else_scope.instructions.deinit(astgen.gpa);
6138 try genDefers(&else_scope, &astgen.fn_block.?.base, scope, .none);6241
6242 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
6243 .both = try else_scope.addUnNode(.err_union_code, operand, node),
6244 };
6245 try genDefers(&else_scope, defer_outer, scope, which_ones);
6139 _ = try else_scope.addUnNode(.ret_node, operand, node);6246 _ = try else_scope.addUnNode(.ret_node, operand, node);
61406247
6141 try setCondBrPayload(condbr, is_err, &then_scope, &else_scope);6248 try setCondBrPayload(condbr, is_non_err, &then_scope, &else_scope);
61426249
6143 return Zir.Inst.Ref.unreachable_value;6250 return Zir.Inst.Ref.unreachable_value;
6144 },6251 },
...@@ -6885,7 +6992,7 @@ fn builtinCall(...@@ -6885,7 +6992,7 @@ fn builtinCall(
6885 .field => {6992 .field => {
6886 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);6993 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
6887 if (rl == .ref) {6994 if (rl == .ref) {
6888 return try gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{6995 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
6889 .lhs = try expr(gz, scope, .ref, params[0]),6996 .lhs = try expr(gz, scope, .ref, params[0]),
6890 .field_name = field_name,6997 .field_name = field_name,
6891 });6998 });
src/Module.zig+17-2
...@@ -755,6 +755,7 @@ pub const Fn = struct {...@@ -755,6 +755,7 @@ pub const Fn = struct {
755 rbrace_column: u16,755 rbrace_column: u16,
756756
757 state: Analysis,757 state: Analysis,
758 is_cold: bool = false,
758759
759 pub const Analysis = enum {760 pub const Analysis = enum {
760 queued,761 queued,
...@@ -776,8 +777,19 @@ pub const Fn = struct {...@@ -776,8 +777,19 @@ pub const Fn = struct {
776 }777 }
777778
778 pub fn deinit(func: *Fn, gpa: *Allocator) void {779 pub fn deinit(func: *Fn, gpa: *Allocator) void {
779 _ = func;780 if (func.getInferredErrorSet()) |map| {
780 _ = gpa;781 map.deinit(gpa);
782 }
783 }
784
785 pub fn getInferredErrorSet(func: *Fn) ?*std.StringHashMapUnmanaged(void) {
786 const ret_ty = func.owner_decl.ty.fnReturnType();
787 if (ret_ty.zigTypeTag() == .ErrorUnion) {
788 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
789 return &payload.data.map;
790 }
791 }
792 return null;
781 }793 }
782};794};
783795
...@@ -3453,6 +3465,9 @@ pub fn clearDecl(...@@ -3453,6 +3465,9 @@ pub fn clearDecl(
3453 for (decl.dependencies.keys()) |dep| {3465 for (decl.dependencies.keys()) |dep| {
3454 dep.removeDependant(decl);3466 dep.removeDependant(decl);
3455 if (dep.dependants.count() == 0 and !dep.deletion_flag) {3467 if (dep.dependants.count() == 0 and !dep.deletion_flag) {
3468 log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{
3469 decl, decl.name, dep, dep.name,
3470 });
3456 // We don't recursively perform a deletion here, because during the update,3471 // We don't recursively perform a deletion here, because during the update,
3457 // another reference to it may turn up.3472 // another reference to it may turn up.
3458 dep.deletion_flag = true;3473 dep.deletion_flag = true;
src/Sema.zig+224-88
...@@ -225,12 +225,10 @@ pub fn analyzeBody(...@@ -225,12 +225,10 @@ pub fn analyzeBody(
225 .float => try sema.zirFloat(block, inst),225 .float => try sema.zirFloat(block, inst),
226 .float128 => try sema.zirFloat128(block, inst),226 .float128 => try sema.zirFloat128(block, inst),
227 .int_type => try sema.zirIntType(block, inst),227 .int_type => try sema.zirIntType(block, inst),
228 .is_err => try sema.zirIsErr(block, inst),228 .is_non_err => try sema.zirIsNonErr(block, inst),
229 .is_err_ptr => try sema.zirIsErrPtr(block, inst),229 .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
230 .is_non_null => try sema.zirIsNull(block, inst, true),230 .is_non_null => try sema.zirIsNonNull(block, inst),
231 .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true),231 .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
232 .is_null => try sema.zirIsNull(block, inst, false),
233 .is_null_ptr => try sema.zirIsNullPtr(block, inst, false),
234 .loop => try sema.zirLoop(block, inst),232 .loop => try sema.zirLoop(block, inst),
235 .merge_error_sets => try sema.zirMergeErrorSets(block, inst),233 .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
236 .negate => try sema.zirNegate(block, inst, .sub),234 .negate => try sema.zirNegate(block, inst, .sub),
...@@ -244,6 +242,7 @@ pub fn analyzeBody(...@@ -244,6 +242,7 @@ pub fn analyzeBody(
244 .ptr_type => try sema.zirPtrType(block, inst),242 .ptr_type => try sema.zirPtrType(block, inst),
245 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),243 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
246 .ref => try sema.zirRef(block, inst),244 .ref => try sema.zirRef(block, inst),
245 .ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
247 .shl => try sema.zirShl(block, inst),246 .shl => try sema.zirShl(block, inst),
248 .shr => try sema.zirShr(block, inst),247 .shr => try sema.zirShr(block, inst),
249 .slice_end => try sema.zirSliceEnd(block, inst),248 .slice_end => try sema.zirSliceEnd(block, inst),
...@@ -380,8 +379,9 @@ pub fn analyzeBody(...@@ -380,8 +379,9 @@ pub fn analyzeBody(
380 .condbr => return sema.zirCondbr(block, inst),379 .condbr => return sema.zirCondbr(block, inst),
381 .@"break" => return sema.zirBreak(block, inst),380 .@"break" => return sema.zirBreak(block, inst),
382 .compile_error => return sema.zirCompileError(block, inst),381 .compile_error => return sema.zirCompileError(block, inst),
383 .ret_coerce => return sema.zirRetTok(block, inst, true),382 .ret_coerce => return sema.zirRetCoerce(block, inst, true),
384 .ret_node => return sema.zirRetNode(block, inst),383 .ret_node => return sema.zirRetNode(block, inst),
384 .ret_err_value => return sema.zirRetErrValue(block, inst),
385 .@"unreachable" => return sema.zirUnreachable(block, inst),385 .@"unreachable" => return sema.zirUnreachable(block, inst),
386 .repeat => return sema.zirRepeat(block, inst),386 .repeat => return sema.zirRepeat(block, inst),
387 .panic => return sema.zirPanic(block, inst),387 .panic => return sema.zirPanic(block, inst),
...@@ -587,6 +587,19 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In...@@ -587,6 +587,19 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In
587 return sema.inst_map.get(@intCast(u32, i)).?;587 return sema.inst_map.get(@intCast(u32, i)).?;
588}588}
589589
590fn resolveConstBool(
591 sema: *Sema,
592 block: *Scope.Block,
593 src: LazySrcLoc,
594 zir_ref: Zir.Inst.Ref,
595) !bool {
596 const air_inst = try sema.resolveInst(zir_ref);
597 const wanted_type = Type.initTag(.bool);
598 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
599 const val = try sema.resolveConstValue(block, src, coerced_inst);
600 return val.toBool();
601}
602
590fn resolveConstString(603fn resolveConstString(
591 sema: *Sema,604 sema: *Sema,
592 block: *Scope.Block,605 block: *Scope.Block,
...@@ -1754,8 +1767,9 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!...@@ -1754,8 +1767,9 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
1754fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {1767fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {
1755 const inst_data = sema.code.instructions.items(.data)[inst].un_node;1768 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1756 const src: LazySrcLoc = inst_data.src();1769 const src: LazySrcLoc = inst_data.src();
1757 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirPanic", .{});1770 const msg_inst = try sema.resolveInst(inst_data.operand);
1758 //return always_noreturn;1771
1772 return sema.panicWithMsg(block, src, msg_inst);
1759}1773}
17601774
1761fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {1775fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
...@@ -2028,8 +2042,10 @@ fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inne...@@ -2028,8 +2042,10 @@ fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inne
20282042
2029fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2043fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
2030 const inst_data = sema.code.instructions.items(.data)[inst].un_node;2044 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2031 const src: LazySrcLoc = inst_data.src();2045 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2032 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetCold", .{});2046 const is_cold = try sema.resolveConstBool(block, operand_src, inst_data.operand);
2047 const func = sema.func orelse return; // does nothing outside a function
2048 func.is_cold = is_cold;
2033}2049}
20342050
2035fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2051fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
...@@ -2041,11 +2057,7 @@ fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner...@@ -2041,11 +2057,7 @@ fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
2041fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2057fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
2042 const inst_data = sema.code.instructions.items(.data)[inst].un_node;2058 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2043 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };2059 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20442060 block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand);
2045 const op = try sema.resolveInst(inst_data.operand);
2046 const op_coerced = try sema.coerce(block, Type.initTag(.bool), op, operand_src);
2047 const b = (try sema.resolveConstValue(block, operand_src, op_coerced)).toBool();
2048 block.want_safety = b;
2049}2061}
20502062
2051fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2063fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
...@@ -2190,21 +2202,27 @@ fn zirCall(...@@ -2190,21 +2202,27 @@ fn zirCall(
2190 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);2202 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
2191 const args = sema.code.refSlice(extra.end, extra.data.args_len);2203 const args = sema.code.refSlice(extra.end, extra.data.args_len);
21922204
2193 return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args);2205 const func = try sema.resolveInst(extra.data.callee);
2206 // TODO handle function calls of generic functions
2207 const resolved_args = try sema.arena.alloc(*Inst, args.len);
2208 for (args) |zir_arg, i| {
2209 // the args are already casted to the result of a param type instruction.
2210 resolved_args[i] = try sema.resolveInst(zir_arg);
2211 }
2212
2213 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args);
2194}2214}
21952215
2196fn analyzeCall(2216fn analyzeCall(
2197 sema: *Sema,2217 sema: *Sema,
2198 block: *Scope.Block,2218 block: *Scope.Block,
2199 zir_func: Zir.Inst.Ref,2219 func: *ir.Inst,
2200 func_src: LazySrcLoc,2220 func_src: LazySrcLoc,
2201 call_src: LazySrcLoc,2221 call_src: LazySrcLoc,
2202 modifier: std.builtin.CallOptions.Modifier,2222 modifier: std.builtin.CallOptions.Modifier,
2203 ensure_result_used: bool,2223 ensure_result_used: bool,
2204 zir_args: []const Zir.Inst.Ref,2224 args: []const *ir.Inst,
2205) InnerError!*ir.Inst {2225) InnerError!*ir.Inst {
2206 const func = try sema.resolveInst(zir_func);
2207
2208 if (func.ty.zigTypeTag() != .Fn)2226 if (func.ty.zigTypeTag() != .Fn)
2209 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});2227 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
22102228
...@@ -2221,22 +2239,22 @@ fn analyzeCall(...@@ -2221,22 +2239,22 @@ fn analyzeCall(
2221 const fn_params_len = func.ty.fnParamLen();2239 const fn_params_len = func.ty.fnParamLen();
2222 if (func.ty.fnIsVarArgs()) {2240 if (func.ty.fnIsVarArgs()) {
2223 assert(cc == .C);2241 assert(cc == .C);
2224 if (zir_args.len < fn_params_len) {2242 if (args.len < fn_params_len) {
2225 // TODO add error note: declared here2243 // TODO add error note: declared here
2226 return sema.mod.fail(2244 return sema.mod.fail(
2227 &block.base,2245 &block.base,
2228 func_src,2246 func_src,
2229 "expected at least {d} argument(s), found {d}",2247 "expected at least {d} argument(s), found {d}",
2230 .{ fn_params_len, zir_args.len },2248 .{ fn_params_len, args.len },
2231 );2249 );
2232 }2250 }
2233 } else if (fn_params_len != zir_args.len) {2251 } else if (fn_params_len != args.len) {
2234 // TODO add error note: declared here2252 // TODO add error note: declared here
2235 return sema.mod.fail(2253 return sema.mod.fail(
2236 &block.base,2254 &block.base,
2237 func_src,2255 func_src,
2238 "expected {d} argument(s), found {d}",2256 "expected {d} argument(s), found {d}",
2239 .{ fn_params_len, zir_args.len },2257 .{ fn_params_len, args.len },
2240 );2258 );
2241 }2259 }
22422260
...@@ -2256,13 +2274,6 @@ fn analyzeCall(...@@ -2256,13 +2274,6 @@ fn analyzeCall(
2256 }),2274 }),
2257 }2275 }
22582276
2259 // TODO handle function calls of generic functions
2260 const casted_args = try sema.arena.alloc(*Inst, zir_args.len);
2261 for (zir_args) |zir_arg, i| {
2262 // the args are already casted to the result of a param type instruction.
2263 casted_args[i] = try sema.resolveInst(zir_arg);
2264 }
2265
2266 const ret_type = func.ty.fnReturnType();2277 const ret_type = func.ty.fnReturnType();
22672278
2268 const is_comptime_call = block.is_comptime or modifier == .compile_time;2279 const is_comptime_call = block.is_comptime or modifier == .compile_time;
...@@ -2323,7 +2334,7 @@ fn analyzeCall(...@@ -2323,7 +2334,7 @@ fn analyzeCall(
2323 defer sema.func = parent_func;2334 defer sema.func = parent_func;
23242335
2325 const parent_param_inst_list = sema.param_inst_list;2336 const parent_param_inst_list = sema.param_inst_list;
2326 sema.param_inst_list = casted_args;2337 sema.param_inst_list = args;
2327 defer sema.param_inst_list = parent_param_inst_list;2338 defer sema.param_inst_list = parent_param_inst_list;
23282339
2329 const parent_next_arg_index = sema.next_arg_index;2340 const parent_next_arg_index = sema.next_arg_index;
...@@ -2357,7 +2368,7 @@ fn analyzeCall(...@@ -2357,7 +2368,7 @@ fn analyzeCall(
2357 break :res result;2368 break :res result;
2358 } else res: {2369 } else res: {
2359 try sema.requireRuntimeBlock(block, call_src);2370 try sema.requireRuntimeBlock(block, call_src);
2360 break :res try block.addCall(call_src, ret_type, func, casted_args);2371 break :res try block.addCall(call_src, ret_type, func, args);
2361 };2372 };
23622373
2363 if (ensure_result_used) {2374 if (ensure_result_used) {
...@@ -2968,17 +2979,19 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner...@@ -2968,17 +2979,19 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
2968 if (operand.ty.zigTypeTag() != .ErrorUnion)2979 if (operand.ty.zigTypeTag() != .ErrorUnion)
2969 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});2980 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
29702981
2982 const result_ty = operand.ty.castTag(.error_union).?.data.error_set;
2983
2971 if (operand.value()) |val| {2984 if (operand.value()) |val| {
2972 assert(val.getError() != null);2985 assert(val.getError() != null);
2973 const data = val.castTag(.error_union).?.data;2986 const data = val.castTag(.error_union).?.data;
2974 return sema.mod.constInst(sema.arena, src, .{2987 return sema.mod.constInst(sema.arena, src, .{
2975 .ty = operand.ty.castTag(.error_union).?.data.error_set,2988 .ty = result_ty,
2976 .val = data,2989 .val = data,
2977 });2990 });
2978 }2991 }
29792992
2980 try sema.requireRuntimeBlock(block, src);2993 try sema.requireRuntimeBlock(block, src);
2981 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);2994 return block.addUnOp(src, result_ty, .unwrap_errunion_err, operand);
2982}2995}
29832996
2984/// Pointer in, value out2997/// Pointer in, value out
...@@ -2994,18 +3007,20 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In...@@ -2994,18 +3007,20 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
2994 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)3007 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
2995 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});3008 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
29963009
3010 const result_ty = operand.ty.elemType().castTag(.error_union).?.data.error_set;
3011
2997 if (operand.value()) |pointer_val| {3012 if (operand.value()) |pointer_val| {
2998 const val = try pointer_val.pointerDeref(sema.arena);3013 const val = try pointer_val.pointerDeref(sema.arena);
2999 assert(val.getError() != null);3014 assert(val.getError() != null);
3000 const data = val.castTag(.error_union).?.data;3015 const data = val.castTag(.error_union).?.data;
3001 return sema.mod.constInst(sema.arena, src, .{3016 return sema.mod.constInst(sema.arena, src, .{
3002 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,3017 .ty = result_ty,
3003 .val = data,3018 .val = data,
3004 });3019 });
3005 }3020 }
30063021
3007 try sema.requireRuntimeBlock(block, src);3022 try sema.requireRuntimeBlock(block, src);
3008 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);3023 return block.addUnOp(src, result_ty, .unwrap_errunion_err_ptr, operand);
3009}3024}
30103025
3011fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {3026fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
...@@ -3081,28 +3096,31 @@ fn funcCommon(...@@ -3081,28 +3096,31 @@ fn funcCommon(
3081) InnerError!*Inst {3096) InnerError!*Inst {
3082 const src: LazySrcLoc = .{ .node_offset = src_node_offset };3097 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
3083 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };3098 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
3084 const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);3099 const bare_return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);
30853100
3086 const mod = sema.mod;3101 const mod = sema.mod;
30873102
3103 const new_func = if (body_inst == 0) undefined else try sema.gpa.create(Module.Fn);
3104 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);
3105
3088 const fn_ty: Type = fn_ty: {3106 const fn_ty: Type = fn_ty: {
3089 // Hot path for some common function types.3107 // Hot path for some common function types.
3090 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and3108 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and
3091 !inferred_error_set)3109 !inferred_error_set)
3092 {3110 {
3093 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {3111 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
3094 break :fn_ty Type.initTag(.fn_noreturn_no_args);3112 break :fn_ty Type.initTag(.fn_noreturn_no_args);
3095 }3113 }
30963114
3097 if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {3115 if (bare_return_type.zigTypeTag() == .Void and cc == .Unspecified) {
3098 break :fn_ty Type.initTag(.fn_void_no_args);3116 break :fn_ty Type.initTag(.fn_void_no_args);
3099 }3117 }
31003118
3101 if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {3119 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
3102 break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);3120 break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);
3103 }3121 }
31043122
3105 if (return_type.zigTypeTag() == .Void and cc == .C) {3123 if (bare_return_type.zigTypeTag() == .Void and cc == .C) {
3106 break :fn_ty Type.initTag(.fn_ccc_void_no_args);3124 break :fn_ty Type.initTag(.fn_ccc_void_no_args);
3107 }3125 }
3108 }3126 }
...@@ -3120,9 +3138,16 @@ fn funcCommon(...@@ -3120,9 +3138,16 @@ fn funcCommon(
3120 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});3138 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
3121 }3139 }
31223140
3123 if (inferred_error_set) {3141 const return_type = if (!inferred_error_set) bare_return_type else blk: {
3124 return mod.fail(&block.base, src, "TODO implement functions with inferred error sets", .{});3142 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{
3125 }3143 .func = new_func,
3144 .map = .{},
3145 });
3146 break :blk try Type.Tag.error_union.create(sema.arena, .{
3147 .error_set = error_set_ty,
3148 .payload = bare_return_type,
3149 });
3150 };
31263151
3127 break :fn_ty try Type.Tag.function.create(sema.arena, .{3152 break :fn_ty try Type.Tag.function.create(sema.arena, .{
3128 .param_types = param_types,3153 .param_types = param_types,
...@@ -3188,7 +3213,6 @@ fn funcCommon(...@@ -3188,7 +3213,6 @@ fn funcCommon(
3188 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;3213 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
31893214
3190 const fn_payload = try sema.arena.create(Value.Payload.Function);3215 const fn_payload = try sema.arena.create(Value.Payload.Function);
3191 const new_func = try sema.gpa.create(Module.Fn);
3192 new_func.* = .{3216 new_func.* = .{
3193 .state = anal_state,3217 .state = anal_state,
3194 .zir_body_inst = body_inst,3218 .zir_body_inst = body_inst,
...@@ -4542,6 +4566,12 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!...@@ -4542,6 +4566,12 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
4542 return mod.constType(sema.arena, src, file_root_decl.ty);4566 return mod.constType(sema.arena, src, file_root_decl.ty);
4543}4567}
45444568
4569fn zirRetErrValueCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4570 _ = block;
4571 _ = inst;
4572 return sema.mod.fail(&block.base, sema.src, "TODO implement zirRetErrValueCode", .{});
4573}
4574
4545fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {4575fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4546 const tracy = trace(@src());4576 const tracy = trace(@src());
4547 defer tracy.end();4577 defer tracy.end();
...@@ -5273,11 +5303,10 @@ fn zirBoolBr(...@@ -5273,11 +5303,10 @@ fn zirBoolBr(
5273 return &block_inst.base;5303 return &block_inst.base;
5274}5304}
52755305
5276fn zirIsNull(5306fn zirIsNonNull(
5277 sema: *Sema,5307 sema: *Sema,
5278 block: *Scope.Block,5308 block: *Scope.Block,
5279 inst: Zir.Inst.Index,5309 inst: Zir.Inst.Index,
5280 invert_logic: bool,
5281) InnerError!*Inst {5310) InnerError!*Inst {
5282 const tracy = trace(@src());5311 const tracy = trace(@src());
5283 defer tracy.end();5312 defer tracy.end();
...@@ -5285,14 +5314,13 @@ fn zirIsNull(...@@ -5285,14 +5314,13 @@ fn zirIsNull(
5285 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5314 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5286 const src = inst_data.src();5315 const src = inst_data.src();
5287 const operand = try sema.resolveInst(inst_data.operand);5316 const operand = try sema.resolveInst(inst_data.operand);
5288 return sema.analyzeIsNull(block, src, operand, invert_logic);5317 return sema.analyzeIsNull(block, src, operand, true);
5289}5318}
52905319
5291fn zirIsNullPtr(5320fn zirIsNonNullPtr(
5292 sema: *Sema,5321 sema: *Sema,
5293 block: *Scope.Block,5322 block: *Scope.Block,
5294 inst: Zir.Inst.Index,5323 inst: Zir.Inst.Index,
5295 invert_logic: bool,
5296) InnerError!*Inst {5324) InnerError!*Inst {
5297 const tracy = trace(@src());5325 const tracy = trace(@src());
5298 defer tracy.end();5326 defer tracy.end();
...@@ -5301,19 +5329,19 @@ fn zirIsNullPtr(...@@ -5301,19 +5329,19 @@ fn zirIsNullPtr(
5301 const src = inst_data.src();5329 const src = inst_data.src();
5302 const ptr = try sema.resolveInst(inst_data.operand);5330 const ptr = try sema.resolveInst(inst_data.operand);
5303 const loaded = try sema.analyzeLoad(block, src, ptr, src);5331 const loaded = try sema.analyzeLoad(block, src, ptr, src);
5304 return sema.analyzeIsNull(block, src, loaded, invert_logic);5332 return sema.analyzeIsNull(block, src, loaded, true);
5305}5333}
53065334
5307fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {5335fn zirIsNonErr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
5308 const tracy = trace(@src());5336 const tracy = trace(@src());
5309 defer tracy.end();5337 defer tracy.end();
53105338
5311 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5339 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5312 const operand = try sema.resolveInst(inst_data.operand);5340 const operand = try sema.resolveInst(inst_data.operand);
5313 return sema.analyzeIsErr(block, inst_data.src(), operand);5341 return sema.analyzeIsNonErr(block, inst_data.src(), operand);
5314}5342}
53155343
5316fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {5344fn zirIsNonErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
5317 const tracy = trace(@src());5345 const tracy = trace(@src());
5318 defer tracy.end();5346 defer tracy.end();
53195347
...@@ -5321,7 +5349,7 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro...@@ -5321,7 +5349,7 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
5321 const src = inst_data.src();5349 const src = inst_data.src();
5322 const ptr = try sema.resolveInst(inst_data.operand);5350 const ptr = try sema.resolveInst(inst_data.operand);
5323 const loaded = try sema.analyzeLoad(block, src, ptr, src);5351 const loaded = try sema.analyzeLoad(block, src, ptr, src);
5324 return sema.analyzeIsErr(block, src, loaded);5352 return sema.analyzeIsNonErr(block, src, loaded);
5325}5353}
53265354
5327fn zirCondbr(5355fn zirCondbr(
...@@ -5388,7 +5416,31 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE...@@ -5388,7 +5416,31 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
5388 }5416 }
5389}5417}
53905418
5391fn zirRetTok(5419fn zirRetErrValue(
5420 sema: *Sema,
5421 block: *Scope.Block,
5422 inst: Zir.Inst.Index,
5423) InnerError!Zir.Inst.Index {
5424 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
5425 const err_name = inst_data.get(sema.code);
5426 const src = inst_data.src();
5427
5428 // Add the error tag to the inferred error set of the in-scope function.
5429 if (sema.func) |func| {
5430 if (func.getInferredErrorSet()) |map| {
5431 _ = try map.getOrPut(sema.gpa, err_name);
5432 }
5433 }
5434 // Return the error code from the function.
5435 const kv = try sema.mod.getErrorValue(err_name);
5436 const result_inst = try sema.mod.constInst(sema.arena, src, .{
5437 .ty = try Type.Tag.error_set_single.create(sema.arena, kv.key),
5438 .val = try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }),
5439 });
5440 return sema.analyzeRet(block, result_inst, src, true);
5441}
5442
5443fn zirRetCoerce(
5392 sema: *Sema,5444 sema: *Sema,
5393 block: *Scope.Block,5445 block: *Scope.Block,
5394 inst: Zir.Inst.Index,5446 inst: Zir.Inst.Index,
...@@ -6195,6 +6247,10 @@ fn zirFuncExtended(...@@ -6195,6 +6247,10 @@ fn zirFuncExtended(
6195 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;6247 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
6196 }6248 }
61976249
6250 const is_var_args = small.is_var_args;
6251 const is_inferred_error = small.is_inferred_error;
6252 const is_extern = small.is_extern;
6253
6198 return sema.funcCommon(6254 return sema.funcCommon(
6199 block,6255 block,
6200 extra.data.src_node,6256 extra.data.src_node,
...@@ -6203,9 +6259,9 @@ fn zirFuncExtended(...@@ -6203,9 +6259,9 @@ fn zirFuncExtended(
6203 extra.data.return_type,6259 extra.data.return_type,
6204 cc,6260 cc,
6205 align_val,6261 align_val,
6206 small.is_var_args,6262 is_var_args,
6207 small.is_inferred_error,6263 is_inferred_error,
6208 small.is_extern,6264 is_extern,
6209 src_locs,6265 src_locs,
6210 lib_name,6266 lib_name,
6211 );6267 );
...@@ -6357,15 +6413,75 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id:...@@ -6357,15 +6413,75 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id:
6357 try parent_block.instructions.append(sema.gpa, &block_inst.base);6413 try parent_block.instructions.append(sema.gpa, &block_inst.base);
6358}6414}
63596415
6360fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !Zir.Inst.Index {6416fn panicWithMsg(
6361 _ = sema;6417 sema: *Sema,
6362 _ = panic_id;6418 block: *Scope.Block,
6363 // TODO Once we have a panic function to call, call it here instead of breakpoint.6419 src: LazySrcLoc,
6364 _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);6420 msg_inst: *ir.Inst,
6365 _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);6421) !Zir.Inst.Index {
6422 const mod = sema.mod;
6423 const arena = sema.arena;
6424
6425 const this_feature_is_implemented_in_the_backend =
6426 mod.comp.bin_file.options.object_format == .c;
6427 if (!this_feature_is_implemented_in_the_backend) {
6428 // TODO implement this feature in all the backends and then delete this branch
6429 _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
6430 _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);
6431 return always_noreturn;
6432 }
6433 const panic_fn = try sema.getBuiltin(block, src, "panic");
6434 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
6435 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
6436 const ptr_stack_trace_ty = try mod.simplePtrType(arena, stack_trace_ty, true, .One);
6437 const null_stack_trace = try mod.constInst(arena, src, .{
6438 .ty = try mod.optionalType(arena, ptr_stack_trace_ty),
6439 .val = Value.initTag(.null_value),
6440 });
6441 const args = try arena.create([2]*ir.Inst);
6442 args.* = .{ msg_inst, null_stack_trace };
6443 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, args);
6366 return always_noreturn;6444 return always_noreturn;
6367}6445}
63686446
6447fn safetyPanic(
6448 sema: *Sema,
6449 block: *Scope.Block,
6450 src: LazySrcLoc,
6451 panic_id: PanicId,
6452) !Zir.Inst.Index {
6453 const msg = switch (panic_id) {
6454 .unreach => "reached unreachable code",
6455 .unwrap_null => "attempt to use null value",
6456 .unwrap_errunion => "unreachable error occurred",
6457 .cast_to_null => "cast causes pointer to be null",
6458 .incorrect_alignment => "incorrect alignment",
6459 .invalid_error_code => "invalid error code",
6460 };
6461
6462 const msg_inst = msg_inst: {
6463 // TODO instead of making a new decl for every panic in the entire compilation,
6464 // introduce the concept of a reference-counted decl for these
6465 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
6466 errdefer new_decl_arena.deinit();
6467
6468 const decl_ty = try Type.Tag.array_u8.create(&new_decl_arena.allocator, msg.len);
6469 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, msg);
6470
6471 const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{
6472 .ty = decl_ty,
6473 .val = decl_val,
6474 });
6475 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
6476 try new_decl.finalizeNewArena(&new_decl_arena);
6477 break :msg_inst try sema.analyzeDeclRef(block, .unneeded, new_decl);
6478 };
6479
6480 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);
6481
6482 return sema.panicWithMsg(block, src, casted_msg_inst);
6483}
6484
6369fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {6485fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
6370 sema.branch_count += 1;6486 sema.branch_count += 1;
6371 if (sema.branch_count > sema.branch_quota) {6487 if (sema.branch_count > sema.branch_quota) {
...@@ -7102,20 +7218,25 @@ fn analyzeIsNull(...@@ -7102,20 +7218,25 @@ fn analyzeIsNull(
7102 return block.addUnOp(src, result_ty, inst_tag, operand);7218 return block.addUnOp(src, result_ty, inst_tag, operand);
7103}7219}
71047220
7105fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst {7221fn analyzeIsNonErr(
7222 sema: *Sema,
7223 block: *Scope.Block,
7224 src: LazySrcLoc,
7225 operand: *Inst,
7226) InnerError!*Inst {
7106 const ot = operand.ty.zigTypeTag();7227 const ot = operand.ty.zigTypeTag();
7107 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false);7228 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, true);
7108 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true);7229 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, false);
7109 assert(ot == .ErrorUnion);7230 assert(ot == .ErrorUnion);
7110 const result_ty = Type.initTag(.bool);7231 const result_ty = Type.initTag(.bool);
7111 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {7232 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {
7112 if (err_union.isUndef()) {7233 if (err_union.isUndef()) {
7113 return sema.mod.constUndef(sema.arena, src, result_ty);7234 return sema.mod.constUndef(sema.arena, src, result_ty);
7114 }7235 }
7115 return sema.mod.constBool(sema.arena, src, err_union.getError() != null);7236 return sema.mod.constBool(sema.arena, src, err_union.getError() == null);
7116 }7237 }
7117 try sema.requireRuntimeBlock(block, src);7238 try sema.requireRuntimeBlock(block, src);
7118 return block.addUnOp(src, result_ty, .is_err, operand);7239 return block.addUnOp(src, result_ty, .is_non_err, operand);
7119}7240}
71207241
7121fn analyzeSlice(7242fn analyzeSlice(
...@@ -7377,15 +7498,13 @@ fn wrapOptional(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst)...@@ -7377,15 +7498,13 @@ fn wrapOptional(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst)
7377}7498}
73787499
7379fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {7500fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
7380 // TODO deal with inferred error sets
7381 const err_union = dest_type.castTag(.error_union).?;7501 const err_union = dest_type.castTag(.error_union).?;
7382 if (inst.value()) |val| {7502 if (inst.value()) |val| {
7383 const to_wrap = if (inst.ty.zigTypeTag() != .ErrorSet) blk: {7503 if (inst.ty.zigTypeTag() != .ErrorSet) {
7384 _ = try sema.coerce(block, err_union.data.payload, inst, inst.src);7504 _ = try sema.coerce(block, err_union.data.payload, inst, inst.src);
7385 break :blk val;
7386 } else switch (err_union.data.error_set.tag()) {7505 } else switch (err_union.data.error_set.tag()) {
7387 .anyerror => val,7506 .anyerror => {},
7388 .error_set_single => blk: {7507 .error_set_single => {
7389 const expected_name = val.castTag(.@"error").?.data.name;7508 const expected_name = val.castTag(.@"error").?.data.name;
7390 const n = err_union.data.error_set.castTag(.error_set_single).?.data;7509 const n = err_union.data.error_set.castTag(.error_set_single).?.data;
7391 if (!mem.eql(u8, expected_name, n)) {7510 if (!mem.eql(u8, expected_name, n)) {
...@@ -7396,9 +7515,8 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst...@@ -7396,9 +7515,8 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst
7396 .{ err_union.data.error_set, inst.ty },7515 .{ err_union.data.error_set, inst.ty },
7397 );7516 );
7398 }7517 }
7399 break :blk val;
7400 },7518 },
7401 .error_set => blk: {7519 .error_set => {
7402 const expected_name = val.castTag(.@"error").?.data.name;7520 const expected_name = val.castTag(.@"error").?.data.name;
7403 const error_set = err_union.data.error_set.castTag(.error_set).?.data;7521 const error_set = err_union.data.error_set.castTag(.error_set).?.data;
7404 const names = error_set.names_ptr[0..error_set.names_len];7522 const names = error_set.names_ptr[0..error_set.names_len];
...@@ -7415,18 +7533,26 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst...@@ -7415,18 +7533,26 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst
7415 .{ err_union.data.error_set, inst.ty },7533 .{ err_union.data.error_set, inst.ty },
7416 );7534 );
7417 }7535 }
7418 break :blk val;7536 },
7537 .error_set_inferred => {
7538 const expected_name = val.castTag(.@"error").?.data.name;
7539 const map = &err_union.data.error_set.castTag(.error_set_inferred).?.data.map;
7540 if (!map.contains(expected_name)) {
7541 return sema.mod.fail(
7542 &block.base,
7543 inst.src,
7544 "expected type '{}', found type '{}'",
7545 .{ err_union.data.error_set, inst.ty },
7546 );
7547 }
7419 },7548 },
7420 else => unreachable,7549 else => unreachable,
7421 };7550 }
74227551
7423 return sema.mod.constInst(sema.arena, inst.src, .{7552 return sema.mod.constInst(sema.arena, inst.src, .{
7424 .ty = dest_type,7553 .ty = dest_type,
7425 // creating a SubValue for the error_union payload7554 // creating a SubValue for the error_union payload
7426 .val = try Value.Tag.error_union.create(7555 .val = try Value.Tag.error_union.create(sema.arena, val),
7427 sema.arena,
7428 to_wrap,
7429 ),
7430 });7556 });
7431 }7557 }
74327558
...@@ -7573,12 +7699,12 @@ fn resolveBuiltinTypeFields(...@@ -7573,12 +7699,12 @@ fn resolveBuiltinTypeFields(
7573 return sema.resolveTypeFields(block, src, resolved_ty);7699 return sema.resolveTypeFields(block, src, resolved_ty);
7574}7700}
75757701
7576fn getBuiltinType(7702fn getBuiltin(
7577 sema: *Sema,7703 sema: *Sema,
7578 block: *Scope.Block,7704 block: *Scope.Block,
7579 src: LazySrcLoc,7705 src: LazySrcLoc,
7580 name: []const u8,7706 name: []const u8,
7581) InnerError!Type {7707) InnerError!*ir.Inst {
7582 const mod = sema.mod;7708 const mod = sema.mod;
7583 const std_pkg = mod.root_pkg.table.get("std").?;7709 const std_pkg = mod.root_pkg.table.get("std").?;
7584 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;7710 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
...@@ -7596,7 +7722,16 @@ fn getBuiltinType(...@@ -7596,7 +7722,16 @@ fn getBuiltinType(
7596 builtin_ty.getNamespace().?,7722 builtin_ty.getNamespace().?,
7597 name,7723 name,
7598 );7724 );
7599 const ty_inst = try sema.analyzeLoad(block, src, opt_ty_inst.?, src);7725 return sema.analyzeLoad(block, src, opt_ty_inst.?, src);
7726}
7727
7728fn getBuiltinType(
7729 sema: *Sema,
7730 block: *Scope.Block,
7731 src: LazySrcLoc,
7732 name: []const u8,
7733) InnerError!Type {
7734 const ty_inst = try sema.getBuiltin(block, src, name);
7600 return sema.resolveAirAsType(block, src, ty_inst);7735 return sema.resolveAirAsType(block, src, ty_inst);
7601}7736}
76027737
...@@ -7662,6 +7797,7 @@ fn typeHasOnePossibleValue(...@@ -7662,6 +7797,7 @@ fn typeHasOnePossibleValue(
7662 .error_union,7797 .error_union,
7663 .error_set,7798 .error_set,
7664 .error_set_single,7799 .error_set_single,
7800 .error_set_inferred,
7665 .@"opaque",7801 .@"opaque",
7666 .var_args_param,7802 .var_args_param,
7667 .manyptr_u8,7803 .manyptr_u8,
src/Zir.zig+33-26
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1//! Zig Intermediate Representation. Astgen.zig converts AST nodes to these1//! Zig Intermediate Representation. Astgen.zig converts AST nodes to these
2//! untyped IR instructions. Next, Sema.zig processes these into TZIR.2//! untyped IR instructions. Next, Sema.zig processes these into AIR.
3//! The minimum amount of information needed to represent a list of ZIR instructions.3//! The minimum amount of information needed to represent a list of ZIR instructions.
4//! Once this structure is completed, it can be used to generate TZIR, followed by4//! Once this structure is completed, it can be used to generate AIR, followed by
5//! machine code, without any memory access into the AST tree token list, node list,5//! machine code, without any memory access into the AST tree token list, node list,
6//! or source bytes. Exceptions include:6//! or source bytes. Exceptions include:
7//! * Compile errors, which may need to reach into these data structures to7//! * Compile errors, which may need to reach into these data structures to
...@@ -398,26 +398,20 @@ pub const Inst = struct {...@@ -398,26 +398,20 @@ pub const Inst = struct {
398 /// Return a boolean false if an optional is null. `x != null`398 /// Return a boolean false if an optional is null. `x != null`
399 /// Uses the `un_node` field.399 /// Uses the `un_node` field.
400 is_non_null,400 is_non_null,
401 /// Return a boolean true if an optional is null. `x == null`
402 /// Uses the `un_node` field.
403 is_null,
404 /// Return a boolean false if an optional is null. `x.* != null`401 /// Return a boolean false if an optional is null. `x.* != null`
405 /// Uses the `un_node` field.402 /// Uses the `un_node` field.
406 is_non_null_ptr,403 is_non_null_ptr,
407 /// Return a boolean true if an optional is null. `x.* == null`404 /// Return a boolean false if value is an error
408 /// Uses the `un_node` field.
409 is_null_ptr,
410 /// Return a boolean true if value is an error
411 /// Uses the `un_node` field.405 /// Uses the `un_node` field.
412 is_err,406 is_non_err,
413 /// Return a boolean true if dereferenced pointer is an error407 /// Return a boolean false if dereferenced pointer is an error
414 /// Uses the `un_node` field.408 /// Uses the `un_node` field.
415 is_err_ptr,409 is_non_err_ptr,
416 /// A labeled block of code that loops forever. At the end of the body will have either410 /// A labeled block of code that loops forever. At the end of the body will have either
417 /// a `repeat` instruction or a `repeat_inline` instruction.411 /// a `repeat` instruction or a `repeat_inline` instruction.
418 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.412 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.
419 /// This ZIR instruction is needed because TZIR does not (yet?) match ZIR, and Sema413 /// This ZIR instruction is needed because AIR does not (yet?) match ZIR, and Sema
420 /// needs to emit more than 1 TZIR block for this instruction.414 /// needs to emit more than 1 AIR block for this instruction.
421 /// The payload is `Block`.415 /// The payload is `Block`.
422 loop,416 loop,
423 /// Sends runtime control flow back to the beginning of the current block.417 /// Sends runtime control flow back to the beginning of the current block.
...@@ -466,6 +460,19 @@ pub const Inst = struct {...@@ -466,6 +460,19 @@ pub const Inst = struct {
466 /// Uses the `un_tok` union field.460 /// Uses the `un_tok` union field.
467 /// The operand needs to get coerced to the function's return type.461 /// The operand needs to get coerced to the function's return type.
468 ret_coerce,462 ret_coerce,
463 /// Sends control flow back to the function's callee.
464 /// The return operand is `error.foo` where `foo` is given by the string.
465 /// If the current function has an inferred error set, the error given by the
466 /// name is added to it.
467 /// Uses the `str_tok` union field.
468 ret_err_value,
469 /// A string name is provided which is an anonymous error set value.
470 /// If the current function has an inferred error set, the error given by the
471 /// name is added to it.
472 /// Results in the error code. Note that control flow is not diverted with
473 /// this instruction; a following 'ret' instruction will do the diversion.
474 /// Uses the `str_tok` union field.
475 ret_err_value_code,
469 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.476 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
470 /// Uses the `ptr_type_simple` union field.477 /// Uses the `ptr_type_simple` union field.
471 ptr_type_simple,478 ptr_type_simple,
...@@ -1033,11 +1040,9 @@ pub const Inst = struct {...@@ -1033,11 +1040,9 @@ pub const Inst = struct {
1033 .float128,1040 .float128,
1034 .int_type,1041 .int_type,
1035 .is_non_null,1042 .is_non_null,
1036 .is_null,
1037 .is_non_null_ptr,1043 .is_non_null_ptr,
1038 .is_null_ptr,1044 .is_non_err,
1039 .is_err,1045 .is_non_err_ptr,
1040 .is_err_ptr,
1041 .mod_rem,1046 .mod_rem,
1042 .mul,1047 .mul,
1043 .mulwrap,1048 .mulwrap,
...@@ -1193,6 +1198,7 @@ pub const Inst = struct {...@@ -1193,6 +1198,7 @@ pub const Inst = struct {
1193 .@"resume",1198 .@"resume",
1194 .@"await",1199 .@"await",
1195 .await_nosuspend,1200 .await_nosuspend,
1201 .ret_err_value_code,
1196 .extended,1202 .extended,
1197 => false,1203 => false,
11981204
...@@ -1203,6 +1209,7 @@ pub const Inst = struct {...@@ -1203,6 +1209,7 @@ pub const Inst = struct {
1203 .compile_error,1209 .compile_error,
1204 .ret_node,1210 .ret_node,
1205 .ret_coerce,1211 .ret_coerce,
1212 .ret_err_value,
1206 .@"unreachable",1213 .@"unreachable",
1207 .repeat,1214 .repeat,
1208 .repeat_inline,1215 .repeat_inline,
...@@ -1291,11 +1298,9 @@ pub const Inst = struct {...@@ -1291,11 +1298,9 @@ pub const Inst = struct {
1291 .float128 = .pl_node,1298 .float128 = .pl_node,
1292 .int_type = .int_type,1299 .int_type = .int_type,
1293 .is_non_null = .un_node,1300 .is_non_null = .un_node,
1294 .is_null = .un_node,
1295 .is_non_null_ptr = .un_node,1301 .is_non_null_ptr = .un_node,
1296 .is_null_ptr = .un_node,1302 .is_non_err = .un_node,
1297 .is_err = .un_node,1303 .is_non_err_ptr = .un_node,
1298 .is_err_ptr = .un_node,
1299 .loop = .pl_node,1304 .loop = .pl_node,
1300 .repeat = .node,1305 .repeat = .node,
1301 .repeat_inline = .node,1306 .repeat_inline = .node,
...@@ -1307,6 +1312,8 @@ pub const Inst = struct {...@@ -1307,6 +1312,8 @@ pub const Inst = struct {
1307 .ref = .un_tok,1312 .ref = .un_tok,
1308 .ret_node = .un_node,1313 .ret_node = .un_node,
1309 .ret_coerce = .un_tok,1314 .ret_coerce = .un_tok,
1315 .ret_err_value = .str_tok,
1316 .ret_err_value_code = .str_tok,
1310 .ptr_type_simple = .ptr_type_simple,1317 .ptr_type_simple = .ptr_type_simple,
1311 .ptr_type = .ptr_type,1318 .ptr_type = .ptr_type,
1312 .slice_start = .pl_node,1319 .slice_start = .pl_node,
...@@ -2840,11 +2847,9 @@ const Writer = struct {...@@ -2840,11 +2847,9 @@ const Writer = struct {
2840 .err_union_code,2847 .err_union_code,
2841 .err_union_code_ptr,2848 .err_union_code_ptr,
2842 .is_non_null,2849 .is_non_null,
2843 .is_null,
2844 .is_non_null_ptr,2850 .is_non_null_ptr,
2845 .is_null_ptr,2851 .is_non_err,
2846 .is_err,2852 .is_non_err_ptr,
2847 .is_err_ptr,
2848 .typeof,2853 .typeof,
2849 .typeof_elem,2854 .typeof_elem,
2850 .struct_init_empty,2855 .struct_init_empty,
...@@ -3077,6 +3082,8 @@ const Writer = struct {...@@ -3077,6 +3082,8 @@ const Writer = struct {
3077 .decl_val,3082 .decl_val,
3078 .import,3083 .import,
3079 .arg,3084 .arg,
3085 .ret_err_value,
3086 .ret_err_value_code,
3080 => try self.writeStrTok(stream, inst),3087 => try self.writeStrTok(stream, inst),
30813088
3082 .func => try self.writeFunc(stream, inst, false),3089 .func => try self.writeFunc(stream, inst, false),
src/air.zig+22-12
...@@ -90,8 +90,12 @@ pub const Inst = struct {...@@ -90,8 +90,12 @@ pub const Inst = struct {
90 is_non_null_ptr,90 is_non_null_ptr,
91 /// E!T => bool91 /// E!T => bool
92 is_err,92 is_err,
93 /// E!T => bool (inverted logic)
94 is_non_err,
93 /// *E!T => bool95 /// *E!T => bool
94 is_err_ptr,96 is_err_ptr,
97 /// *E!T => bool (inverted logic)
98 is_non_err_ptr,
95 bool_and,99 bool_and,
96 bool_or,100 bool_or,
97 /// Read a value from a pointer.101 /// Read a value from a pointer.
...@@ -154,7 +158,9 @@ pub const Inst = struct {...@@ -154,7 +158,9 @@ pub const Inst = struct {
154 .is_null,158 .is_null,
155 .is_null_ptr,159 .is_null_ptr,
156 .is_err,160 .is_err,
161 .is_non_err,
157 .is_err_ptr,162 .is_err_ptr,
163 .is_non_err_ptr,
158 .ptrtoint,164 .ptrtoint,
159 .floatcast,165 .floatcast,
160 .intcast,166 .intcast,
...@@ -672,15 +678,15 @@ pub const Body = struct {...@@ -672,15 +678,15 @@ pub const Body = struct {
672/// For debugging purposes, prints a function representation to stderr.678/// For debugging purposes, prints a function representation to stderr.
673pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {679pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {
674 const allocator = old_module.gpa;680 const allocator = old_module.gpa;
675 var ctx: DumpTzir = .{681 var ctx: DumpAir = .{
676 .allocator = allocator,682 .allocator = allocator,
677 .arena = std.heap.ArenaAllocator.init(allocator),683 .arena = std.heap.ArenaAllocator.init(allocator),
678 .old_module = &old_module,684 .old_module = &old_module,
679 .module_fn = module_fn,685 .module_fn = module_fn,
680 .indent = 2,686 .indent = 2,
681 .inst_table = DumpTzir.InstTable.init(allocator),687 .inst_table = DumpAir.InstTable.init(allocator),
682 .partial_inst_table = DumpTzir.InstTable.init(allocator),688 .partial_inst_table = DumpAir.InstTable.init(allocator),
683 .const_table = DumpTzir.InstTable.init(allocator),689 .const_table = DumpAir.InstTable.init(allocator),
684 };690 };
685 defer ctx.inst_table.deinit();691 defer ctx.inst_table.deinit();
686 defer ctx.partial_inst_table.deinit();692 defer ctx.partial_inst_table.deinit();
...@@ -695,12 +701,12 @@ pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {...@@ -695,12 +701,12 @@ pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {
695 .dependency_failure => std.debug.print("(dependency_failure)", .{}),701 .dependency_failure => std.debug.print("(dependency_failure)", .{}),
696 .success => {702 .success => {
697 const writer = std.io.getStdErr().writer();703 const writer = std.io.getStdErr().writer();
698 ctx.dump(module_fn.body, writer) catch @panic("failed to dump TZIR");704 ctx.dump(module_fn.body, writer) catch @panic("failed to dump AIR");
699 },705 },
700 }706 }
701}707}
702708
703const DumpTzir = struct {709const DumpAir = struct {
704 allocator: *std.mem.Allocator,710 allocator: *std.mem.Allocator,
705 arena: std.heap.ArenaAllocator,711 arena: std.heap.ArenaAllocator,
706 old_module: *const Module,712 old_module: *const Module,
...@@ -718,7 +724,7 @@ const DumpTzir = struct {...@@ -718,7 +724,7 @@ const DumpTzir = struct {
718 /// TODO: Improve this code to include a stack of Body and store the instructions724 /// TODO: Improve this code to include a stack of Body and store the instructions
719 /// in there. Now we are putting all the instructions in a function local table,725 /// in there. Now we are putting all the instructions in a function local table,
720 /// however instructions that are in a Body can be thown away when the Body ends.726 /// however instructions that are in a Body can be thown away when the Body ends.
721 fn dump(dtz: *DumpTzir, body: Body, writer: std.fs.File.Writer) !void {727 fn dump(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) !void {
722 // First pass to pre-populate the table so that we can show even invalid references.728 // First pass to pre-populate the table so that we can show even invalid references.
723 // Must iterate the same order we iterate the second time.729 // Must iterate the same order we iterate the second time.
724 // We also look for constants and put them in the const_table.730 // We also look for constants and put them in the const_table.
...@@ -737,7 +743,7 @@ const DumpTzir = struct {...@@ -737,7 +743,7 @@ const DumpTzir = struct {
737 return dtz.dumpBody(body, writer);743 return dtz.dumpBody(body, writer);
738 }744 }
739745
740 fn fetchInstsAndResolveConsts(dtz: *DumpTzir, body: Body) error{OutOfMemory}!void {746 fn fetchInstsAndResolveConsts(dtz: *DumpAir, body: Body) error{OutOfMemory}!void {
741 for (body.instructions) |inst| {747 for (body.instructions) |inst| {
742 try dtz.inst_table.put(inst, dtz.next_index);748 try dtz.inst_table.put(inst, dtz.next_index);
743 dtz.next_index += 1;749 dtz.next_index += 1;
...@@ -759,7 +765,9 @@ const DumpTzir = struct {...@@ -759,7 +765,9 @@ const DumpTzir = struct {
759 .is_null,765 .is_null,
760 .is_null_ptr,766 .is_null_ptr,
761 .is_err,767 .is_err,
768 .is_non_err,
762 .is_err_ptr,769 .is_err_ptr,
770 .is_non_err_ptr,
763 .ptrtoint,771 .ptrtoint,
764 .floatcast,772 .floatcast,
765 .intcast,773 .intcast,
...@@ -865,7 +873,7 @@ const DumpTzir = struct {...@@ -865,7 +873,7 @@ const DumpTzir = struct {
865 }873 }
866 }874 }
867875
868 fn dumpBody(dtz: *DumpTzir, body: Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void {876 fn dumpBody(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void {
869 for (body.instructions) |inst| {877 for (body.instructions) |inst| {
870 const my_index = dtz.next_partial_index;878 const my_index = dtz.next_partial_index;
871 try dtz.partial_inst_table.put(inst, my_index);879 try dtz.partial_inst_table.put(inst, my_index);
...@@ -888,11 +896,13 @@ const DumpTzir = struct {...@@ -888,11 +896,13 @@ const DumpTzir = struct {
888 .bitcast,896 .bitcast,
889 .not,897 .not,
890 .is_non_null,898 .is_non_null,
891 .is_null,
892 .is_non_null_ptr,899 .is_non_null_ptr,
900 .is_null,
893 .is_null_ptr,901 .is_null_ptr,
894 .is_err,902 .is_err,
895 .is_err_ptr,903 .is_err_ptr,
904 .is_non_err,
905 .is_non_err_ptr,
896 .ptrtoint,906 .ptrtoint,
897 .floatcast,907 .floatcast,
898 .intcast,908 .intcast,
...@@ -1150,7 +1160,7 @@ const DumpTzir = struct {...@@ -1150,7 +1160,7 @@ const DumpTzir = struct {
1150 }1160 }
1151 }1161 }
11521162
1153 fn writeInst(dtz: *DumpTzir, writer: std.fs.File.Writer, inst: *Inst) !?usize {1163 fn writeInst(dtz: *DumpAir, writer: std.fs.File.Writer, inst: *Inst) !?usize {
1154 if (dtz.partial_inst_table.get(inst)) |operand_index| {1164 if (dtz.partial_inst_table.get(inst)) |operand_index| {
1155 try writer.print("%{d}", .{operand_index});1165 try writer.print("%{d}", .{operand_index});
1156 return null;1166 return null;
...@@ -1166,7 +1176,7 @@ const DumpTzir = struct {...@@ -1166,7 +1176,7 @@ const DumpTzir = struct {
1166 }1176 }
1167 }1177 }
11681178
1169 fn findConst(dtz: *DumpTzir, operand: *Inst) !void {1179 fn findConst(dtz: *DumpAir, operand: *Inst) !void {
1170 if (operand.tag == .constant) {1180 if (operand.tag == .constant) {
1171 try dtz.const_table.put(operand, dtz.next_const_index);1181 try dtz.const_table.put(operand, dtz.next_const_index);
1172 dtz.next_const_index += 1;1182 dtz.next_const_index += 1;
src/codegen.zig+141-85
...@@ -142,40 +142,52 @@ pub fn generateSymbol(...@@ -142,40 +142,52 @@ pub fn generateSymbol(
142 ),142 ),
143 };143 };
144 },144 },
145 .Pointer => {145 .Pointer => switch (typed_value.ty.ptrSize()) {
146 // TODO populate .debug_info for the pointer146 .Slice => {
147 if (typed_value.val.castTag(.decl_ref)) |payload| {147 return Result{
148 const decl = payload.data;148 .fail = try ErrorMsg.create(
149 if (decl.analysis != .complete) return error.AnalysisFail;149 bin_file.allocator,
150 // TODO handle the dependency of this symbol on the decl's vaddr.150 src_loc,
151 // If the decl changes vaddr, then this symbol needs to get regenerated.151 "TODO implement generateSymbol for slice {}",
152 const vaddr = bin_file.getDeclVAddr(decl);152 .{typed_value.val},
153 const endian = bin_file.options.target.cpu.arch.endian();153 ),
154 switch (bin_file.options.target.cpu.arch.ptrBitWidth()) {154 };
155 16 => {155 },
156 try code.resize(2);156 else => {
157 mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian);157 // TODO populate .debug_info for the pointer
158 },158 if (typed_value.val.castTag(.decl_ref)) |payload| {
159 32 => {159 const decl = payload.data;
160 try code.resize(4);160 if (decl.analysis != .complete) return error.AnalysisFail;
161 mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian);161 // TODO handle the dependency of this symbol on the decl's vaddr.
162 },162 // If the decl changes vaddr, then this symbol needs to get regenerated.
163 64 => {163 const vaddr = bin_file.getDeclVAddr(decl);
164 try code.resize(8);164 const endian = bin_file.options.target.cpu.arch.endian();
165 mem.writeInt(u64, code.items[0..8], vaddr, endian);165 switch (bin_file.options.target.cpu.arch.ptrBitWidth()) {
166 },166 16 => {
167 else => unreachable,167 try code.resize(2);
168 mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian);
169 },
170 32 => {
171 try code.resize(4);
172 mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian);
173 },
174 64 => {
175 try code.resize(8);
176 mem.writeInt(u64, code.items[0..8], vaddr, endian);
177 },
178 else => unreachable,
179 }
180 return Result{ .appended = {} };
168 }181 }
169 return Result{ .appended = {} };182 return Result{
170 }183 .fail = try ErrorMsg.create(
171 return Result{184 bin_file.allocator,
172 .fail = try ErrorMsg.create(185 src_loc,
173 bin_file.allocator,186 "TODO implement generateSymbol for pointer {}",
174 src_loc,187 .{typed_value.val},
175 "TODO implement generateSymbol for pointer {}",188 ),
176 .{typed_value.val},189 };
177 ),190 },
178 };
179 },191 },
180 .Int => {192 .Int => {
181 // TODO populate .debug_info for the integer193 // TODO populate .debug_info for the integer
...@@ -847,6 +859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -847,6 +859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
847 .is_non_null_ptr => return self.genIsNonNullPtr(inst.castTag(.is_non_null_ptr).?),859 .is_non_null_ptr => return self.genIsNonNullPtr(inst.castTag(.is_non_null_ptr).?),
848 .is_null => return self.genIsNull(inst.castTag(.is_null).?),860 .is_null => return self.genIsNull(inst.castTag(.is_null).?),
849 .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?),861 .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?),
862 .is_non_err => return self.genIsNonErr(inst.castTag(.is_non_err).?),
863 .is_non_err_ptr => return self.genIsNonErrPtr(inst.castTag(.is_non_err_ptr).?),
850 .is_err => return self.genIsErr(inst.castTag(.is_err).?),864 .is_err => return self.genIsErr(inst.castTag(.is_err).?),
851 .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?),865 .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?),
852 .load => return self.genLoad(inst.castTag(.load).?),866 .load => return self.genLoad(inst.castTag(.load).?),
...@@ -2244,10 +2258,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2244,10 +2258,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2244 try self.register_manager.getReg(reg, null);2258 try self.register_manager.getReg(reg, null);
2245 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);2259 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2246 },2260 },
2247 .stack_offset => {2261 .stack_offset => |off| {
2248 // Here we need to emit instructions like this:2262 // Here we need to emit instructions like this:
2249 // mov qword ptr [rsp + stack_offset], x2263 // mov qword ptr [rsp + stack_offset], x
2250 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});2264 try self.genSetStack(arg.src, arg.ty, off, arg_mcv);
2251 },2265 },
2252 .ptr_stack_offset => {2266 .ptr_stack_offset => {
2253 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});2267 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
...@@ -2960,6 +2974,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2960,6 +2974,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2960 return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{});2974 return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{});
2961 }2975 }
29622976
2977 fn genIsNonErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
2978 switch (arch) {
2979 else => return self.fail(inst.base.src, "TODO implement is_non_err for {}", .{self.target.cpu.arch}),
2980 }
2981 }
2982
2983 fn genIsNonErrPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
2984 return self.fail(inst.base.src, "TODO load the operand and call genIsNonErr", .{});
2985 }
2986
2963 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {2987 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {
2964 // A loop is a setup to be able to jump back to the beginning.2988 // A loop is a setup to be able to jump back to the beginning.
2965 const start_index = self.code.items.len;2989 const start_index = self.code.items.len;
...@@ -3444,9 +3468,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3444,9 +3468,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3444 },3468 },
3445 }3469 }
3446 },3470 },
3447 .embedded_in_code => |code_offset| {3471 .embedded_in_code => {
3448 _ = code_offset;3472 // TODO this and `.stack_offset` below need to get improved to support types greater than
3449 return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{});3473 // register size, and do general memcpy
3474 const reg = try self.copyToTmpRegister(src, ty, mcv);
3475 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
3450 },3476 },
3451 .register => |reg| {3477 .register => |reg| {
3452 try self.genX8664ModRMRegToStack(src, ty, stack_offset, reg, 0x89);3478 try self.genX8664ModRMRegToStack(src, ty, stack_offset, reg, 0x89);
...@@ -3456,6 +3482,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3456,6 +3482,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3456 return self.fail(src, "TODO implement set stack variable from memory vaddr", .{});3482 return self.fail(src, "TODO implement set stack variable from memory vaddr", .{});
3457 },3483 },
3458 .stack_offset => |off| {3484 .stack_offset => |off| {
3485 // TODO this and `.embedded_in_code` above need to get improved to support types greater than
3486 // register size, and do general memcpy
3487
3459 if (stack_offset == off)3488 if (stack_offset == off)
3460 return; // Copy stack variable to itself; nothing to do.3489 return; // Copy stack variable to itself; nothing to do.
34613490
...@@ -4161,33 +4190,48 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4161,33 +4190,48 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4161 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4190 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4162 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4191 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4163 switch (typed_value.ty.zigTypeTag()) {4192 switch (typed_value.ty.zigTypeTag()) {
4164 .Pointer => {4193 .Pointer => switch (typed_value.ty.ptrSize()) {
4165 if (typed_value.val.castTag(.decl_ref)) |payload| {4194 .Slice => {
4166 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4195 var buf: Type.Payload.ElemType = undefined;
4167 const decl = payload.data;4196 const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
4168 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];4197 const ptr_mcv = try self.genTypedValue(src, .{ .ty = ptr_type, .val = typed_value.val });
4169 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;4198 const slice_len = typed_value.val.sliceLen();
4170 return MCValue{ .memory = got_addr };4199 // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean
4171 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4200 // the Sema code needs to use anonymous Decls or alloca instructions to store data.
4172 const decl = payload.data;4201 const ptr_imm = ptr_mcv.memory;
4173 const got_addr = blk: {4202 _ = slice_len;
4174 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;4203 _ = ptr_imm;
4175 const got = seg.sections.items[macho_file.got_section_index.?];4204 // We need more general support for const data being stored in memory to make this work.
4176 break :blk got.addr + decl.link.macho.offset_table_index * ptr_bytes;4205 return self.fail(src, "TODO codegen for const slices", .{});
4177 };4206 },
4178 return MCValue{ .memory = got_addr };4207 else => {
4179 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {4208 if (typed_value.val.castTag(.decl_ref)) |payload| {
4180 const decl = payload.data;4209 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4181 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;4210 const decl = payload.data;
4182 return MCValue{ .memory = got_addr };4211 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4183 } else {4212 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
4184 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});4213 return MCValue{ .memory = got_addr };
4214 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4215 const decl = payload.data;
4216 const got_addr = blk: {
4217 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
4218 const got = seg.sections.items[macho_file.got_section_index.?];
4219 break :blk got.addr + decl.link.macho.offset_table_index * ptr_bytes;
4220 };
4221 return MCValue{ .memory = got_addr };
4222 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4223 const decl = payload.data;
4224 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
4225 return MCValue{ .memory = got_addr };
4226 } else {
4227 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
4228 }
4185 }4229 }
4186 }4230 if (typed_value.val.tag() == .int_u64) {
4187 if (typed_value.val.tag() == .int_u64) {4231 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
4188 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };4232 }
4189 }4233 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
4190 return self.fail(src, "TODO codegen more kinds of const pointers", .{});4234 },
4191 },4235 },
4192 .Int => {4236 .Int => {
4193 const info = typed_value.ty.intInfo(self.target.*);4237 const info = typed_value.ty.intInfo(self.target.*);
...@@ -4264,27 +4308,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4264,27 +4308,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4264 var next_stack_offset: u32 = 0;4308 var next_stack_offset: u32 = 0;
42654309
4266 for (param_types) |ty, i| {4310 for (param_types) |ty, i| {
4267 switch (ty.zigTypeTag()) {4311 if (!ty.hasCodeGenBits()) {
4268 .Bool, .Int => {4312 assert(cc != .C);
4269 if (!ty.hasCodeGenBits()) {4313 result.args[i] = .{ .none = {} };
4270 assert(cc != .C);4314 continue;
4271 result.args[i] = .{ .none = {} };4315 }
4272 } else {4316 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4273 const param_size = @intCast(u32, ty.abiSize(self.target.*));4317 const pass_in_reg = switch (ty.zigTypeTag()) {
4274 if (next_int_reg >= c_abi_int_param_regs.len) {4318 .Bool => true,
4275 result.args[i] = .{ .stack_offset = next_stack_offset };4319 .Int => param_size <= 8,
4276 next_stack_offset += param_size;4320 .Pointer => ty.ptrSize() != .Slice,
4277 } else {4321 .Optional => ty.isPtrLikeOptional(),
4278 const aliased_reg = registerAlias(4322 else => false,
4279 c_abi_int_param_regs[next_int_reg],4323 };
4280 param_size,4324 if (pass_in_reg) {
4281 );4325 if (next_int_reg >= c_abi_int_param_regs.len) {
4282 result.args[i] = .{ .register = aliased_reg };4326 result.args[i] = .{ .stack_offset = next_stack_offset };
4283 next_int_reg += 1;4327 next_stack_offset += param_size;
4284 }4328 } else {
4285 }4329 const aliased_reg = registerAlias(
4286 },4330 c_abi_int_param_regs[next_int_reg],
4287 else => return self.fail(src, "TODO implement function parameters of type {s}", .{@tagName(ty.zigTypeTag())}),4331 param_size,
4332 );
4333 result.args[i] = .{ .register = aliased_reg };
4334 next_int_reg += 1;
4335 }
4336 } else {
4337 // For simplicity of codegen, slices and other types are always pushed onto the stack.
4338 // TODO: look into optimizing this by passing things as registers sometimes,
4339 // such as ptr and len of slices as separate registers.
4340 // TODO: also we need to honor the C ABI for relevant types rather than passing on
4341 // the stack here.
4342 result.args[i] = .{ .stack_offset = next_stack_offset };
4343 next_stack_offset += param_size;
4288 }4344 }
4289 }4345 }
4290 result.stack_byte_count = next_stack_offset;4346 result.stack_byte_count = next_stack_offset;
src/codegen/c.zig+285-68
...@@ -39,7 +39,12 @@ const BlockData = struct {...@@ -39,7 +39,12 @@ const BlockData = struct {
39};39};
4040
41pub const CValueMap = std.AutoHashMap(*Inst, CValue);41pub const CValueMap = std.AutoHashMap(*Inst, CValue);
42pub const TypedefMap = std.HashMap(Type, struct { name: []const u8, rendered: []u8 }, Type.HashContext, std.hash_map.default_max_load_percentage);42pub const TypedefMap = std.HashMap(
43 Type,
44 struct { name: []const u8, rendered: []u8 },
45 Type.HashContext,
46 std.hash_map.default_max_load_percentage,
47);
4348
44fn formatTypeAsCIdentifier(49fn formatTypeAsCIdentifier(
45 data: Type,50 data: Type,
...@@ -151,14 +156,49 @@ pub const Object = struct {...@@ -151,14 +156,49 @@ pub const Object = struct {
151 render_ty = render_ty.elemType();156 render_ty = render_ty.elemType();
152 }157 }
153158
154 try o.dg.renderType(w, render_ty);159 if (render_ty.zigTypeTag() == .Fn) {
155160 const ret_ty = render_ty.fnReturnType();
156 const const_prefix = switch (mutability) {161 if (ret_ty.zigTypeTag() == .NoReturn) {
157 .Const => "const ",162 // noreturn attribute is not allowed here.
158 .Mut => "",163 try w.writeAll("void");
159 };164 } else {
160 try w.print(" {s}", .{const_prefix});165 try o.dg.renderType(w, ret_ty);
161 try o.writeCValue(w, name);166 }
167 try w.writeAll(" (*");
168 switch (mutability) {
169 .Const => try w.writeAll("const "),
170 .Mut => {},
171 }
172 try o.writeCValue(w, name);
173 try w.writeAll(")(");
174 const param_len = render_ty.fnParamLen();
175 const is_var_args = render_ty.fnIsVarArgs();
176 if (param_len == 0 and !is_var_args)
177 try w.writeAll("void")
178 else {
179 var index: usize = 0;
180 while (index < param_len) : (index += 1) {
181 if (index > 0) {
182 try w.writeAll(", ");
183 }
184 try o.dg.renderType(w, render_ty.fnParamType(index));
185 }
186 }
187 if (is_var_args) {
188 if (param_len != 0) try w.writeAll(", ");
189 try w.writeAll("...");
190 }
191 try w.writeByte(')');
192 } else {
193 try o.dg.renderType(w, render_ty);
194
195 const const_prefix = switch (mutability) {
196 .Const => "const ",
197 .Mut => "",
198 };
199 try w.print(" {s}", .{const_prefix});
200 try o.writeCValue(w, name);
201 }
162 try w.writeAll(suffix.items);202 try w.writeAll(suffix.items);
163 }203 }
164};204};
...@@ -196,35 +236,72 @@ pub const DeclGen = struct {...@@ -196,35 +236,72 @@ pub const DeclGen = struct {
196 return writer.print("{d}", .{val.toSignedInt()});236 return writer.print("{d}", .{val.toSignedInt()});
197 return writer.print("{d}", .{val.toUnsignedInt()});237 return writer.print("{d}", .{val.toUnsignedInt()});
198 },238 },
199 .Pointer => switch (val.tag()) {239 .Pointer => switch (t.ptrSize()) {
200 .null_value, .zero => try writer.writeAll("NULL"),240 .Slice => {
201 .one => try writer.writeAll("1"),241 try writer.writeByte('(');
202 .decl_ref => {242 try dg.renderType(writer, t);
203 const decl = val.castTag(.decl_ref).?.data;243 try writer.writeAll("){");
204244 var buf: Type.Payload.ElemType = undefined;
205 // Determine if we must pointer cast.245 try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
206 assert(decl.has_tv);246 try writer.writeAll(", ");
207 if (t.eql(decl.ty)) {247 try writer.print("{d}", .{val.sliceLen()});
208 try writer.print("&{s}", .{decl.name});248 try writer.writeAll("}");
209 } else {
210 try writer.writeAll("(");
211 try dg.renderType(writer, t);
212 try writer.print(")&{s}", .{decl.name});
213 }
214 },
215 .function => {
216 const func = val.castTag(.function).?.data;
217 try writer.print("{s}", .{func.owner_decl.name});
218 },249 },
219 .extern_fn => {250 else => switch (val.tag()) {
220 const decl = val.castTag(.extern_fn).?.data;251 .null_value, .zero => try writer.writeAll("NULL"),
221 try writer.print("{s}", .{decl.name});252 .one => try writer.writeAll("1"),
253 .decl_ref => {
254 const decl = val.castTag(.decl_ref).?.data;
255
256 // Determine if we must pointer cast.
257 assert(decl.has_tv);
258 if (t.eql(decl.ty)) {
259 try writer.print("&{s}", .{decl.name});
260 } else {
261 try writer.writeAll("(");
262 try dg.renderType(writer, t);
263 try writer.print(")&{s}", .{decl.name});
264 }
265 },
266 .function => {
267 const func = val.castTag(.function).?.data;
268 try writer.print("{s}", .{func.owner_decl.name});
269 },
270 .extern_fn => {
271 const decl = val.castTag(.extern_fn).?.data;
272 try writer.print("{s}", .{decl.name});
273 },
274 else => switch (t.ptrSize()) {
275 .Slice => unreachable,
276 .Many => {
277 if (val.castTag(.ref_val)) |ref_val_payload| {
278 const sub_val = ref_val_payload.data;
279 if (sub_val.castTag(.bytes)) |bytes_payload| {
280 const bytes = bytes_payload.data;
281 try writer.writeByte('(');
282 try dg.renderType(writer, t);
283 // TODO: make our own C string escape instead of using std.zig.fmtEscapes
284 try writer.print(")\"{}\"", .{std.zig.fmtEscapes(bytes)});
285 } else {
286 unreachable;
287 }
288 } else {
289 unreachable;
290 }
291 },
292 .One => {
293 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
294 defer arena.deinit();
295
296 const elem_ty = t.elemType();
297 const elem_val = try val.pointerDeref(&arena.allocator);
298
299 try writer.writeAll("&");
300 try dg.renderValue(writer, elem_ty, elem_val);
301 },
302 .C => unreachable,
303 },
222 },304 },
223 else => |e| return dg.fail(
224 .{ .node_offset = 0 },
225 "TODO: C backend: implement Pointer value {s}",
226 .{@tagName(e)},
227 ),
228 },305 },
229 .Array => {306 .Array => {
230 // First try specific tag representations for more efficiency.307 // First try specific tag representations for more efficiency.
...@@ -283,6 +360,12 @@ pub const DeclGen = struct {...@@ -283,6 +360,12 @@ pub const DeclGen = struct {
283 const error_type = t.errorUnionSet();360 const error_type = t.errorUnionSet();
284 const payload_type = t.errorUnionChild();361 const payload_type = t.errorUnionChild();
285 const data = val.castTag(.error_union).?.data;362 const data = val.castTag(.error_union).?.data;
363
364 if (!payload_type.hasCodeGenBits()) {
365 // We use the error type directly as the type.
366 return dg.renderValue(writer, error_type, data);
367 }
368
286 try writer.writeByte('(');369 try writer.writeByte('(');
287 try dg.renderType(writer, t);370 try dg.renderType(writer, t);
288 try writer.writeAll("){");371 try writer.writeAll("){");
...@@ -329,6 +412,32 @@ pub const DeclGen = struct {...@@ -329,6 +412,32 @@ pub const DeclGen = struct {
329 },412 },
330 }413 }
331 },414 },
415 .Fn => switch (val.tag()) {
416 .null_value, .zero => try writer.writeAll("NULL"),
417 .one => try writer.writeAll("1"),
418 .decl_ref => {
419 const decl = val.castTag(.decl_ref).?.data;
420
421 // Determine if we must pointer cast.
422 assert(decl.has_tv);
423 if (t.eql(decl.ty)) {
424 try writer.print("&{s}", .{decl.name});
425 } else {
426 try writer.writeAll("(");
427 try dg.renderType(writer, t);
428 try writer.print(")&{s}", .{decl.name});
429 }
430 },
431 .function => {
432 const func = val.castTag(.function).?.data;
433 try writer.print("{s}", .{func.owner_decl.name});
434 },
435 .extern_fn => {
436 const decl = val.castTag(.extern_fn).?.data;
437 try writer.print("{s}", .{decl.name});
438 },
439 else => unreachable,
440 },
332 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{441 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
333 @tagName(e),442 @tagName(e),
334 }),443 }),
...@@ -339,6 +448,12 @@ pub const DeclGen = struct {...@@ -339,6 +448,12 @@ pub const DeclGen = struct {
339 if (!is_global) {448 if (!is_global) {
340 try w.writeAll("static ");449 try w.writeAll("static ");
341 }450 }
451 if (dg.decl.val.castTag(.function)) |func_payload| {
452 const func: *Module.Fn = func_payload.data;
453 if (func.is_cold) {
454 try w.writeAll("ZIG_COLD ");
455 }
456 }
342 try dg.renderType(w, dg.decl.ty.fnReturnType());457 try dg.renderType(w, dg.decl.ty.fnReturnType());
343 const decl_name = mem.span(dg.decl.name);458 const decl_name = mem.span(dg.decl.name);
344 try w.print(" {s}(", .{decl_name});459 try w.print(" {s}(", .{decl_name});
...@@ -413,7 +528,35 @@ pub const DeclGen = struct {...@@ -413,7 +528,35 @@ pub const DeclGen = struct {
413528
414 .Pointer => {529 .Pointer => {
415 if (t.isSlice()) {530 if (t.isSlice()) {
416 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});531 if (dg.typedefs.get(t)) |some| {
532 return w.writeAll(some.name);
533 }
534
535 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
536 defer buffer.deinit();
537 const bw = buffer.writer();
538
539 try bw.writeAll("typedef struct { ");
540 const elem_type = t.elemType();
541 try dg.renderType(bw, elem_type);
542 try bw.writeAll(" *");
543 if (t.isConstPtr()) {
544 try bw.writeAll("const ");
545 }
546 if (t.isVolatilePtr()) {
547 try bw.writeAll("volatile ");
548 }
549 try bw.writeAll("ptr; size_t len; } ");
550 const name_index = buffer.items.len;
551 try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)});
552
553 const rendered = buffer.toOwnedSlice();
554 errdefer dg.typedefs.allocator.free(rendered);
555 const name = rendered[name_index .. rendered.len - 2];
556
557 try dg.typedefs.ensureUnusedCapacity(1);
558 try w.writeAll(name);
559 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
417 } else {560 } else {
418 try dg.renderType(w, t.elemType());561 try dg.renderType(w, t.elemType());
419 try w.writeAll(" *");562 try w.writeAll(" *");
...@@ -446,13 +589,13 @@ pub const DeclGen = struct {...@@ -446,13 +589,13 @@ pub const DeclGen = struct {
446 try dg.renderType(bw, child_type);589 try dg.renderType(bw, child_type);
447 try bw.writeAll(" payload; bool is_null; } ");590 try bw.writeAll(" payload; bool is_null; } ");
448 const name_index = buffer.items.len;591 const name_index = buffer.items.len;
449 try bw.print("zig_opt_{s}_t;\n", .{typeToCIdentifier(child_type)});592 try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)});
450593
451 const rendered = buffer.toOwnedSlice();594 const rendered = buffer.toOwnedSlice();
452 errdefer dg.typedefs.allocator.free(rendered);595 errdefer dg.typedefs.allocator.free(rendered);
453 const name = rendered[name_index .. rendered.len - 2];596 const name = rendered[name_index .. rendered.len - 2];
454597
455 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);598 try dg.typedefs.ensureUnusedCapacity(1);
456 try w.writeAll(name);599 try w.writeAll(name);
457 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });600 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
458 },601 },
...@@ -465,7 +608,11 @@ pub const DeclGen = struct {...@@ -465,7 +608,11 @@ pub const DeclGen = struct {
465 return w.writeAll(some.name);608 return w.writeAll(some.name);
466 }609 }
467 const child_type = t.errorUnionChild();610 const child_type = t.errorUnionChild();
468 const set_type = t.errorUnionSet();611 const err_set_type = t.errorUnionSet();
612
613 if (!child_type.hasCodeGenBits()) {
614 return dg.renderType(w, err_set_type);
615 }
469616
470 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);617 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
471 defer buffer.deinit();618 defer buffer.deinit();
...@@ -475,13 +622,20 @@ pub const DeclGen = struct {...@@ -475,13 +622,20 @@ pub const DeclGen = struct {
475 try dg.renderType(bw, child_type);622 try dg.renderType(bw, child_type);
476 try bw.writeAll(" payload; uint16_t error; } ");623 try bw.writeAll(" payload; uint16_t error; } ");
477 const name_index = buffer.items.len;624 const name_index = buffer.items.len;
478 try bw.print("zig_err_union_{s}_{s}_t;\n", .{ typeToCIdentifier(set_type), typeToCIdentifier(child_type) });625 if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {
626 const func = inf_err_set_payload.data.func;
627 try bw.print("zig_E_{s};\n", .{func.owner_decl.name});
628 } else {
629 try bw.print("zig_E_{s}_{s};\n", .{
630 typeToCIdentifier(err_set_type), typeToCIdentifier(child_type),
631 });
632 }
479633
480 const rendered = buffer.toOwnedSlice();634 const rendered = buffer.toOwnedSlice();
481 errdefer dg.typedefs.allocator.free(rendered);635 errdefer dg.typedefs.allocator.free(rendered);
482 const name = rendered[name_index .. rendered.len - 2];636 const name = rendered[name_index .. rendered.len - 2];
483637
484 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);638 try dg.typedefs.ensureUnusedCapacity(1);
485 try w.writeAll(name);639 try w.writeAll(name);
486 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });640 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
487 },641 },
...@@ -514,7 +668,7 @@ pub const DeclGen = struct {...@@ -514,7 +668,7 @@ pub const DeclGen = struct {
514 errdefer dg.typedefs.allocator.free(rendered);668 errdefer dg.typedefs.allocator.free(rendered);
515 const name = rendered[name_start .. rendered.len - 2];669 const name = rendered[name_start .. rendered.len - 2];
516670
517 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);671 try dg.typedefs.ensureUnusedCapacity(1);
518 try w.writeAll(name);672 try w.writeAll(name);
519 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });673 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
520 },674 },
...@@ -526,7 +680,28 @@ pub const DeclGen = struct {...@@ -526,7 +680,28 @@ pub const DeclGen = struct {
526 try dg.renderType(w, int_tag_ty);680 try dg.renderType(w, int_tag_ty);
527 },681 },
528 .Union => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Union", .{}),682 .Union => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Union", .{}),
529 .Fn => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Fn", .{}),683 .Fn => {
684 try dg.renderType(w, t.fnReturnType());
685 try w.writeAll(" (*)(");
686 const param_len = t.fnParamLen();
687 const is_var_args = t.fnIsVarArgs();
688 if (param_len == 0 and !is_var_args)
689 try w.writeAll("void")
690 else {
691 var index: usize = 0;
692 while (index < param_len) : (index += 1) {
693 if (index > 0) {
694 try w.writeAll(", ");
695 }
696 try dg.renderType(w, t.fnParamType(index));
697 }
698 }
699 if (is_var_args) {
700 if (param_len != 0) try w.writeAll(", ");
701 try w.writeAll("...");
702 }
703 try w.writeByte(')');
704 },
530 .Opaque => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Opaque", .{}),705 .Opaque => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Opaque", .{}),
531 .Frame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Frame", .{}),706 .Frame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Frame", .{}),
532 .AnyFrame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type AnyFrame", .{}),707 .AnyFrame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type AnyFrame", .{}),
...@@ -569,23 +744,27 @@ pub fn genDecl(o: *Object) !void {...@@ -569,23 +744,27 @@ pub fn genDecl(o: *Object) !void {
569 .val = o.dg.decl.val,744 .val = o.dg.decl.val,
570 };745 };
571 if (tv.val.castTag(.function)) |func_payload| {746 if (tv.val.castTag(.function)) |func_payload| {
572 const is_global = o.dg.declIsGlobal(tv);
573 const fwd_decl_writer = o.dg.fwd_decl.writer();
574 if (is_global) {
575 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
576 }
577 try o.dg.renderFunctionSignature(fwd_decl_writer, is_global);
578 try fwd_decl_writer.writeAll(";\n");
579
580 const func: *Module.Fn = func_payload.data;747 const func: *Module.Fn = func_payload.data;
581 try o.indent_writer.insertNewline();748 if (func.owner_decl == o.dg.decl) {
582 try o.dg.renderFunctionSignature(o.writer(), is_global);749 const is_global = o.dg.declIsGlobal(tv);
750 const fwd_decl_writer = o.dg.fwd_decl.writer();
751 if (is_global) {
752 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
753 }
754 try o.dg.renderFunctionSignature(fwd_decl_writer, is_global);
755 try fwd_decl_writer.writeAll(";\n");
583756
584 try o.writer().writeByte(' ');757 try o.indent_writer.insertNewline();
585 try genBody(o, func.body);758 try o.dg.renderFunctionSignature(o.writer(), is_global);
586759
587 try o.indent_writer.insertNewline();760 try o.writer().writeByte(' ');
588 } else if (tv.val.tag() == .extern_fn) {761 try genBody(o, func.body);
762
763 try o.indent_writer.insertNewline();
764 return;
765 }
766 }
767 if (tv.val.tag() == .extern_fn) {
589 const writer = o.writer();768 const writer = o.writer();
590 try writer.writeAll("ZIG_EXTERN_C ");769 try writer.writeAll("ZIG_EXTERN_C ");
591 try o.dg.renderFunctionSignature(writer, true);770 try o.dg.renderFunctionSignature(writer, true);
...@@ -644,9 +823,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -644,9 +823,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
644 const is_global = dg.declIsGlobal(tv);823 const is_global = dg.declIsGlobal(tv);
645 if (is_global) {824 if (is_global) {
646 try writer.writeAll("ZIG_EXTERN_C ");825 try writer.writeAll("ZIG_EXTERN_C ");
826 try dg.renderFunctionSignature(writer, is_global);
827 try dg.fwd_decl.appendSlice(";\n");
647 }828 }
648 try dg.renderFunctionSignature(writer, is_global);
649 try dg.fwd_decl.appendSlice(";\n");
650 },829 },
651 else => {},830 else => {},
652 }831 }
...@@ -726,8 +905,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -726,8 +905,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
726 .ref => try genRef(o, inst.castTag(.ref).?),905 .ref => try genRef(o, inst.castTag(.ref).?),
727 .struct_field_ptr => try genStructFieldPtr(o, inst.castTag(.struct_field_ptr).?),906 .struct_field_ptr => try genStructFieldPtr(o, inst.castTag(.struct_field_ptr).?),
728907
729 .is_err => try genIsErr(o, inst.castTag(.is_err).?),908 .is_err => try genIsErr(o, inst.castTag(.is_err).?, "", ".", "!="),
730 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),909 .is_non_err => try genIsErr(o, inst.castTag(.is_non_err).?, "", ".", "=="),
910 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?, "*", "->", "!="),
911 .is_non_err_ptr => try genIsErr(o, inst.castTag(.is_non_err_ptr).?, "*", "->", "=="),
731912
732 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),913 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
733 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),914 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
...@@ -1213,9 +1394,25 @@ fn genStructFieldPtr(o: *Object, inst: *Inst.StructFieldPtr) !CValue {...@@ -1213,9 +1394,25 @@ fn genStructFieldPtr(o: *Object, inst: *Inst.StructFieldPtr) !CValue {
12131394
1214// *(E!T) -> E NOT *E1395// *(E!T) -> E NOT *E
1215fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {1396fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {
1397 if (inst.base.isUnused())
1398 return CValue.none;
1399
1216 const writer = o.writer();1400 const writer = o.writer();
1217 const operand = try o.resolveInst(inst.operand);1401 const operand = try o.resolveInst(inst.operand);
12181402
1403 const payload_ty = inst.operand.ty.errorUnionChild();
1404 if (!payload_ty.hasCodeGenBits()) {
1405 if (inst.operand.ty.zigTypeTag() == .Pointer) {
1406 const local = try o.allocLocal(inst.base.ty, .Const);
1407 try writer.writeAll(" = *");
1408 try o.writeCValue(writer, operand);
1409 try writer.writeAll(";\n");
1410 return local;
1411 } else {
1412 return operand;
1413 }
1414 }
1415
1219 const maybe_deref = if (inst.operand.ty.zigTypeTag() == .Pointer) "->" else ".";1416 const maybe_deref = if (inst.operand.ty.zigTypeTag() == .Pointer) "->" else ".";
12201417
1221 const local = try o.allocLocal(inst.base.ty, .Const);1418 const local = try o.allocLocal(inst.base.ty, .Const);
...@@ -1225,10 +1422,19 @@ fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -1225,10 +1422,19 @@ fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {
1225 try writer.print("){s}error;\n", .{maybe_deref});1422 try writer.print("){s}error;\n", .{maybe_deref});
1226 return local;1423 return local;
1227}1424}
1425
1228fn genUnwrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {1426fn genUnwrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {
1427 if (inst.base.isUnused())
1428 return CValue.none;
1429
1229 const writer = o.writer();1430 const writer = o.writer();
1230 const operand = try o.resolveInst(inst.operand);1431 const operand = try o.resolveInst(inst.operand);
12311432
1433 const payload_ty = inst.operand.ty.errorUnionChild();
1434 if (!payload_ty.hasCodeGenBits()) {
1435 return CValue.none;
1436 }
1437
1232 const maybe_deref = if (inst.operand.ty.zigTypeTag() == .Pointer) "->" else ".";1438 const maybe_deref = if (inst.operand.ty.zigTypeTag() == .Pointer) "->" else ".";
1233 const maybe_addrof = if (inst.base.ty.zigTypeTag() == .Pointer) "&" else "";1439 const maybe_addrof = if (inst.base.ty.zigTypeTag() == .Pointer) "&" else "";
12341440
...@@ -1277,15 +1483,26 @@ fn genWrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -1277,15 +1483,26 @@ fn genWrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {
1277 return local;1483 return local;
1278}1484}
12791485
1280fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {1486fn genIsErr(
1487 o: *Object,
1488 inst: *Inst.UnOp,
1489 deref_prefix: [*:0]const u8,
1490 deref_suffix: [*:0]const u8,
1491 op_str: [*:0]const u8,
1492) !CValue {
1281 const writer = o.writer();1493 const writer = o.writer();
1282 const maybe_deref = if (inst.base.tag == .is_err_ptr) "[0]" else "";
1283 const operand = try o.resolveInst(inst.operand);1494 const operand = try o.resolveInst(inst.operand);
1284
1285 const local = try o.allocLocal(Type.initTag(.bool), .Const);1495 const local = try o.allocLocal(Type.initTag(.bool), .Const);
1286 try writer.writeAll(" = (");1496 const payload_ty = inst.operand.ty.errorUnionChild();
1287 try o.writeCValue(writer, operand);1497 if (!payload_ty.hasCodeGenBits()) {
1288 try writer.print("){s}.error != 0;\n", .{maybe_deref});1498 try writer.print(" = {s}", .{deref_prefix});
1499 try o.writeCValue(writer, operand);
1500 try writer.print(" {s} 0;\n", .{op_str});
1501 } else {
1502 try writer.writeAll(" = ");
1503 try o.writeCValue(writer, operand);
1504 try writer.print("{s}error {s} 0;\n", .{ deref_suffix, op_str });
1505 }
1289 return local;1506 return local;
1290}1507}
12911508
src/codegen/wasm.zig+4-5
...@@ -814,7 +814,8 @@ pub const Context = struct {...@@ -814,7 +814,8 @@ pub const Context = struct {
814 .constant => unreachable,814 .constant => unreachable,
815 .dbg_stmt => WValue.none,815 .dbg_stmt => WValue.none,
816 .div => self.genBinOp(inst.castTag(.div).?, .div),816 .div => self.genBinOp(inst.castTag(.div).?, .div),
817 .is_err => self.genIsErr(inst.castTag(.is_err).?),817 .is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),
818 .is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),
818 .load => self.genLoad(inst.castTag(.load).?),819 .load => self.genLoad(inst.castTag(.load).?),
819 .loop => self.genLoop(inst.castTag(.loop).?),820 .loop => self.genLoop(inst.castTag(.loop).?),
820 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),821 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
...@@ -1278,7 +1279,7 @@ pub const Context = struct {...@@ -1278,7 +1279,7 @@ pub const Context = struct {
1278 return .none;1279 return .none;
1279 }1280 }
12801281
1281 fn genIsErr(self: *Context, inst: *Inst.UnOp) InnerError!WValue {1282 fn genIsErr(self: *Context, inst: *Inst.UnOp, opcode: wasm.Opcode) InnerError!WValue {
1282 const operand = self.resolveInst(inst.operand);1283 const operand = self.resolveInst(inst.operand);
1283 const offset = self.code.items.len;1284 const offset = self.code.items.len;
1284 const writer = self.code.writer();1285 const writer = self.code.writer();
...@@ -1289,9 +1290,7 @@ pub const Context = struct {...@@ -1289,9 +1290,7 @@ pub const Context = struct {
1289 try writer.writeByte(wasm.opcode(.i32_const));1290 try writer.writeByte(wasm.opcode(.i32_const));
1290 try leb.writeILEB128(writer, @as(i32, 0));1291 try leb.writeILEB128(writer, @as(i32, 0));
12911292
1292 // we want to break out of the condition if they're *not* equal,1293 try writer.writeByte(@enumToInt(opcode));
1293 // because that means there's an error.
1294 try writer.writeByte(wasm.opcode(.i32_ne));
12951294
1296 return WValue{ .code_offset = offset };1295 return WValue{ .code_offset = offset };
1297 }1296 }
src/link/C.zig+4-6
...@@ -207,7 +207,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -207,7 +207,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
207 }207 }
208208
209 var fn_count: usize = 0;209 var fn_count: usize = 0;
210 var typedefs = std.HashMap(Type, []const u8, Type.HashContext, std.hash_map.default_max_load_percentage).init(comp.gpa);210 var typedefs = std.HashMap(Type, void, Type.HashContext, std.hash_map.default_max_load_percentage).init(comp.gpa);
211 defer typedefs.deinit();211 defer typedefs.deinit();
212212
213 // Typedefs, forward decls and non-functions first.213 // Typedefs, forward decls and non-functions first.
...@@ -217,14 +217,12 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -217,14 +217,12 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
217 if (!decl.has_tv) continue;217 if (!decl.has_tv) continue;
218 const buf = buf: {218 const buf = buf: {
219 if (decl.val.castTag(.function)) |_| {219 if (decl.val.castTag(.function)) |_| {
220 try typedefs.ensureUnusedCapacity(decl.fn_link.c.typedefs.count());
220 var it = decl.fn_link.c.typedefs.iterator();221 var it = decl.fn_link.c.typedefs.iterator();
221 while (it.next()) |new| {222 while (it.next()) |new| {
222 if (typedefs.get(new.key_ptr.*)) |previous| {223 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);
223 try err_typedef_writer.print("typedef {s} {s};\n", .{ previous, new.value_ptr.name });224 if (!gop.found_existing) {
224 } else {
225 try typedefs.ensureCapacity(typedefs.capacity() + 1);
226 try err_typedef_writer.writeAll(new.value_ptr.rendered);225 try err_typedef_writer.writeAll(new.value_ptr.rendered);
227 typedefs.putAssumeCapacityNoClobber(new.key_ptr.*, new.value_ptr.name);
228 }226 }
229 }227 }
230 fn_count += 1;228 fn_count += 1;
src/link/C/zig.h+6
...@@ -12,6 +12,12 @@...@@ -12,6 +12,12 @@
12#define zig_threadlocal zig_threadlocal_unavailable12#define zig_threadlocal zig_threadlocal_unavailable
13#endif13#endif
1414
15#if __GNUC__
16#define ZIG_COLD __attribute__ ((cold))
17#else
18#define ZIG_COLD
19#endif
20
15#if __STDC_VERSION__ >= 199901L21#if __STDC_VERSION__ >= 199901L
16#define ZIG_RESTRICT restrict22#define ZIG_RESTRICT restrict
17#elif defined(__GNUC__)23#elif defined(__GNUC__)
src/link/Elf.zig+17-6
...@@ -2505,11 +2505,7 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo...@@ -2505,11 +2505,7 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo
2505 abbrev_base_type,2505 abbrev_base_type,
2506 DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data12506 DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1
2507 1, // DW.AT_byte_size, DW.FORM_data12507 1, // DW.AT_byte_size, DW.FORM_data1
2508 'b',2508 'b', 'o', 'o', 'l', 0, // DW.AT_name, DW.FORM_string
2509 'o',
2510 'o',
2511 'l',
2512 0, // DW.AT_name, DW.FORM_string
2513 });2509 });
2514 },2510 },
2515 .Int => {2511 .Int => {
...@@ -2526,8 +2522,23 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo...@@ -2526,8 +2522,23 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo
2526 // DW.AT_name, DW.FORM_string2522 // DW.AT_name, DW.FORM_string
2527 try dbg_info_buffer.writer().print("{}\x00", .{ty});2523 try dbg_info_buffer.writer().print("{}\x00", .{ty});
2528 },2524 },
2525 .Optional => {
2526 if (ty.isPtrLikeOptional()) {
2527 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12);
2528 dbg_info_buffer.appendAssumeCapacity(abbrev_base_type);
2529 // DW.AT_encoding, DW.FORM_data1
2530 dbg_info_buffer.appendAssumeCapacity(DW.ATE_address);
2531 // DW.AT_byte_size, DW.FORM_data1
2532 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target)));
2533 // DW.AT_name, DW.FORM_string
2534 try dbg_info_buffer.writer().print("{}\x00", .{ty});
2535 } else {
2536 log.err("TODO implement .debug_info for type '{}'", .{ty});
2537 try dbg_info_buffer.append(abbrev_pad1);
2538 }
2539 },
2529 else => {2540 else => {
2530 std.log.scoped(.compiler).err("TODO implement .debug_info for type '{}'", .{ty});2541 log.err("TODO implement .debug_info for type '{}'", .{ty});
2531 try dbg_info_buffer.append(abbrev_pad1);2542 try dbg_info_buffer.append(abbrev_pad1);
2532 },2543 },
2533 }2544 }
src/type.zig+82-3
...@@ -58,7 +58,7 @@ pub const Type = extern union {...@@ -58,7 +58,7 @@ pub const Type = extern union {
58 .bool => return .Bool,58 .bool => return .Bool,
59 .void => return .Void,59 .void => return .Void,
60 .type => return .Type,60 .type => return .Type,
61 .error_set, .error_set_single, .anyerror => return .ErrorSet,61 .error_set, .error_set_single, .anyerror, .error_set_inferred => return .ErrorSet,
62 .comptime_int => return .ComptimeInt,62 .comptime_int => return .ComptimeInt,
63 .comptime_float => return .ComptimeFloat,63 .comptime_float => return .ComptimeFloat,
64 .noreturn => return .NoReturn,64 .noreturn => return .NoReturn,
...@@ -689,7 +689,15 @@ pub const Type = extern union {...@@ -689,7 +689,15 @@ pub const Type = extern union {
689 .optional_single_mut_pointer,689 .optional_single_mut_pointer,
690 .optional_single_const_pointer,690 .optional_single_const_pointer,
691 .anyframe_T,691 .anyframe_T,
692 => return self.copyPayloadShallow(allocator, Payload.ElemType),692 => {
693 const payload = self.cast(Payload.ElemType).?;
694 const new_payload = try allocator.create(Payload.ElemType);
695 new_payload.* = .{
696 .base = .{ .tag = payload.base.tag },
697 .data = try payload.data.copy(allocator),
698 };
699 return Type{ .ptr_otherwise = &new_payload.base };
700 },
693701
694 .int_signed,702 .int_signed,
695 .int_unsigned,703 .int_unsigned,
...@@ -756,6 +764,7 @@ pub const Type = extern union {...@@ -756,6 +764,7 @@ pub const Type = extern union {
756 });764 });
757 },765 },
758 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),766 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
767 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
759 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),768 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
760 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),769 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
761 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),770 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
...@@ -1031,6 +1040,10 @@ pub const Type = extern union {...@@ -1031,6 +1040,10 @@ pub const Type = extern union {
1031 const error_set = ty.castTag(.error_set).?.data;1040 const error_set = ty.castTag(.error_set).?.data;
1032 return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));1041 return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));
1033 },1042 },
1043 .error_set_inferred => {
1044 const func = ty.castTag(.error_set_inferred).?.data.func;
1045 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
1046 },
1034 .error_set_single => {1047 .error_set_single => {
1035 const name = ty.castTag(.error_set_single).?.data;1048 const name = ty.castTag(.error_set_single).?.data;
1036 return writer.print("error{{{s}}}", .{name});1049 return writer.print("error{{{s}}}", .{name});
...@@ -1144,6 +1157,7 @@ pub const Type = extern union {...@@ -1144,6 +1157,7 @@ pub const Type = extern union {
1144 .anyerror_void_error_union,1157 .anyerror_void_error_union,
1145 .error_set,1158 .error_set,
1146 .error_set_single,1159 .error_set_single,
1160 .error_set_inferred,
1147 .manyptr_u8,1161 .manyptr_u8,
1148 .manyptr_const_u8,1162 .manyptr_const_u8,
1149 .atomic_ordering,1163 .atomic_ordering,
...@@ -1161,6 +1175,9 @@ pub const Type = extern union {...@@ -1161,6 +1175,9 @@ pub const Type = extern union {
1161 .@"struct" => {1175 .@"struct" => {
1162 // TODO introduce lazy value mechanism1176 // TODO introduce lazy value mechanism
1163 const struct_obj = self.castTag(.@"struct").?.data;1177 const struct_obj = self.castTag(.@"struct").?.data;
1178 assert(struct_obj.status == .have_field_types or
1179 struct_obj.status == .layout_wip or
1180 struct_obj.status == .have_layout);
1164 for (struct_obj.fields.values()) |value| {1181 for (struct_obj.fields.values()) |value| {
1165 if (value.ty.hasCodeGenBits())1182 if (value.ty.hasCodeGenBits())
1166 return true;1183 return true;
...@@ -1348,6 +1365,7 @@ pub const Type = extern union {...@@ -1348,6 +1365,7 @@ pub const Type = extern union {
1348 .error_set_single,1365 .error_set_single,
1349 .anyerror_void_error_union,1366 .anyerror_void_error_union,
1350 .anyerror,1367 .anyerror,
1368 .error_set_inferred,
1351 => return 2, // TODO revisit this when we have the concept of the error tag type1369 => return 2, // TODO revisit this when we have the concept of the error tag type
13521370
1353 .array, .array_sentinel => return self.elemType().abiAlignment(target),1371 .array, .array_sentinel => return self.elemType().abiAlignment(target),
...@@ -1580,6 +1598,7 @@ pub const Type = extern union {...@@ -1580,6 +1598,7 @@ pub const Type = extern union {
1580 .error_set_single,1598 .error_set_single,
1581 .anyerror_void_error_union,1599 .anyerror_void_error_union,
1582 .anyerror,1600 .anyerror,
1601 .error_set_inferred,
1583 => return 2, // TODO revisit this when we have the concept of the error tag type1602 => return 2, // TODO revisit this when we have the concept of the error tag type
15841603
1585 .int_signed, .int_unsigned => {1604 .int_signed, .int_unsigned => {
...@@ -1744,6 +1763,7 @@ pub const Type = extern union {...@@ -1744,6 +1763,7 @@ pub const Type = extern union {
1744 .error_set_single,1763 .error_set_single,
1745 .anyerror_void_error_union,1764 .anyerror_void_error_union,
1746 .anyerror,1765 .anyerror,
1766 .error_set_inferred,
1747 => return 16, // TODO revisit this when we have the concept of the error tag type1767 => return 16, // TODO revisit this when we have the concept of the error tag type
17481768
1749 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,1769 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
...@@ -1863,6 +1883,48 @@ pub const Type = extern union {...@@ -1863,6 +1883,48 @@ pub const Type = extern union {
1863 };1883 };
1864 }1884 }
18651885
1886 pub fn slicePtrFieldType(self: Type, buffer: *Payload.ElemType) Type {
1887 switch (self.tag()) {
1888 .const_slice_u8 => return Type.initTag(.manyptr_const_u8),
1889
1890 .const_slice => {
1891 const elem_type = self.castTag(.const_slice).?.data;
1892 buffer.* = .{
1893 .base = .{ .tag = .many_const_pointer },
1894 .data = elem_type,
1895 };
1896 return Type.initPayload(&buffer.base);
1897 },
1898 .mut_slice => {
1899 const elem_type = self.castTag(.mut_slice).?.data;
1900 buffer.* = .{
1901 .base = .{ .tag = .many_mut_pointer },
1902 .data = elem_type,
1903 };
1904 return Type.initPayload(&buffer.base);
1905 },
1906
1907 .pointer => {
1908 const payload = self.castTag(.pointer).?.data;
1909 assert(payload.size == .Slice);
1910 if (payload.mutable) {
1911 buffer.* = .{
1912 .base = .{ .tag = .many_mut_pointer },
1913 .data = payload.pointee_type,
1914 };
1915 } else {
1916 buffer.* = .{
1917 .base = .{ .tag = .many_const_pointer },
1918 .data = payload.pointee_type,
1919 };
1920 }
1921 return Type.initPayload(&buffer.base);
1922 },
1923
1924 else => unreachable,
1925 }
1926 }
1927
1866 pub fn isConstPtr(self: Type) bool {1928 pub fn isConstPtr(self: Type) bool {
1867 return switch (self.tag()) {1929 return switch (self.tag()) {
1868 .single_const_pointer,1930 .single_const_pointer,
...@@ -1915,7 +1977,10 @@ pub const Type = extern union {...@@ -1915,7 +1977,10 @@ pub const Type = extern union {
1915 /// Asserts that the type is an optional1977 /// Asserts that the type is an optional
1916 pub fn isPtrLikeOptional(self: Type) bool {1978 pub fn isPtrLikeOptional(self: Type) bool {
1917 switch (self.tag()) {1979 switch (self.tag()) {
1918 .optional_single_const_pointer, .optional_single_mut_pointer => return true,1980 .optional_single_const_pointer,
1981 .optional_single_mut_pointer,
1982 => return true,
1983
1919 .optional => {1984 .optional => {
1920 var buf: Payload.ElemType = undefined;1985 var buf: Payload.ElemType = undefined;
1921 const child_type = self.optionalChild(&buf);1986 const child_type = self.optionalChild(&buf);
...@@ -2400,6 +2465,7 @@ pub const Type = extern union {...@@ -2400,6 +2465,7 @@ pub const Type = extern union {
2400 .error_union,2465 .error_union,
2401 .error_set,2466 .error_set,
2402 .error_set_single,2467 .error_set_single,
2468 .error_set_inferred,
2403 .@"opaque",2469 .@"opaque",
2404 .var_args_param,2470 .var_args_param,
2405 .manyptr_u8,2471 .manyptr_u8,
...@@ -2892,6 +2958,8 @@ pub const Type = extern union {...@@ -2892,6 +2958,8 @@ pub const Type = extern union {
2892 anyframe_T,2958 anyframe_T,
2893 error_set,2959 error_set,
2894 error_set_single,2960 error_set_single,
2961 /// The type is the inferred error set of a specific function.
2962 error_set_inferred,
2895 empty_struct,2963 empty_struct,
2896 @"opaque",2964 @"opaque",
2897 @"struct",2965 @"struct",
...@@ -2989,6 +3057,7 @@ pub const Type = extern union {...@@ -2989,6 +3057,7 @@ pub const Type = extern union {
2989 => Payload.Bits,3057 => Payload.Bits,
29903058
2991 .error_set => Payload.ErrorSet,3059 .error_set => Payload.ErrorSet,
3060 .error_set_inferred => Payload.ErrorSetInferred,
29923061
2993 .array, .vector => Payload.Array,3062 .array, .vector => Payload.Array,
2994 .array_sentinel => Payload.ArraySentinel,3063 .array_sentinel => Payload.ArraySentinel,
...@@ -3081,6 +3150,16 @@ pub const Type = extern union {...@@ -3081,6 +3150,16 @@ pub const Type = extern union {
3081 data: *Module.ErrorSet,3150 data: *Module.ErrorSet,
3082 };3151 };
30833152
3153 pub const ErrorSetInferred = struct {
3154 pub const base_tag = Tag.error_set_inferred;
3155
3156 base: Payload = Payload{ .tag = base_tag },
3157 data: struct {
3158 func: *Module.Fn,
3159 map: std.StringHashMapUnmanaged(void),
3160 },
3161 };
3162
3084 pub const Pointer = struct {3163 pub const Pointer = struct {
3085 pub const base_tag = Tag.pointer;3164 pub const base_tag = Tag.pointer;
30863165
src/value.zig+22-5
...@@ -483,13 +483,13 @@ pub const Value = extern union {...@@ -483,13 +483,13 @@ pub const Value = extern union {
483 /// TODO this should become a debug dump() function. In order to print values in a meaningful way483 /// TODO this should become a debug dump() function. In order to print values in a meaningful way
484 /// we also need access to the type.484 /// we also need access to the type.
485 pub fn format(485 pub fn format(
486 self: Value,486 start_val: Value,
487 comptime fmt: []const u8,487 comptime fmt: []const u8,
488 options: std.fmt.FormatOptions,488 options: std.fmt.FormatOptions,
489 out_stream: anytype,489 out_stream: anytype,
490 ) !void {490 ) !void {
491 comptime assert(fmt.len == 0);491 comptime assert(fmt.len == 0);
492 var val = self;492 var val = start_val;
493 while (true) switch (val.tag()) {493 while (true) switch (val.tag()) {
494 .u8_type => return out_stream.writeAll("u8"),494 .u8_type => return out_stream.writeAll("u8"),
495 .i8_type => return out_stream.writeAll("i8"),495 .i8_type => return out_stream.writeAll("i8"),
...@@ -598,9 +598,9 @@ pub const Value = extern union {...@@ -598,9 +598,9 @@ pub const Value = extern union {
598 val = field_ptr.container_ptr;598 val = field_ptr.container_ptr;
599 },599 },
600 .empty_array => return out_stream.writeAll(".{}"),600 .empty_array => return out_stream.writeAll(".{}"),
601 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),601 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
602 .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),602 .enum_field_index => return out_stream.print("(enum field {d})", .{val.castTag(.enum_field_index).?.data}),
603 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),603 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
604 .repeated => {604 .repeated => {
605 try out_stream.writeAll("(repeated) ");605 try out_stream.writeAll("(repeated) ");
606 val = val.castTag(.repeated).?.data;606 val = val.castTag(.repeated).?.data;
...@@ -1336,6 +1336,23 @@ pub const Value = extern union {...@@ -1336,6 +1336,23 @@ pub const Value = extern union {
1336 };1336 };
1337 }1337 }
13381338
1339 pub fn sliceLen(val: Value) u64 {
1340 return switch (val.tag()) {
1341 .empty_array => 0,
1342 .bytes => val.castTag(.bytes).?.data.len,
1343 .ref_val => sliceLen(val.castTag(.ref_val).?.data),
1344 .decl_ref => {
1345 const decl = val.castTag(.decl_ref).?.data;
1346 if (decl.ty.zigTypeTag() == .Array) {
1347 return decl.ty.arrayLen();
1348 } else {
1349 return 1;
1350 }
1351 },
1352 else => unreachable,
1353 };
1354 }
1355
1339 /// Asserts the value is a single-item pointer to an array, or an array,1356 /// Asserts the value is a single-item pointer to an array, or an array,
1340 /// or an unknown-length pointer, and returns the element value at the index.1357 /// or an unknown-length pointer, and returns the element value at the index.
1341 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {1358 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
test/stage2/cbe.zig+20-13
...@@ -804,19 +804,26 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -804,19 +804,26 @@ pub fn addCases(ctx: *TestContext) !void {
804 });804 });
805 }805 }
806806
807 ctx.c("empty start function", linux_x64,807 {
808 \\export fn _start() noreturn {808 var case = ctx.exeFromCompiledC("inferred error sets", .{});
809 \\ unreachable;809
810 \\}810 case.addCompareOutput(
811 ,811 \\pub export fn main() c_int {
812 \\ZIG_EXTERN_C zig_noreturn void _start(void);812 \\ if (foo()) |_| {
813 \\813 \\ @panic("test fail");
814 \\zig_noreturn void _start(void) {814 \\ } else |err| {
815 \\ zig_breakpoint();815 \\ if (err != error.ItBroke) {
816 \\ zig_unreachable();816 \\ @panic("test fail");
817 \\}817 \\ }
818 \\818 \\ }
819 );819 \\ return 0;
820 \\}
821 \\fn foo() !void {
822 \\ return error.ItBroke;
823 \\}
824 , "");
825 }
826
820 ctx.h("simple header", linux_x64,827 ctx.h("simple header", linux_x64,
821 \\export fn start() void{}828 \\export fn start() void{}
822 ,829 ,
test/stage2/wasm.zig-2
...@@ -587,8 +587,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -587,8 +587,6 @@ pub fn addCases(ctx: *TestContext) !void {
587 }587 }
588588
589 {589 {
590 // TODO implement Type equality comparison of error unions in SEMA
591 // before we can incrementally compile functions with an error union as return type
592 var case = ctx.exe("wasm error union part 2", wasi);590 var case = ctx.exe("wasm error union part 2", wasi);
593591
594 case.addCompareOutput(592 case.addCompareOutput(