Commit b560f46c87

Andrew Kelley <andrew@ziglang.org>
2021-11-25 06:27:40
stage2: fix unwrap function call with optional pointer return value
1 parent a130eac
Changed files (7)
src/arch/wasm/CodeGen.zig
@@ -848,6 +848,11 @@ pub fn gen(self: *Self, ty: Type, val: Value) InnerError!Result {
             try self.emitConstant(val, ty);
             return Result.appended;
         },
+        .Bool => {
+            const int_byte: u8 = @boolToInt(val.toBool());
+            try self.code.append(int_byte);
+            return Result.appended;
+        },
         .Struct => {
             // TODO write the fields for real
             const abi_size = try std.math.cast(usize, ty.abiSize(self.target));
src/codegen/c.zig
@@ -772,10 +772,7 @@ pub const DeclGen = struct {
         const target = dg.module.getTarget();
 
         switch (t.zigTypeTag()) {
-            .NoReturn => {
-                try w.writeAll("zig_noreturn void");
-            },
-            .Void => try w.writeAll("void"),
+            .NoReturn, .Void => try w.writeAll("void"),
             .Bool => try w.writeAll("bool"),
             .Int => {
                 switch (t.tag()) {
src/codegen.zig
@@ -286,6 +286,62 @@ pub fn generateSymbol(
             }
             return Result{ .appended = {} };
         },
+        .Enum => {
+            // TODO populate .debug_info for the enum
+            var int_buffer: Value.Payload.U64 = undefined;
+            const int_val = typed_value.enumToInt(&int_buffer);
+
+            const target = bin_file.options.target;
+            const info = typed_value.ty.intInfo(target);
+            if (info.bits <= 8) {
+                const x = @intCast(u8, int_val.toUnsignedInt());
+                try code.append(x);
+                return Result{ .appended = {} };
+            }
+            if (info.bits > 64) {
+                return Result{
+                    .fail = try ErrorMsg.create(
+                        bin_file.allocator,
+                        src_loc,
+                        "TODO implement generateSymbol for big int enums ('{}')",
+                        .{typed_value.ty},
+                    ),
+                };
+            }
+            const endian = target.cpu.arch.endian();
+            switch (info.signedness) {
+                .unsigned => {
+                    if (info.bits <= 16) {
+                        const x = @intCast(u16, int_val.toUnsignedInt());
+                        mem.writeInt(u16, try code.addManyAsArray(2), x, endian);
+                    } else if (info.bits <= 32) {
+                        const x = @intCast(u32, int_val.toUnsignedInt());
+                        mem.writeInt(u32, try code.addManyAsArray(4), x, endian);
+                    } else {
+                        const x = int_val.toUnsignedInt();
+                        mem.writeInt(u64, try code.addManyAsArray(8), x, endian);
+                    }
+                },
+                .signed => {
+                    if (info.bits <= 16) {
+                        const x = @intCast(i16, int_val.toSignedInt());
+                        mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
+                    } else if (info.bits <= 32) {
+                        const x = @intCast(i32, int_val.toSignedInt());
+                        mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
+                    } else {
+                        const x = int_val.toSignedInt();
+                        mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
+                    }
+                },
+            }
+            return Result{ .appended = {} };
+        },
+        .Bool => {
+            const x: u8 = @boolToInt(typed_value.val.toBool());
+            try code.append(x);
+            return Result{ .appended = {} };
+        },
         .Struct => {
             const field_vals = typed_value.val.castTag(.@"struct").?.data;
             _ = field_vals; // TODO write the fields for real
src/Module.zig
@@ -3464,11 +3464,16 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
                 queue_linker_work = true;
             }
         },
-        .array, .@"struct", .@"union" => {
+
+        .generic_poison => unreachable,
+        .unreachable_value => unreachable,
+
+        .function => {},
+
+        else => {
             log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name });
             queue_linker_work = true;
         },
-        else => {},
     }
 
     decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);
src/Sema.zig
@@ -4800,8 +4800,10 @@ fn zirOptionalPayload(
         if (val.isNull()) {
             return sema.fail(block, src, "unable to unwrap null", .{});
         }
-        const sub_val = val.castTag(.opt_payload).?.data;
-        return sema.addConstant(result_ty, sub_val);
+        if (val.castTag(.opt_payload)) |payload| {
+            return sema.addConstant(result_ty, payload.data);
+        }
+        return sema.addConstant(result_ty, val);
     }
 
     try sema.requireRuntimeBlock(block, src);
test/behavior/optional.zig
@@ -118,3 +118,21 @@ fn test_cmp_optional_non_optional() !void {
         break :blk2 @as(?f64, 5.0);
     };
 }
+
+test "unwrap function call with optional pointer return value" {
+    const S = struct {
+        fn entry() !void {
+            try expect(foo().?.* == 1234);
+            try expect(bar() == null);
+        }
+        const global: i32 = 1234;
+        fn foo() ?*const i32 {
+            return &global;
+        }
+        fn bar() ?*i32 {
+            return null;
+        }
+    };
+    try S.entry();
+    comptime try S.entry();
+}
test/behavior/optional_stage1.zig
@@ -3,24 +3,6 @@ const testing = std.testing;
 const expect = testing.expect;
 const expectEqual = testing.expectEqual;
 
-test "unwrap function call with optional pointer return value" {
-    const S = struct {
-        fn entry() !void {
-            try expect(foo().?.* == 1234);
-            try expect(bar() == null);
-        }
-        const global: i32 = 1234;
-        fn foo() ?*const i32 {
-            return &global;
-        }
-        fn bar() ?*i32 {
-            return null;
-        }
-    };
-    try S.entry();
-    comptime try S.entry();
-}
-
 test "nested orelse" {
     const S = struct {
         fn entry() !void {