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.
This commit is contained in:
@@ -895,8 +895,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
|
||||
.ref => try genRef(o, inst.castTag(.ref).?),
|
||||
.struct_field_ptr => try genStructFieldPtr(o, inst.castTag(.struct_field_ptr).?),
|
||||
|
||||
.is_err => try genIsErr(o, inst.castTag(.is_err).?),
|
||||
.is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),
|
||||
.is_err => try genIsErr(o, inst.castTag(.is_err).?, "", "!="),
|
||||
.is_non_err => try genIsErr(o, inst.castTag(.is_non_err).?, "", "=="),
|
||||
.is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?, "[0]", "!="),
|
||||
.is_non_err_ptr => try genIsErr(o, inst.castTag(.is_non_err_ptr).?, "[0]", "=="),
|
||||
|
||||
.unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
|
||||
.unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
|
||||
@@ -1446,15 +1448,14 @@ fn genWrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {
|
||||
return local;
|
||||
}
|
||||
|
||||
fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {
|
||||
fn genIsErr(o: *Object, inst: *Inst.UnOp, deref_suffix: []const u8, op_str: []const u8) !CValue {
|
||||
const writer = o.writer();
|
||||
const maybe_deref = if (inst.base.tag == .is_err_ptr) "[0]" else "";
|
||||
const operand = try o.resolveInst(inst.operand);
|
||||
|
||||
const local = try o.allocLocal(Type.initTag(.bool), .Const);
|
||||
try writer.writeAll(" = (");
|
||||
try o.writeCValue(writer, operand);
|
||||
try writer.print("){s}.error != 0;\n", .{maybe_deref});
|
||||
try writer.print("){s}.error {s} 0;\n", .{ deref_suffix, op_str });
|
||||
return local;
|
||||
}
|
||||
|
||||
|
||||
@@ -814,7 +814,8 @@ pub const Context = struct {
|
||||
.constant => unreachable,
|
||||
.dbg_stmt => WValue.none,
|
||||
.div => self.genBinOp(inst.castTag(.div).?, .div),
|
||||
.is_err => self.genIsErr(inst.castTag(.is_err).?),
|
||||
.is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),
|
||||
.is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),
|
||||
.load => self.genLoad(inst.castTag(.load).?),
|
||||
.loop => self.genLoop(inst.castTag(.loop).?),
|
||||
.mul => self.genBinOp(inst.castTag(.mul).?, .mul),
|
||||
@@ -1278,7 +1279,7 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genIsErr(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
|
||||
fn genIsErr(self: *Context, inst: *Inst.UnOp, opcode: wasm.Opcode) InnerError!WValue {
|
||||
const operand = self.resolveInst(inst.operand);
|
||||
const offset = self.code.items.len;
|
||||
const writer = self.code.writer();
|
||||
@@ -1289,9 +1290,7 @@ pub const Context = struct {
|
||||
try writer.writeByte(wasm.opcode(.i32_const));
|
||||
try leb.writeILEB128(writer, @as(i32, 0));
|
||||
|
||||
// we want to break out of the condition if they're *not* equal,
|
||||
// because that means there's an error.
|
||||
try writer.writeByte(wasm.opcode(.i32_ne));
|
||||
try writer.writeByte(@enumToInt(opcode));
|
||||
|
||||
return WValue{ .code_offset = offset };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user