aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-02-25 12:54:40 +0200
committerAndrew Kelley <andrew@ziglang.org>2022-02-26 12:51:23 -0700
commitee149aaa03e586e48c32cce09bf488ae0e88d053 (patch)
tree786f7b54e7e47027ee66e3fd2c412bed4a31b7bf
parentb3aa1ab693ac160a07c44f07c7b90577039860a1 (diff)
downloadzig-ee149aaa03e586e48c32cce09bf488ae0e88d053.tar.gz
zig-ee149aaa03e586e48c32cce09bf488ae0e88d053.zip
stage2: actually coerce in coerce_result_ptr at comptime
-rw-r--r--src/Sema.zig31
-rw-r--r--src/type.zig4
-rw-r--r--test/behavior/cast.zig6
-rw-r--r--test/behavior/error.zig7
-rw-r--r--test/behavior/struct.zig25
5 files changed, 63 insertions, 10 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 41398016e5..4f08fb12d0 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -1598,11 +1598,37 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
// we cannot do it.
if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| {
if (ptr_val.isComptimeMutablePtr()) {
+ const sentinel_val = try sema.addConstant(pointee_ty, Value.initTag(.unreachable_value));
+ const coerced = try sema.coerce(block, sema.typeOf(ptr).childType(), sentinel_val, src);
+
+ var res_ptr = ptr_val;
+ var cur_val = (try sema.resolveMaybeUndefVal(block, .unneeded, coerced)).?;
+ while (true) switch (cur_val.tag()) {
+ .unreachable_value => break,
+ .opt_payload => {
+ res_ptr = try Value.Tag.opt_payload_ptr.create(sema.arena, res_ptr);
+ cur_val = cur_val.castTag(.opt_payload).?.data;
+ },
+ .eu_payload => {
+ res_ptr = try Value.Tag.eu_payload_ptr.create(sema.arena, res_ptr);
+ cur_val = cur_val.castTag(.eu_payload).?.data;
+ },
+ else => {
+ if (std.debug.runtime_safety) {
+ std.debug.panic("unexpected Value tag for coerce_result_ptr: {s}", .{
+ cur_val.tag(),
+ });
+ } else {
+ unreachable;
+ }
+ },
+ };
+
const ptr_ty = try Type.ptr(sema.arena, .{
.pointee_type = pointee_ty,
.@"addrspace" = addr_space,
});
- return sema.addConstant(ptr_ty, ptr_val);
+ return sema.addConstant(ptr_ty, res_ptr);
}
}
@@ -1673,7 +1699,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
}
},
}
- } else unreachable; // TODO should not need else unreachable
+ }
}
pub fn analyzeStructDecl(
@@ -16937,7 +16963,6 @@ fn wrapErrorUnionPayload(
const dest_payload_ty = dest_ty.errorUnionPayload();
const coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src);
if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| {
- if (val.isUndef()) return sema.addConstUndef(dest_ty);
return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val));
}
try sema.requireRuntimeBlock(block, inst_src);
diff --git a/src/type.zig b/src/type.zig
index 4eb78b0656..581465c51a 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -3980,7 +3980,7 @@ pub const Type = extern union {
pub fn structFields(ty: Type) Module.Struct.Fields {
switch (ty.tag()) {
- .empty_struct => return .{},
+ .empty_struct, .empty_struct_literal => return .{},
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
assert(struct_obj.haveFieldTypes());
@@ -3996,7 +3996,7 @@ pub const Type = extern union {
const struct_obj = ty.castTag(.@"struct").?.data;
return struct_obj.fields.count();
},
- .empty_struct => return 0,
+ .empty_struct, .empty_struct_literal => return 0,
.tuple => return ty.castTag(.tuple).?.data.types.len,
else => unreachable,
}
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index 0ddbf6458a..50d99897c8 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -371,7 +371,9 @@ fn testPeerResolveArrayConstSlice(b: bool) !void {
}
test "implicitly cast from T to anyerror!?T" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try castToOptionalTypeError(1);
comptime try castToOptionalTypeError(1);
@@ -387,7 +389,7 @@ fn castToOptionalTypeError(z: i32) !void {
const f = z;
const g: anyerror!?i32 = f;
- _ = g catch {};
+ _ = try g;
const a = A{ .a = z };
const b: anyerror!?A = a;
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index 028bd26047..82814dc587 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -294,10 +294,11 @@ fn quux_1() !i32 {
}
test "error: Zero sized error set returned with value payload crash" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- _ = foo3(0) catch {};
- _ = comptime foo3(0) catch {};
+ _ = try foo3(0);
+ _ = comptime try foo3(0);
}
const Error = error{};
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index a1d60632a9..1da2b0373d 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -1237,3 +1237,28 @@ test "anon init through error union" {
try S.doTheTest();
comptime try S.doTheTest();
}
+
+test "typed init through error unions and optionals" {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+ if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ a: u32,
+
+ fn foo() anyerror!?anyerror!@This() {
+ return @This(){ .a = 1 };
+ }
+ fn bar() ?anyerror![2]u8 {
+ return [2]u8{ 1, 2 };
+ }
+
+ fn doTheTest() !void {
+ var a = try (try foo()).?;
+ var b = try bar().?;
+ try expect(a.a + b[1] == 3);
+ }
+ };
+
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}