Skip to content

Commit

Permalink
improve stage2 to allow catch at comptime:
Browse files Browse the repository at this point in the history
* add error_union value tag.
* add analyzeIsErr
* add Value.isError
* add TZIR wrap_errunion_payload and wrap_errunion_err for
  wrapping from T -> E!T and E -> E!T
* add anlyzeInstUnwrapErrCode and analyzeInstUnwrapErr
* add analyzeInstEnsureErrPayloadVoid:
* Fix bug in astgen where .? was in wrong spot causing segfault when using this check
* add wrapErrorUnion
* tests!!!
  • Loading branch information
g-w1 committed Jan 19, 2021
1 parent 7e56028 commit d80ce37
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 10 deletions.
38 changes: 35 additions & 3 deletions src/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2458,7 +2458,15 @@ pub fn analyzeIsNull(
}

pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
return self.fail(scope, src, "TODO implement analysis of iserr", .{});
const ot = operand.ty.zigTypeTag();
if (ot != .ErrorSet and ot != .ErrorUnion) return self.constBool(scope, src, false);
if (ot == .ErrorSet) return self.constBool(scope, src, true);
assert(ot == .ErrorUnion);
if (operand.value()) |err_union| {
return self.constBool(scope, src, err_union.getError() != null);
}
const b = try self.requireRuntimeBlock(scope, src);
return self.addUnOp(b, src, Type.initTag(.bool), .is_err, operand);
}

pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst {
Expand Down Expand Up @@ -2761,6 +2769,24 @@ fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*In
return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst);
}

fn wrapErrorUnion(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
const err_union = dest_type.castTag(.error_union).?;
if (inst.value()) |val| {
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
}

const b = try self.requireRuntimeBlock(scope, inst.src);

// we are coercing from E to E!T
if (inst.ty.zigTypeTag() == .ErrorSet) {
var coerced = try self.coerce(scope, err_union.data.error_set, inst);
return self.addUnOp(b, inst.src, dest_type, .wrap_errunion_err, coerced);
} else {
var coerced = try self.coerce(scope, err_union.data.payload, inst);
return self.addUnOp(b, inst.src, dest_type, .wrap_errunion_payload, coerced);
}
}

fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
const int_payload = try scope.arena().create(Type.Payload.Bits);
int_payload.* = .{
Expand Down Expand Up @@ -2827,7 +2853,7 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
return chosen.ty;
}

pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) error{ OutOfMemory, AnalysisFail }!*Inst {
// If the types are the same, we can return the operand.
if (dest_type.eql(inst.ty))
return inst;
Expand Down Expand Up @@ -2861,6 +2887,11 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
}
}

// T to E!T or E to E!T
if (dest_type.tag() == .error_union) {
return try self.wrapErrorUnion(scope, dest_type, inst);
}

// Coercions where the source is a single pointer to an array.
src_array_ptr: {
if (!inst.ty.isSinglePointer()) break :src_array_ptr;
Expand Down Expand Up @@ -2939,7 +2970,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
}

pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*Inst {
pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) error{ OutOfMemory, AnalysisFail }!?*Inst {
const val = inst.value() orelse return null;
const src_zig_tag = inst.ty.zigTypeTag();
const dst_zig_tag = dest_type.zigTypeTag();
Expand Down Expand Up @@ -3429,6 +3460,7 @@ pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
pub const PanicId = enum {
unreach,
unwrap_null,
unwrap_errunion,
};

pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void {
Expand Down
5 changes: 3 additions & 2 deletions src/astgen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1497,8 +1497,9 @@ const CondKind = union(enum) {

fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
if (self == .bool) return &then_scope.base;

const payload = payload_node.?.castTag(.PointerPayload) orelse {
const payload = if (payload_node) |node|
node.castTag(.PointerPayload).?
else {
// condition is error union and payload is not explicitly ignored
_ = try addZIRUnOp(mod, &then_scope.base, src, .ensure_err_payload_void, self.err_union.?);
return &then_scope.base;
Expand Down
42 changes: 42 additions & 0 deletions src/codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.unreach => return MCValue{ .unreach = {} },
.optional_payload => return self.genOptionalPayload(inst.castTag(.optional_payload).?),
.optional_payload_ptr => return self.genOptionalPayloadPtr(inst.castTag(.optional_payload_ptr).?),
.unwrap_errunion_err => return self.genUnwrapErrErr(inst.castTag(.unwrap_errunion_err).?),
.unwrap_errunion_payload => return self.genUnwrapErrPayload(inst.castTag(.unwrap_errunion_payload).?),
.wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
.wrap_errunion_payload => return self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),
.wrap_errunion_err => return self.genWrapErrUnionErr(inst.castTag(.wrap_errunion_err).?),
.varptr => return self.genVarPtr(inst.castTag(.varptr).?),
.xor => return self.genXor(inst.castTag(.xor).?),
}
Expand Down Expand Up @@ -1140,6 +1144,23 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}

fn genUnwrapErrErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
return MCValue.dead;
switch (arch) {
else => return self.fail(inst.base.src, "TODO implement unwrap error union error for {}", .{self.target.cpu.arch}),
}
}

fn genUnwrapErrPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
return MCValue.dead;
switch (arch) {
else => return self.fail(inst.base.src, "TODO implement unwrap error union payload for {}", .{self.target.cpu.arch}),
}
}
fn genWrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
const optional_ty = inst.base.ty;

Expand All @@ -1156,6 +1177,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}

/// T to E!T
fn genWrapErrUnionPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
return MCValue.dead;

switch (arch) {
else => return self.fail(inst.base.src, "TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}),
}
}

/// E to E!T
fn genWrapErrUnionErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
return MCValue.dead;

switch (arch) {
else => return self.fail(inst.base.src, "TODO implement wrap errunion error for {}", .{self.target.cpu.arch}),
}
}
fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
Expand Down
12 changes: 12 additions & 0 deletions src/ir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ pub const Inst = struct {
// *?T => *T
optional_payload_ptr,
wrap_optional,
/// gets the payload of an error union
unwrap_errunion_payload,
/// gets the error from an error union
unwrap_errunion_err,
/// wrap from T to E!T
wrap_errunion_payload,
/// wrap from E to E!T
wrap_errunion_err,
xor,
switchbr,

Expand Down Expand Up @@ -136,6 +144,10 @@ pub const Inst = struct {
.optional_payload,
.optional_payload_ptr,
.wrap_optional,
.unwrap_errunion_payload,
.unwrap_errunion_err,
.wrap_errunion_payload,
.wrap_errunion_err,
=> UnOp,

.add,
Expand Down
Loading

0 comments on commit d80ce37

Please sign in to comment.