codegen: lower error_set and error_union

This commit is contained in:
Jakub Konka 2022-02-20 16:35:24 +01:00
parent 358b544157
commit f4f23e307c
3 changed files with 52 additions and 6 deletions

View File

@ -3509,6 +3509,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
return self.fail("TODO isErr for errors with size larger than register size", .{});
}
} else {
log.warn("operand = {}, payload_type = {}", .{ operand, payload_type });
return self.fail("TODO isErr for non-empty payloads", .{});
}
}
@ -5108,22 +5109,18 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
const error_type = typed_value.ty.errorUnionSet();
const payload_type = typed_value.ty.errorUnionPayload();
if (typed_value.val.castTag(.eu_payload)) |pl| {
if (typed_value.val.castTag(.eu_payload)) |_| {
if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return MCValue{ .immediate = 0 };
}
_ = pl;
return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
} else {
if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
}
}
return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty});
return self.lowerUnnamedConst(typed_value);
},
.Struct => {
return self.lowerUnnamedConst(typed_value);

View File

@ -432,6 +432,54 @@ pub fn generateSymbol(
return Result{ .appended = {} };
},
.ErrorUnion => {
const error_ty = typed_value.ty.errorUnionSet();
const payload_ty = typed_value.ty.errorUnionPayload();
const is_payload = typed_value.val.errorUnionIsPayload();
const error_val = if (!is_payload) typed_value.val else Value.initTag(.zero);
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
.ty = error_ty,
.val = error_val,
}, code, debug_output)) {
.appended => {},
.externally_managed => |external_slice| {
code.appendSliceAssumeCapacity(external_slice);
},
.fail => |em| return Result{ .fail = em },
}
if (payload_ty.hasRuntimeBits()) {
const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
.ty = payload_ty,
.val = payload_val,
}, code, debug_output)) {
.appended => {},
.externally_managed => |external_slice| {
code.appendSliceAssumeCapacity(external_slice);
},
.fail => |em| return Result{ .fail = em },
}
}
return Result{ .appended = {} };
},
.ErrorSet => {
const target = bin_file.options.target;
switch (typed_value.val.tag()) {
.@"error" => {
const name = typed_value.val.getError().?;
const kv = try bin_file.options.module.?.getErrorValue(name);
const endian = target.cpu.arch.endian();
try code.writer().writeInt(u32, kv.value, endian);
},
else => {
try code.writer().writeByteNTimes(0, @intCast(usize, typed_value.ty.abiSize(target)));
},
}
return Result{ .appended = {} };
},
else => |t| {
return Result{
.fail = try ErrorMsg.create(

View File

@ -3127,6 +3127,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl
.fail => |em| {
decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, decl, em);
log.err("{s}", .{em.msg});
return error.AnalysisFail;
},
};