| author | |
| committer | |
| log | 5c8bd443d92c6306f60857720103ae46ca7b8b3e |
| tree | fbac6bd8a6d337ef035b07ef766b3718f91e0781 |
| parent | 5816997ae79c6025d5f85aab0c9ab456fecadec9 |
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: off | 4621 | // 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: on | 4624 | // 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); |
| 4642 | 4640 | ||
| 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 | }; |
| 4657 | 4648 | ||
| 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); |
| 4713 | 4711 | ||
| 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 | }; |
| 4731 | 4739 | ||
| 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); |
| 4735 | 4743 | ||
| 4736 | // We hold off on the break instructions as well as copying the then/else | 4744 | // 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_ptr | 4745 | // instructions into place until we know whether to keep store_to_block_ptr |
| 4738 | // instructions or not. | 4746 | // instructions or not. |
| 4739 | 4747 | ||
| 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 | } |
| 6230 | 6228 | ||
| 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); |
| 6234 | 6232 | ||
| 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); |
| 6242 | 6238 | ||
| 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); |
| 6247 | 6247 | ||
| 6248 | try setCondBrPayload(condbr, is_err, &then_scope, &else_scope); | 6248 | try setCondBrPayload(condbr, is_non_err, &then_scope, &else_scope); |
| 6249 | 6249 | ||
| 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}); |
| 2983 | 2981 | ||
| 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 | } |
| 2992 | 2992 | ||
| 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 | } |
| 2996 | 2996 | ||
| 2997 | /// Pointer in, value out | 2997 | /// 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()}); |
| 3009 | 3009 | ||
| 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 | } |
| 3019 | 3021 | ||
| 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 | } |
| 3023 | 3025 | ||
| 3024 | fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { | 3026 | fn 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 | } |
| 5300 | 5302 | ||
| 5301 | fn zirIsNull( | 5303 | fn 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 | } |
| 5315 | 5316 | ||
| 5316 | fn zirIsNullPtr( | 5317 | fn 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 | } |
| 5331 | 5331 | ||
| 5332 | fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | 5332 | fn 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(); |
| 5335 | 5335 | ||
| 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 | } |
| 5340 | 5340 | ||
| 5341 | fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | 5341 | fn 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(); |
| 5344 | 5344 | ||
| ... | @@ -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 | } |
| 5351 | 5351 | ||
| 5352 | fn zirCondbr( | 5352 | fn 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 | } |
| 7221 | 7221 | ||
| 7222 | fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst { | 7222 | fn 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 | } |
| 7237 | 7242 | ||
| 7238 | fn analyzeSlice( | 7243 | fn 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 error | 407 | /// 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 either | 410 | /// 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 => bool | 91 | /// E!T => bool |
| 92 | is_err, | 92 | is_err, |
| 93 | /// E!T => bool (inverted logic) | ||
| 94 | is_non_err, | ||
| 93 | /// *E!T => bool | 95 | /// *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 | } |
| 2974 | 2976 | ||
| 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).?), |
| 897 | 897 | ||
| 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]", "=="), | ||
| 900 | 902 | ||
| 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 | } |
| 1448 | 1450 | ||
| 1449 | fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue { | 1451 | fn 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); |
| 1453 | 1454 | ||
| 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 | } |
| 1460 | 1461 |
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 | } |
| 1280 | 1281 | ||
| 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)); |
| 1291 | 1292 | ||
| 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)); | ||
| 1295 | 1294 | ||
| 1296 | return WValue{ .code_offset = offset }; | 1295 | return WValue{ .code_offset = offset }; |
| 1297 | } | 1296 | } |