stage2: support anon init through error unions and optionals at runtime

This commit is contained in:
Veikka Tuominen
2022-02-19 21:49:30 +02:00
parent 27c63bf433
commit 6f0601c793
2 changed files with 30 additions and 22 deletions

View File

@@ -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

View File

@@ -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();
}