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
786786 rl,
787787 node,
788788 node_datas[node].lhs,
789 .is_err_ptr,
789 .is_non_err_ptr,
790790 .err_union_payload_unsafe_ptr,
791791 .err_union_code_ptr,
792792 node_datas[node].rhs,
......@@ -798,7 +798,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr
798798 rl,
799799 node,
800800 node_datas[node].lhs,
801 .is_err,
801 .is_non_err,
802802 .err_union_payload_unsafe,
803803 .err_union_code,
804804 node_datas[node].rhs,
......@@ -813,7 +813,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr
813813 rl,
814814 node,
815815 node_datas[node].lhs,
816 .is_null_ptr,
816 .is_non_null_ptr,
817817 .optional_payload_unsafe_ptr,
818818 undefined,
819819 node_datas[node].rhs,
......@@ -825,7 +825,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr
825825 rl,
826826 node,
827827 node_datas[node].lhs,
828 .is_null,
828 .is_non_null,
829829 .optional_payload_unsafe,
830830 undefined,
831831 node_datas[node].rhs,
......@@ -1948,11 +1948,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
19481948 .float128,
19491949 .int_type,
19501950 .is_non_null,
1951 .is_null,
19521951 .is_non_null_ptr,
1953 .is_null_ptr,
1954 .is_err,
1955 .is_err_ptr,
1952 .is_non_err,
1953 .is_non_err_ptr,
19561954 .mod_rem,
19571955 .mul,
19581956 .mulwrap,
......@@ -4621,8 +4619,8 @@ fn tryExpr(
46214619 };
46224620 const err_ops = switch (rl) {
46234621 // zig fmt: off
4624 .ref => [3]Zir.Inst.Tag{ .is_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 },
4622 .ref => [3]Zir.Inst.Tag{ .is_non_err_ptr, .err_union_code_ptr, .err_union_payload_unsafe_ptr },
4623 else => [3]Zir.Inst.Tag{ .is_non_err, .err_union_code, .err_union_payload_unsafe },
46264624 // zig fmt: on
46274625 };
46284626 // This could be a pointer or value depending on the `operand_rl` parameter.
......@@ -4640,21 +4638,21 @@ fn tryExpr(
46404638 var then_scope = parent_gz.makeSubBlock(scope);
46414639 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
46504641 block_scope.break_count += 1;
46514642 // 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);
4653 const else_result = switch (rl) {
4643 const unwrapped_payload = try then_scope.addUnNode(err_ops[2], operand, node);
4644 const then_result = switch (rl) {
46544645 .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),
46564647 };
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
46584656 return finishThenElseBlock(
46594657 parent_gz,
46604658 rl,
......@@ -4711,18 +4709,28 @@ fn orelseCatchExpr(
47114709 var then_scope = parent_gz.makeSubBlock(scope);
47124710 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
47144722 var err_val_scope: Scope.LocalVal = undefined;
4715 const then_sub_scope = blk: {
4716 const payload = payload_token orelse break :blk &then_scope.base;
4723 const else_sub_scope = blk: {
4724 const payload = payload_token orelse break :blk &else_scope.base;
47174725 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
47184726 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
47194727 }
47204728 const err_name = try astgen.identAsString(payload);
47214729 err_val_scope = .{
4722 .parent = &then_scope.base,
4723 .gen_zir = &then_scope,
4730 .parent = &else_scope.base,
4731 .gen_zir = &else_scope,
47244732 .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),
47264734 .token_src = payload,
47274735 .id_cat = .@"capture",
47284736 };
......@@ -4730,23 +4738,13 @@ fn orelseCatchExpr(
47304738 };
47314739
47324740 block_scope.break_count += 1;
4733 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, rhs);
4734 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
4741 const else_result = try expr(&else_scope, else_sub_scope, block_scope.break_result_loc, rhs);
4742 try checkUsed(parent_gz, &else_scope.base, else_sub_scope);
47354743
47364744 // We hold off on the break instructions as well as copying the then/else
47374745 // instructions into place until we know whether to keep store_to_block_ptr
47384746 // 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
47504748 return finishThenElseBlock(
47514749 parent_gz,
47524750 rl,
......@@ -4964,7 +4962,7 @@ fn ifExpr(
49644962 if (if_full.error_token) |_| {
49654963 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
49664964 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;
49684966 break :c .{
49694967 .inst = err_union,
49704968 .bool_bit = try block_scope.addUnNode(tag, err_union, node),
......@@ -5221,7 +5219,7 @@ fn whileExpr(
52215219 if (while_full.error_token) |_| {
52225220 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
52235221 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;
52255223 break :c .{
52265224 .inst = err_union,
52275225 .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
62296227 }
62306228
62316229 // 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);
62336231 const condbr = try gz.addCondBr(.condbr, node);
62346232
62356233 var then_scope = gz.makeSubBlock(scope);
62366234 defer then_scope.instructions.deinit(astgen.gpa);
6237 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
6238 .both = try then_scope.addUnNode(.err_union_code, operand, node),
6239 };
6240 try genDefers(&then_scope, defer_outer, scope, which_ones);
6235
6236 try genDefers(&then_scope, defer_outer, scope, .normal_only);
62416237 _ = try then_scope.addUnNode(.ret_node, operand, node);
62426238
62436239 var else_scope = gz.makeSubBlock(scope);
62446240 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);
62466246 _ = 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
62506250 return Zir.Inst.Ref.unreachable_value;
62516251 },
src/Sema.zig+30-25
......@@ -225,12 +225,10 @@ pub fn analyzeBody(
225225 .float => try sema.zirFloat(block, inst),
226226 .float128 => try sema.zirFloat128(block, inst),
227227 .int_type => try sema.zirIntType(block, inst),
228 .is_err => try sema.zirIsErr(block, inst),
229 .is_err_ptr => try sema.zirIsErrPtr(block, inst),
230 .is_non_null => try sema.zirIsNull(block, inst, true),
231 .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true),
232 .is_null => try sema.zirIsNull(block, inst, false),
233 .is_null_ptr => try sema.zirIsNullPtr(block, inst, false),
228 .is_non_err => try sema.zirIsNonErr(block, inst),
229 .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
230 .is_non_null => try sema.zirIsNonNull(block, inst),
231 .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
234232 .loop => try sema.zirLoop(block, inst),
235233 .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
236234 .negate => try sema.zirNegate(block, inst, .sub),
......@@ -2981,17 +2979,19 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
29812979 if (operand.ty.zigTypeTag() != .ErrorUnion)
29822980 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
29842984 if (operand.value()) |val| {
29852985 assert(val.getError() != null);
29862986 const data = val.castTag(.error_union).?.data;
29872987 return sema.mod.constInst(sema.arena, src, .{
2988 .ty = operand.ty.castTag(.error_union).?.data.error_set,
2988 .ty = result_ty,
29892989 .val = data,
29902990 });
29912991 }
29922992
29932993 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);
29952995}
29962996
29972997/// Pointer in, value out
......@@ -3007,18 +3007,20 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
30073007 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
30083008 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
30103012 if (operand.value()) |pointer_val| {
30113013 const val = try pointer_val.pointerDeref(sema.arena);
30123014 assert(val.getError() != null);
30133015 const data = val.castTag(.error_union).?.data;
30143016 return sema.mod.constInst(sema.arena, src, .{
3015 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,
3017 .ty = result_ty,
30163018 .val = data,
30173019 });
30183020 }
30193021
30203022 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);
30223024}
30233025
30243026fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
......@@ -5298,11 +5300,10 @@ fn zirBoolBr(
52985300 return &block_inst.base;
52995301}
53005302
5301fn zirIsNull(
5303fn zirIsNonNull(
53025304 sema: *Sema,
53035305 block: *Scope.Block,
53045306 inst: Zir.Inst.Index,
5305 invert_logic: bool,
53065307) InnerError!*Inst {
53075308 const tracy = trace(@src());
53085309 defer tracy.end();
......@@ -5310,14 +5311,13 @@ fn zirIsNull(
53105311 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
53115312 const src = inst_data.src();
53125313 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);
53145315}
53155316
5316fn zirIsNullPtr(
5317fn zirIsNonNullPtr(
53175318 sema: *Sema,
53185319 block: *Scope.Block,
53195320 inst: Zir.Inst.Index,
5320 invert_logic: bool,
53215321) InnerError!*Inst {
53225322 const tracy = trace(@src());
53235323 defer tracy.end();
......@@ -5326,19 +5326,19 @@ fn zirIsNullPtr(
53265326 const src = inst_data.src();
53275327 const ptr = try sema.resolveInst(inst_data.operand);
53285328 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);
53305330}
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 {
53335333 const tracy = trace(@src());
53345334 defer tracy.end();
53355335
53365336 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
53375337 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);
53395339}
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 {
53425342 const tracy = trace(@src());
53435343 defer tracy.end();
53445344
......@@ -5346,7 +5346,7 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
53465346 const src = inst_data.src();
53475347 const ptr = try sema.resolveInst(inst_data.operand);
53485348 const loaded = try sema.analyzeLoad(block, src, ptr, src);
5349 return sema.analyzeIsErr(block, src, loaded);
5349 return sema.analyzeIsNonErr(block, src, loaded);
53505350}
53515351
53525352fn zirCondbr(
......@@ -7219,20 +7219,25 @@ fn analyzeIsNull(
72197219 return block.addUnOp(src, result_ty, inst_tag, operand);
72207220}
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 {
72237228 const ot = operand.ty.zigTypeTag();
7224 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false);
7225 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true);
7229 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, true);
7230 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, false);
72267231 assert(ot == .ErrorUnion);
72277232 const result_ty = Type.initTag(.bool);
72287233 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {
72297234 if (err_union.isUndef()) {
72307235 return sema.mod.constUndef(sema.arena, src, result_ty);
72317236 }
7232 return sema.mod.constBool(sema.arena, src, err_union.getError() != null);
7237 return sema.mod.constBool(sema.arena, src, err_union.getError() == null);
72337238 }
72347239 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);
72367241}
72377242
72387243fn analyzeSlice(
src/Zir.zig+10-22
......@@ -398,21 +398,15 @@ pub const Inst = struct {
398398 /// Return a boolean false if an optional is null. `x != null`
399399 /// Uses the `un_node` field.
400400 is_non_null,
401 /// Return a boolean true if an optional is null. `x == null`
402 /// Uses the `un_node` field.
403 is_null,
404401 /// Return a boolean false if an optional is null. `x.* != null`
405402 /// Uses the `un_node` field.
406403 is_non_null_ptr,
407 /// Return a boolean true if an optional is null. `x.* == null`
408 /// Uses the `un_node` field.
409 is_null_ptr,
410 /// Return a boolean true if value is an error
404 /// Return a boolean false if value is an error
411405 /// Uses the `un_node` field.
412 is_err,
413 /// Return a boolean true if dereferenced pointer is an error
406 is_non_err,
407 /// Return a boolean false if dereferenced pointer is an error
414408 /// Uses the `un_node` field.
415 is_err_ptr,
409 is_non_err_ptr,
416410 /// A labeled block of code that loops forever. At the end of the body will have either
417411 /// a `repeat` instruction or a `repeat_inline` instruction.
418412 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.
......@@ -1046,11 +1040,9 @@ pub const Inst = struct {
10461040 .float128,
10471041 .int_type,
10481042 .is_non_null,
1049 .is_null,
10501043 .is_non_null_ptr,
1051 .is_null_ptr,
1052 .is_err,
1053 .is_err_ptr,
1044 .is_non_err,
1045 .is_non_err_ptr,
10541046 .mod_rem,
10551047 .mul,
10561048 .mulwrap,
......@@ -1306,11 +1298,9 @@ pub const Inst = struct {
13061298 .float128 = .pl_node,
13071299 .int_type = .int_type,
13081300 .is_non_null = .un_node,
1309 .is_null = .un_node,
13101301 .is_non_null_ptr = .un_node,
1311 .is_null_ptr = .un_node,
1312 .is_err = .un_node,
1313 .is_err_ptr = .un_node,
1302 .is_non_err = .un_node,
1303 .is_non_err_ptr = .un_node,
13141304 .loop = .pl_node,
13151305 .repeat = .node,
13161306 .repeat_inline = .node,
......@@ -2857,11 +2847,9 @@ const Writer = struct {
28572847 .err_union_code,
28582848 .err_union_code_ptr,
28592849 .is_non_null,
2860 .is_null,
28612850 .is_non_null_ptr,
2862 .is_null_ptr,
2863 .is_err,
2864 .is_err_ptr,
2851 .is_non_err,
2852 .is_non_err_ptr,
28652853 .typeof,
28662854 .typeof_elem,
28672855 .struct_init_empty,
src/air.zig+11-1
......@@ -90,8 +90,12 @@ pub const Inst = struct {
9090 is_non_null_ptr,
9191 /// E!T => bool
9292 is_err,
93 /// E!T => bool (inverted logic)
94 is_non_err,
9395 /// *E!T => bool
9496 is_err_ptr,
97 /// *E!T => bool (inverted logic)
98 is_non_err_ptr,
9599 bool_and,
96100 bool_or,
97101 /// Read a value from a pointer.
......@@ -154,7 +158,9 @@ pub const Inst = struct {
154158 .is_null,
155159 .is_null_ptr,
156160 .is_err,
161 .is_non_err,
157162 .is_err_ptr,
163 .is_non_err_ptr,
158164 .ptrtoint,
159165 .floatcast,
160166 .intcast,
......@@ -759,7 +765,9 @@ const DumpAir = struct {
759765 .is_null,
760766 .is_null_ptr,
761767 .is_err,
768 .is_non_err,
762769 .is_err_ptr,
770 .is_non_err_ptr,
763771 .ptrtoint,
764772 .floatcast,
765773 .intcast,
......@@ -888,11 +896,13 @@ const DumpAir = struct {
888896 .bitcast,
889897 .not,
890898 .is_non_null,
891 .is_null,
892899 .is_non_null_ptr,
900 .is_null,
893901 .is_null_ptr,
894902 .is_err,
895903 .is_err_ptr,
904 .is_non_err,
905 .is_non_err_ptr,
896906 .ptrtoint,
897907 .floatcast,
898908 .intcast,
src/codegen.zig+12
......@@ -859,6 +859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
859859 .is_non_null_ptr => return self.genIsNonNullPtr(inst.castTag(.is_non_null_ptr).?),
860860 .is_null => return self.genIsNull(inst.castTag(.is_null).?),
861861 .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).?),
862864 .is_err => return self.genIsErr(inst.castTag(.is_err).?),
863865 .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?),
864866 .load => return self.genLoad(inst.castTag(.load).?),
......@@ -2972,6 +2974,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29722974 return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{});
29732975 }
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
29752987 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {
29762988 // A loop is a setup to be able to jump back to the beginning.
29772989 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
895895 .ref => try genRef(o, inst.castTag(.ref).?),
896896 .struct_field_ptr => try genStructFieldPtr(o, inst.castTag(.struct_field_ptr).?),
897897
898 .is_err => try genIsErr(o, inst.castTag(.is_err).?),
899 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),
898 .is_err => try genIsErr(o, inst.castTag(.is_err).?, "", "!="),
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
901903 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
902904 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
......@@ -1446,15 +1448,14 @@ fn genWrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {
14461448 return local;
14471449}
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 {
14501452 const writer = o.writer();
1451 const maybe_deref = if (inst.base.tag == .is_err_ptr) "[0]" else "";
14521453 const operand = try o.resolveInst(inst.operand);
14531454
14541455 const local = try o.allocLocal(Type.initTag(.bool), .Const);
14551456 try writer.writeAll(" = (");
14561457 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 });
14581459 return local;
14591460}
14601461
src/codegen/wasm.zig+4-5
......@@ -814,7 +814,8 @@ pub const Context = struct {
814814 .constant => unreachable,
815815 .dbg_stmt => WValue.none,
816816 .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),
818819 .load => self.genLoad(inst.castTag(.load).?),
819820 .loop => self.genLoop(inst.castTag(.loop).?),
820821 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
......@@ -1278,7 +1279,7 @@ pub const Context = struct {
12781279 return .none;
12791280 }
12801281
1281 fn genIsErr(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
1282 fn genIsErr(self: *Context, inst: *Inst.UnOp, opcode: wasm.Opcode) InnerError!WValue {
12821283 const operand = self.resolveInst(inst.operand);
12831284 const offset = self.code.items.len;
12841285 const writer = self.code.writer();
......@@ -1289,9 +1290,7 @@ pub const Context = struct {
12891290 try writer.writeByte(wasm.opcode(.i32_const));
12901291 try leb.writeILEB128(writer, @as(i32, 0));
12911292
1292 // we want to break out of the condition if they're *not* equal,
1293 // because that means there's an error.
1294 try writer.writeByte(wasm.opcode(.i32_ne));
1293 try writer.writeByte(@enumToInt(opcode));
12951294
12961295 return WValue{ .code_offset = offset };
12971296 }