authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-24 22:27:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-24 22:44:33-07:00
logb560f46c871f234a8b2f762c03984eef963f360a
tree4c82363776185796842c5b4a505444381a77e67e
parenta130eac7857512db50320fb1c64079b0d696885d

stage2: fix unwrap function call with optional pointer return value


7 files changed, 91 insertions(+), 26 deletions(-)

src/Module.zig+7-2
......@@ -3464,11 +3464,16 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
34643464 queue_linker_work = true;
34653465 }
34663466 },
3467 .array, .@"struct", .@"union" => {
3467
3468 .generic_poison => unreachable,
3469 .unreachable_value => unreachable,
3470
3471 .function => {},
3472
3473 else => {
34683474 log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name });
34693475 queue_linker_work = true;
34703476 },
3471 else => {},
34723477 }
34733478
34743479 decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);
src/Sema.zig+4-2
......@@ -4800,8 +4800,10 @@ fn zirOptionalPayload(
48004800 if (val.isNull()) {
48014801 return sema.fail(block, src, "unable to unwrap null", .{});
48024802 }
4803 const sub_val = val.castTag(.opt_payload).?.data;
4804 return sema.addConstant(result_ty, sub_val);
4803 if (val.castTag(.opt_payload)) |payload| {
4804 return sema.addConstant(result_ty, payload.data);
4805 }
4806 return sema.addConstant(result_ty, val);
48054807 }
48064808
48074809 try sema.requireRuntimeBlock(block, src);
src/arch/wasm/CodeGen.zig+5
......@@ -848,6 +848,11 @@ pub fn gen(self: *Self, ty: Type, val: Value) InnerError!Result {
848848 try self.emitConstant(val, ty);
849849 return Result.appended;
850850 },
851 .Bool => {
852 const int_byte: u8 = @boolToInt(val.toBool());
853 try self.code.append(int_byte);
854 return Result.appended;
855 },
851856 .Struct => {
852857 // TODO write the fields for real
853858 const abi_size = try std.math.cast(usize, ty.abiSize(self.target));
src/codegen.zig+56
......@@ -286,6 +286,62 @@ pub fn generateSymbol(
286286 }
287287 return Result{ .appended = {} };
288288 },
289 .Enum => {
290 // TODO populate .debug_info for the enum
291 var int_buffer: Value.Payload.U64 = undefined;
292 const int_val = typed_value.enumToInt(&int_buffer);
293
294 const target = bin_file.options.target;
295 const info = typed_value.ty.intInfo(target);
296 if (info.bits <= 8) {
297 const x = @intCast(u8, int_val.toUnsignedInt());
298 try code.append(x);
299 return Result{ .appended = {} };
300 }
301 if (info.bits > 64) {
302 return Result{
303 .fail = try ErrorMsg.create(
304 bin_file.allocator,
305 src_loc,
306 "TODO implement generateSymbol for big int enums ('{}')",
307 .{typed_value.ty},
308 ),
309 };
310 }
311 const endian = target.cpu.arch.endian();
312 switch (info.signedness) {
313 .unsigned => {
314 if (info.bits <= 16) {
315 const x = @intCast(u16, int_val.toUnsignedInt());
316 mem.writeInt(u16, try code.addManyAsArray(2), x, endian);
317 } else if (info.bits <= 32) {
318 const x = @intCast(u32, int_val.toUnsignedInt());
319 mem.writeInt(u32, try code.addManyAsArray(4), x, endian);
320 } else {
321 const x = int_val.toUnsignedInt();
322 mem.writeInt(u64, try code.addManyAsArray(8), x, endian);
323 }
324 },
325 .signed => {
326 if (info.bits <= 16) {
327 const x = @intCast(i16, int_val.toSignedInt());
328 mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
329 } else if (info.bits <= 32) {
330 const x = @intCast(i32, int_val.toSignedInt());
331 mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
332 } else {
333 const x = int_val.toSignedInt();
334 mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
335 }
336 },
337 }
338 return Result{ .appended = {} };
339 },
340 .Bool => {
341 const x: u8 = @boolToInt(typed_value.val.toBool());
342 try code.append(x);
343 return Result{ .appended = {} };
344 },
289345 .Struct => {
290346 const field_vals = typed_value.val.castTag(.@"struct").?.data;
291347 _ = field_vals; // TODO write the fields for real
src/codegen/c.zig+1-4
......@@ -772,10 +772,7 @@ pub const DeclGen = struct {
772772 const target = dg.module.getTarget();
773773
774774 switch (t.zigTypeTag()) {
775 .NoReturn => {
776 try w.writeAll("zig_noreturn void");
777 },
778 .Void => try w.writeAll("void"),
775 .NoReturn, .Void => try w.writeAll("void"),
779776 .Bool => try w.writeAll("bool"),
780777 .Int => {
781778 switch (t.tag()) {
test/behavior/optional.zig+18
......@@ -118,3 +118,21 @@ fn test_cmp_optional_non_optional() !void {
118118 break :blk2 @as(?f64, 5.0);
119119 };
120120}
121
122test "unwrap function call with optional pointer return value" {
123 const S = struct {
124 fn entry() !void {
125 try expect(foo().?.* == 1234);
126 try expect(bar() == null);
127 }
128 const global: i32 = 1234;
129 fn foo() ?*const i32 {
130 return &global;
131 }
132 fn bar() ?*i32 {
133 return null;
134 }
135 };
136 try S.entry();
137 comptime try S.entry();
138}
test/behavior/optional_stage1.zig-18
......@@ -3,24 +3,6 @@ const testing = std.testing;
33const expect = testing.expect;
44const expectEqual = testing.expectEqual;
55
6test "unwrap function call with optional pointer return value" {
7 const S = struct {
8 fn entry() !void {
9 try expect(foo().?.* == 1234);
10 try expect(bar() == null);
11 }
12 const global: i32 = 1234;
13 fn foo() ?*const i32 {
14 return &global;
15 }
16 fn bar() ?*i32 {
17 return null;
18 }
19 };
20 try S.entry();
21 comptime try S.entry();
22}
23
246test "nested orelse" {
257 const S = struct {
268 fn entry() !void {