stage2: support anon init through error unions and optionals at runtime
This commit is contained in:
28
src/Sema.zig
28
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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user