Commit 6f0601c793

Veikka Tuominen <git@vexu.eu>
2022-02-19 20:49:30
stage2: support anon init through error unions and optionals at runtime
1 parent 27c63bf
Changed files (2)
src
test
behavior
src/Sema.zig
@@ -2603,8 +2603,8 @@ fn zirArrayBasePtr(
     const start_ptr = sema.resolveInst(inst_data.operand);
     var base_ptr = start_ptr;
     while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
-        .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false),
-        .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false),
+        .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
+        .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
         else => break,
     };
 
@@ -2630,8 +2630,8 @@ fn zirFieldBasePtr(
     const start_ptr = sema.resolveInst(inst_data.operand);
     var base_ptr = start_ptr;
     while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
-        .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false),
-        .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false),
+        .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
+        .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
         else => break,
     };
 
@@ -5263,7 +5263,7 @@ fn zirOptionalPayloadPtr(
     const optional_ptr = sema.resolveInst(inst_data.operand);
     const src = inst_data.src();
 
-    return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check);
+    return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
 }
 
 fn analyzeOptionalPayloadPtr(
@@ -5272,6 +5272,7 @@ fn analyzeOptionalPayloadPtr(
     src: LazySrcLoc,
     optional_ptr: Air.Inst.Ref,
     safety_check: bool,
+    initializing: bool,
 ) CompileError!Air.Inst.Ref {
     const optional_ptr_ty = sema.typeOf(optional_ptr);
     assert(optional_ptr_ty.zigTypeTag() == .Pointer);
@@ -5290,7 +5291,7 @@ fn analyzeOptionalPayloadPtr(
 
     if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {
         if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| {
-            if (safety_check) {
+            if (!initializing) {
                 if (val.isNull()) {
                     return sema.fail(block, src, "unable to unwrap null", .{});
                 }
@@ -5308,7 +5309,10 @@ fn analyzeOptionalPayloadPtr(
         const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);
         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
     }
-    return block.addTyOp(.optional_payload_ptr, child_pointer, optional_ptr);
+    return block.addTyOp(if (initializing)
+        .optional_payload_ptr_set
+    else
+        .optional_payload_ptr, child_pointer, optional_ptr);
 }
 
 /// Value in, value out.
@@ -5412,7 +5416,7 @@ fn zirErrUnionPayloadPtr(
     const operand = sema.resolveInst(inst_data.operand);
     const src = inst_data.src();
 
-    return sema.analyzeErrUnionPayloadPtr(block, src, operand, safety_check);
+    return sema.analyzeErrUnionPayloadPtr(block, src, operand, safety_check, false);
 }
 
 fn analyzeErrUnionPayloadPtr(
@@ -5421,6 +5425,7 @@ fn analyzeErrUnionPayloadPtr(
     src: LazySrcLoc,
     operand: Air.Inst.Ref,
     safety_check: bool,
+    initializing: bool,
 ) CompileError!Air.Inst.Ref {
     const operand_ty = sema.typeOf(operand);
     assert(operand_ty.zigTypeTag() == .Pointer);
@@ -5437,7 +5442,7 @@ fn analyzeErrUnionPayloadPtr(
 
     if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
         if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {
-            if (safety_check) {
+            if (!initializing) {
                 if (val.getError()) |name| {
                     return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
                 }
@@ -5455,7 +5460,10 @@ fn analyzeErrUnionPayloadPtr(
         const is_non_err = try block.addUnOp(.is_err, operand);
         try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
     }
-    return block.addTyOp(.unwrap_errunion_payload_ptr, operand_pointer_ty, operand);
+    return block.addTyOp(if (initializing)
+        .errunion_payload_ptr_set
+    else
+        .unwrap_errunion_payload_ptr, operand_pointer_ty, operand);
 }
 
 /// Value in, value out
test/behavior/struct.zig
@@ -1202,33 +1202,32 @@ test "for loop over pointers to struct, getting field from struct pointer" {
 
 test "anon init through error unions and optionals" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-    if (true) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
 
     const S = struct {
         a: u32,
 
         fn foo() anyerror!?anyerror!@This() {
-            return @This(){ .a = 1 };
+            return .{ .a = 1 };
         }
         fn bar() ?anyerror![2]u8 {
-            return [2]u8{ 1, 2 };
+            return .{ 1, 2 };
         }
 
         fn doTheTest() !void {
-            var a = ((foo() catch unreachable).?) catch unreachable;
-            var b = (bar().?) catch unreachable;
+            var a = try (try foo()).?;
+            var b = try bar().?;
             try expect(a.a + b[1] == 3);
         }
     };
 
     try S.doTheTest();
-    comptime try S.doTheTest();
+    // comptime try S.doTheTest(); // TODO
 }
 
 test "anon init through optional" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-    // not sure why this is needed, we only do the test at comptime
-    if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
+    if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
 
     const S = struct {
         a: u32,
@@ -1239,14 +1238,14 @@ test "anon init through optional" {
             try expect(s.?.a == 1);
         }
     };
-    // try S.doTheTest(); // TODO
+
+    try S.doTheTest();
     comptime try S.doTheTest();
 }
 
 test "anon init through error union" {
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-    // not sure why this is needed, we only do the test at comptime
-    if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
+    if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
 
     const S = struct {
         a: u32,
@@ -1257,6 +1256,7 @@ test "anon init through error union" {
             try expect((try s).a == 1);
         }
     };
-    // try S.doTheTest(); // TODO
+
+    try S.doTheTest();
     comptime try S.doTheTest();
 }