Commit f4f23e307c

Jakub Konka <kubkon@jakubkonka.com>
2022-02-20 16:35:24
codegen: lower error_set and error_union
1 parent 358b544
Changed files (3)
src
src/arch/x86_64/CodeGen.zig
@@ -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);
src/link/Elf.zig
@@ -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;
         },
     };
src/codegen.zig
@@ -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(