authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-07 19:50:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-07 19:50:56-07:00
log5c8bd443d92c6306f60857720103ae46ca7b8b3e
treefbac6bd8a6d337ef035b07ef766b3718f91e0781
parent5816997ae79c6025d5f85aab0c9ab456fecadec9

stage2: fix if expressions on error unions

AstGen had the then-else logic backwards for if expressions on error unions. This commit fixes it. Turns out AstGen only really needs `is_non_null` and `is_non_err`, and does not need the `is_null` or `is_err` variants. So I removed the `is_null{,_ptr}` and `is_err{,_ptr}` ZIR instructions (-4) and added `is_non_err`, `is_non_err_ptr` ZIR instructions (+2) for a total of (-2) ZIR instructions, giving us a tiny bit more headroom within the 256 tag limit. This required swapping the order of then/else blocks in a handful of cases, but ultimately means the ZIR will be in the same as source order, which is convenient when debugging. AIR code on the other hand, gains the `is_non_err` and `is_non_err_ptr` instructions. Sema: fix logic in zirErrUnionCode and zirErrUnionCodePtr returning the wrong result type.

7 files changed, 119 insertions(+), 104 deletions(-)

src/AstGen.zig+46-46
...@@ -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,
...@@ -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,
...@@ -4621,8 +4619,8 @@ fn tryExpr(...@@ -4621,8 +4619,8 @@ fn tryExpr(
4621 };4619 };
4622 const err_ops = switch (rl) {4620 const err_ops = switch (rl) {
4623 // zig fmt: off4621 // zig fmt: off
4624 .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 },
4625 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 },
4626 // zig fmt: on4624 // zig fmt: on
4627 };4625 };
4628 // 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.
...@@ -4640,21 +4638,21 @@ fn tryExpr(...@@ -4640,21 +4638,21 @@ fn tryExpr(
4640 var then_scope = parent_gz.makeSubBlock(scope);4638 var then_scope = parent_gz.makeSubBlock(scope);
4641 defer then_scope.instructions.deinit(astgen.gpa);4639 defer then_scope.instructions.deinit(astgen.gpa);
46424640
4643 const err_code = try then_scope.addUnNode(err_ops[1], operand, node);
4644 try genDefers(&then_scope, &fn_block.base, scope, .{ .both = err_code });
4645 const then_result = try then_scope.addUnNode(.ret_node, err_code, node);
4646
4647 var else_scope = parent_gz.makeSubBlock(scope);
4648 defer else_scope.instructions.deinit(astgen.gpa);
4649
4650 block_scope.break_count += 1;4641 block_scope.break_count += 1;
4651 // 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]`.
4652 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);
4653 const else_result = switch (rl) {4644 const then_result = switch (rl) {
4654 .ref => unwrapped_payload,4645 .ref => unwrapped_payload,
4655 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),
4656 };4647 };
46574648
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
4658 return finishThenElseBlock(4656 return finishThenElseBlock(
4659 parent_gz,4657 parent_gz,
4660 rl,4658 rl,
...@@ -4711,18 +4709,28 @@ fn orelseCatchExpr(...@@ -4711,18 +4709,28 @@ fn orelseCatchExpr(
4711 var then_scope = parent_gz.makeSubBlock(scope);4709 var then_scope = parent_gz.makeSubBlock(scope);
4712 defer then_scope.instructions.deinit(astgen.gpa);4710 defer then_scope.instructions.deinit(astgen.gpa);
47134711
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
4714 var err_val_scope: Scope.LocalVal = undefined;4722 var err_val_scope: Scope.LocalVal = undefined;
4715 const then_sub_scope = blk: {4723 const else_sub_scope = blk: {
4716 const payload = payload_token orelse break :blk &then_scope.base;4724 const payload = payload_token orelse break :blk &else_scope.base;
4717 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {4725 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
4718 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});4726 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
4719 }4727 }
4720 const err_name = try astgen.identAsString(payload);4728 const err_name = try astgen.identAsString(payload);
4721 err_val_scope = .{4729 err_val_scope = .{
4722 .parent = &then_scope.base,4730 .parent = &else_scope.base,
4723 .gen_zir = &then_scope,4731 .gen_zir = &else_scope,
4724 .name = err_name,4732 .name = err_name,
4725 .inst = try then_scope.addUnNode(unwrap_code_op, operand, node),4733 .inst = try else_scope.addUnNode(unwrap_code_op, operand, node),
4726 .token_src = payload,4734 .token_src = payload,
4727 .id_cat = .@"capture",4735 .id_cat = .@"capture",
4728 };4736 };
...@@ -4730,23 +4738,13 @@ fn orelseCatchExpr(...@@ -4730,23 +4738,13 @@ fn orelseCatchExpr(
4730 };4738 };
47314739
4732 block_scope.break_count += 1;4740 block_scope.break_count += 1;
4733 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);
4734 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);4742 try checkUsed(parent_gz, &else_scope.base, else_sub_scope);
47354743
4736 // 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
4737 // 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
4738 // instructions or not.4746 // instructions or not.
47394747
4740 var else_scope = parent_gz.makeSubBlock(scope);
4741 defer else_scope.instructions.deinit(astgen.gpa);
4742
4743 // This could be a pointer or value depending on `unwrap_op`.
4744 const unwrapped_payload = try else_scope.addUnNode(unwrap_op, operand, node);
4745 const else_result = switch (rl) {
4746 .ref => unwrapped_payload,
4747 else => try rvalue(&else_scope, block_scope.break_result_loc, unwrapped_payload, node),
4748 };
4749
4750 return finishThenElseBlock(4748 return finishThenElseBlock(
4751 parent_gz,4749 parent_gz,
4752 rl,4750 rl,
...@@ -4964,7 +4962,7 @@ fn ifExpr(...@@ -4964,7 +4962,7 @@ fn ifExpr(
4964 if (if_full.error_token) |_| {4962 if (if_full.error_token) |_| {
4965 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;4963 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
4966 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);
4967 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;
4968 break :c .{4966 break :c .{
4969 .inst = err_union,4967 .inst = err_union,
4970 .bool_bit = try block_scope.addUnNode(tag, err_union, node),4968 .bool_bit = try block_scope.addUnNode(tag, err_union, node),
...@@ -5221,7 +5219,7 @@ fn whileExpr(...@@ -5221,7 +5219,7 @@ fn whileExpr(
5221 if (while_full.error_token) |_| {5219 if (while_full.error_token) |_| {
5222 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;5220 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
5223 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);
5224 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;
5225 break :c .{5223 break :c .{
5226 .inst = err_union,5224 .inst = err_union,
5227 .bool_bit = try continue_scope.addUnNode(tag, err_union, node),5225 .bool_bit = try continue_scope.addUnNode(tag, err_union, node),
...@@ -6229,23 +6227,25 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6229,23 +6227,25 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref
6229 }6227 }
62306228
6231 // Emit conditional branch for generating errdefers.6229 // Emit conditional branch for generating errdefers.
6232 const is_err = try gz.addUnNode(.is_err, operand, node);6230 const is_non_err = try gz.addUnNode(.is_non_err, operand, node);
6233 const condbr = try gz.addCondBr(.condbr, node);6231 const condbr = try gz.addCondBr(.condbr, node);
62346232
6235 var then_scope = gz.makeSubBlock(scope);6233 var then_scope = gz.makeSubBlock(scope);
6236 defer then_scope.instructions.deinit(astgen.gpa);6234 defer then_scope.instructions.deinit(astgen.gpa);
6237 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{6235
6238 .both = try then_scope.addUnNode(.err_union_code, operand, node),6236 try genDefers(&then_scope, defer_outer, scope, .normal_only);
6239 };
6240 try genDefers(&then_scope, defer_outer, scope, which_ones);
6241 _ = try then_scope.addUnNode(.ret_node, operand, node);6237 _ = try then_scope.addUnNode(.ret_node, operand, node);
62426238
6243 var else_scope = gz.makeSubBlock(scope);6239 var else_scope = gz.makeSubBlock(scope);
6244 defer else_scope.instructions.deinit(astgen.gpa);6240 defer else_scope.instructions.deinit(astgen.gpa);
6245 try genDefers(&else_scope, defer_outer, scope, .normal_only);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);
6246 _ = try else_scope.addUnNode(.ret_node, operand, node);6246 _ = try else_scope.addUnNode(.ret_node, operand, node);
62476247
6248 try setCondBrPayload(condbr, is_err, &then_scope, &else_scope);6248 try setCondBrPayload(condbr, is_non_err, &then_scope, &else_scope);
62496249
6250 return Zir.Inst.Ref.unreachable_value;6250 return Zir.Inst.Ref.unreachable_value;
6251 },6251 },
src/Sema.zig+30-25
...@@ -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),
...@@ -2981,17 +2979,19 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner...@@ -2981,17 +2979,19 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
2981 if (operand.ty.zigTypeTag() != .ErrorUnion)2979 if (operand.ty.zigTypeTag() != .ErrorUnion)
2982 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});
29832981
2982 const result_ty = operand.ty.castTag(.error_union).?.data.error_set;
2983
2984 if (operand.value()) |val| {2984 if (operand.value()) |val| {
2985 assert(val.getError() != null);2985 assert(val.getError() != null);
2986 const data = val.castTag(.error_union).?.data;2986 const data = val.castTag(.error_union).?.data;
2987 return sema.mod.constInst(sema.arena, src, .{2987 return sema.mod.constInst(sema.arena, src, .{
2988 .ty = operand.ty.castTag(.error_union).?.data.error_set,2988 .ty = result_ty,
2989 .val = data,2989 .val = data,
2990 });2990 });
2991 }2991 }
29922992
2993 try sema.requireRuntimeBlock(block, src);2993 try sema.requireRuntimeBlock(block, src);
2994 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);
2995}2995}
29962996
2997/// Pointer in, value out2997/// Pointer in, value out
...@@ -3007,18 +3007,20 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In...@@ -3007,18 +3007,20 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
3007 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)3007 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
3008 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()});
30093009
3010 const result_ty = operand.ty.elemType().castTag(.error_union).?.data.error_set;
3011
3010 if (operand.value()) |pointer_val| {3012 if (operand.value()) |pointer_val| {
3011 const val = try pointer_val.pointerDeref(sema.arena);3013 const val = try pointer_val.pointerDeref(sema.arena);
3012 assert(val.getError() != null);3014 assert(val.getError() != null);
3013 const data = val.castTag(.error_union).?.data;3015 const data = val.castTag(.error_union).?.data;
3014 return sema.mod.constInst(sema.arena, src, .{3016 return sema.mod.constInst(sema.arena, src, .{
3015 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,3017 .ty = result_ty,
3016 .val = data,3018 .val = data,
3017 });3019 });
3018 }3020 }
30193021
3020 try sema.requireRuntimeBlock(block, src);3022 try sema.requireRuntimeBlock(block, src);
3021 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);
3022}3024}
30233025
3024fn 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 {
...@@ -5298,11 +5300,10 @@ fn zirBoolBr(...@@ -5298,11 +5300,10 @@ fn zirBoolBr(
5298 return &block_inst.base;5300 return &block_inst.base;
5299}5301}
53005302
5301fn zirIsNull(5303fn zirIsNonNull(
5302 sema: *Sema,5304 sema: *Sema,
5303 block: *Scope.Block,5305 block: *Scope.Block,
5304 inst: Zir.Inst.Index,5306 inst: Zir.Inst.Index,
5305 invert_logic: bool,
5306) InnerError!*Inst {5307) InnerError!*Inst {
5307 const tracy = trace(@src());5308 const tracy = trace(@src());
5308 defer tracy.end();5309 defer tracy.end();
...@@ -5310,14 +5311,13 @@ fn zirIsNull(...@@ -5310,14 +5311,13 @@ fn zirIsNull(
5310 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5311 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5311 const src = inst_data.src();5312 const src = inst_data.src();
5312 const operand = try sema.resolveInst(inst_data.operand);5313 const operand = try sema.resolveInst(inst_data.operand);
5313 return sema.analyzeIsNull(block, src, operand, invert_logic);5314 return sema.analyzeIsNull(block, src, operand, true);
5314}5315}
53155316
5316fn zirIsNullPtr(5317fn zirIsNonNullPtr(
5317 sema: *Sema,5318 sema: *Sema,
5318 block: *Scope.Block,5319 block: *Scope.Block,
5319 inst: Zir.Inst.Index,5320 inst: Zir.Inst.Index,
5320 invert_logic: bool,
5321) InnerError!*Inst {5321) InnerError!*Inst {
5322 const tracy = trace(@src());5322 const tracy = trace(@src());
5323 defer tracy.end();5323 defer tracy.end();
...@@ -5326,19 +5326,19 @@ fn zirIsNullPtr(...@@ -5326,19 +5326,19 @@ fn zirIsNullPtr(
5326 const src = inst_data.src();5326 const src = inst_data.src();
5327 const ptr = try sema.resolveInst(inst_data.operand);5327 const ptr = try sema.resolveInst(inst_data.operand);
5328 const loaded = try sema.analyzeLoad(block, src, ptr, src);5328 const loaded = try sema.analyzeLoad(block, src, ptr, src);
5329 return sema.analyzeIsNull(block, src, loaded, invert_logic);5329 return sema.analyzeIsNull(block, src, loaded, true);
5330}5330}
53315331
5332fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {5332fn zirIsNonErr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
5333 const tracy = trace(@src());5333 const tracy = trace(@src());
5334 defer tracy.end();5334 defer tracy.end();
53355335
5336 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5336 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5337 const operand = try sema.resolveInst(inst_data.operand);5337 const operand = try sema.resolveInst(inst_data.operand);
5338 return sema.analyzeIsErr(block, inst_data.src(), operand);5338 return sema.analyzeIsNonErr(block, inst_data.src(), operand);
5339}5339}
53405340
5341fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {5341fn zirIsNonErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
5342 const tracy = trace(@src());5342 const tracy = trace(@src());
5343 defer tracy.end();5343 defer tracy.end();
53445344
...@@ -5346,7 +5346,7 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro...@@ -5346,7 +5346,7 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
5346 const src = inst_data.src();5346 const src = inst_data.src();
5347 const ptr = try sema.resolveInst(inst_data.operand);5347 const ptr = try sema.resolveInst(inst_data.operand);
5348 const loaded = try sema.analyzeLoad(block, src, ptr, src);5348 const loaded = try sema.analyzeLoad(block, src, ptr, src);
5349 return sema.analyzeIsErr(block, src, loaded);5349 return sema.analyzeIsNonErr(block, src, loaded);
5350}5350}
53515351
5352fn zirCondbr(5352fn zirCondbr(
...@@ -7219,20 +7219,25 @@ fn analyzeIsNull(...@@ -7219,20 +7219,25 @@ fn analyzeIsNull(
7219 return block.addUnOp(src, result_ty, inst_tag, operand);7219 return block.addUnOp(src, result_ty, inst_tag, operand);
7220}7220}
72217221
7222fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst {7222fn analyzeIsNonErr(
7223 sema: *Sema,
7224 block: *Scope.Block,
7225 src: LazySrcLoc,
7226 operand: *Inst,
7227) InnerError!*Inst {
7223 const ot = operand.ty.zigTypeTag();7228 const ot = operand.ty.zigTypeTag();
7224 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false);7229 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, true);
7225 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true);7230 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, false);
7226 assert(ot == .ErrorUnion);7231 assert(ot == .ErrorUnion);
7227 const result_ty = Type.initTag(.bool);7232 const result_ty = Type.initTag(.bool);
7228 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {7233 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {
7229 if (err_union.isUndef()) {7234 if (err_union.isUndef()) {
7230 return sema.mod.constUndef(sema.arena, src, result_ty);7235 return sema.mod.constUndef(sema.arena, src, result_ty);
7231 }7236 }
7232 return sema.mod.constBool(sema.arena, src, err_union.getError() != null);7237 return sema.mod.constBool(sema.arena, src, err_union.getError() == null);
7233 }7238 }
7234 try sema.requireRuntimeBlock(block, src);7239 try sema.requireRuntimeBlock(block, src);
7235 return block.addUnOp(src, result_ty, .is_err, operand);7240 return block.addUnOp(src, result_ty, .is_non_err, operand);
7236}7241}
72377242
7238fn analyzeSlice(7243fn analyzeSlice(
src/Zir.zig+10-22
...@@ -398,21 +398,15 @@ pub const Inst = struct {...@@ -398,21 +398,15 @@ 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.
...@@ -1046,11 +1040,9 @@ pub const Inst = struct {...@@ -1046,11 +1040,9 @@ pub const Inst = struct {
1046 .float128,1040 .float128,
1047 .int_type,1041 .int_type,
1048 .is_non_null,1042 .is_non_null,
1049 .is_null,
1050 .is_non_null_ptr,1043 .is_non_null_ptr,
1051 .is_null_ptr,1044 .is_non_err,
1052 .is_err,1045 .is_non_err_ptr,
1053 .is_err_ptr,
1054 .mod_rem,1046 .mod_rem,
1055 .mul,1047 .mul,
1056 .mulwrap,1048 .mulwrap,
...@@ -1306,11 +1298,9 @@ pub const Inst = struct {...@@ -1306,11 +1298,9 @@ pub const Inst = struct {
1306 .float128 = .pl_node,1298 .float128 = .pl_node,
1307 .int_type = .int_type,1299 .int_type = .int_type,
1308 .is_non_null = .un_node,1300 .is_non_null = .un_node,
1309 .is_null = .un_node,
1310 .is_non_null_ptr = .un_node,1301 .is_non_null_ptr = .un_node,
1311 .is_null_ptr = .un_node,1302 .is_non_err = .un_node,
1312 .is_err = .un_node,1303 .is_non_err_ptr = .un_node,
1313 .is_err_ptr = .un_node,
1314 .loop = .pl_node,1304 .loop = .pl_node,
1315 .repeat = .node,1305 .repeat = .node,
1316 .repeat_inline = .node,1306 .repeat_inline = .node,
...@@ -2857,11 +2847,9 @@ const Writer = struct {...@@ -2857,11 +2847,9 @@ const Writer = struct {
2857 .err_union_code,2847 .err_union_code,
2858 .err_union_code_ptr,2848 .err_union_code_ptr,
2859 .is_non_null,2849 .is_non_null,
2860 .is_null,
2861 .is_non_null_ptr,2850 .is_non_null_ptr,
2862 .is_null_ptr,2851 .is_non_err,
2863 .is_err,2852 .is_non_err_ptr,
2864 .is_err_ptr,
2865 .typeof,2853 .typeof,
2866 .typeof_elem,2854 .typeof_elem,
2867 .struct_init_empty,2855 .struct_init_empty,
src/air.zig+11-1
...@@ -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,
...@@ -759,7 +765,9 @@ const DumpAir = struct {...@@ -759,7 +765,9 @@ const DumpAir = 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,
...@@ -888,11 +896,13 @@ const DumpAir = struct {...@@ -888,11 +896,13 @@ const DumpAir = 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,
src/codegen.zig+12
...@@ -859,6 +859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -859,6 +859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
859 .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).?),
860 .is_null => return self.genIsNull(inst.castTag(.is_null).?),860 .is_null => return self.genIsNull(inst.castTag(.is_null).?),
861 .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).?),
862 .is_err => return self.genIsErr(inst.castTag(.is_err).?),864 .is_err => return self.genIsErr(inst.castTag(.is_err).?),
863 .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?),865 .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?),
864 .load => return self.genLoad(inst.castTag(.load).?),866 .load => return self.genLoad(inst.castTag(.load).?),
...@@ -2972,6 +2974,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2972,6 +2974,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2972 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", .{});
2973 }2975 }
29742976
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
2975 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {2987 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {
2976 // 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.
2977 const start_index = self.code.items.len;2989 const start_index = self.code.items.len;
src/codegen/c.zig+6-5
...@@ -895,8 +895,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -895,8 +895,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
895 .ref => try genRef(o, inst.castTag(.ref).?),895 .ref => try genRef(o, inst.castTag(.ref).?),
896 .struct_field_ptr => try genStructFieldPtr(o, inst.castTag(.struct_field_ptr).?),896 .struct_field_ptr => try genStructFieldPtr(o, inst.castTag(.struct_field_ptr).?),
897897
898 .is_err => try genIsErr(o, inst.castTag(.is_err).?),898 .is_err => try genIsErr(o, inst.castTag(.is_err).?, "", "!="),
899 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),899 .is_non_err => try genIsErr(o, inst.castTag(.is_non_err).?, "", "=="),
900 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?, "[0]", "!="),
901 .is_non_err_ptr => try genIsErr(o, inst.castTag(.is_non_err_ptr).?, "[0]", "=="),
900902
901 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),903 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
902 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),904 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
...@@ -1446,15 +1448,14 @@ fn genWrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -1446,15 +1448,14 @@ fn genWrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {
1446 return local;1448 return local;
1447}1449}
14481450
1449fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {1451fn genIsErr(o: *Object, inst: *Inst.UnOp, deref_suffix: []const u8, op_str: []const u8) !CValue {
1450 const writer = o.writer();1452 const writer = o.writer();
1451 const maybe_deref = if (inst.base.tag == .is_err_ptr) "[0]" else "";
1452 const operand = try o.resolveInst(inst.operand);1453 const operand = try o.resolveInst(inst.operand);
14531454
1454 const local = try o.allocLocal(Type.initTag(.bool), .Const);1455 const local = try o.allocLocal(Type.initTag(.bool), .Const);
1455 try writer.writeAll(" = (");1456 try writer.writeAll(" = (");
1456 try o.writeCValue(writer, operand);1457 try o.writeCValue(writer, operand);
1457 try writer.print("){s}.error != 0;\n", .{maybe_deref});1458 try writer.print("){s}.error {s} 0;\n", .{ deref_suffix, op_str });
1458 return local;1459 return local;
1459}1460}
14601461
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 }