Commit 1e5a494603
Changed files (5)
src
src/Sema.zig
@@ -15069,8 +15069,74 @@ fn beginComptimePtrMutation(
else => unreachable,
}
},
- .eu_payload_ptr => return sema.fail(block, src, "TODO comptime store to eu_payload_ptr", .{}),
- .opt_payload_ptr => return sema.fail(block, src, "TODO comptime store opt_payload_ptr", .{}),
+ .eu_payload_ptr => {
+ const eu_ptr_val = ptr_val.castTag(.eu_payload_ptr).?.data;
+ var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr_val);
+ const payload_ty = parent.ty.errorUnionPayload();
+ switch (parent.val.tag()) {
+ else => {
+ // An error union has been initialized to undefined at comptime and now we
+ // are for the first time setting the payload. We must change the
+ // representation of the error union from `undef` to `opt_payload`.
+ const arena = parent.beginArena(sema.gpa);
+ defer parent.finishArena();
+
+ const payload = try arena.create(Value.Payload.SubValue);
+ payload.* = .{
+ .base = .{ .tag = .eu_payload },
+ .data = Value.undef,
+ };
+
+ parent.val.* = Value.initPayload(&payload.base);
+
+ return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &payload.data,
+ .ty = payload_ty,
+ };
+ },
+ .eu_payload => return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &parent.val.castTag(.eu_payload).?.data,
+ .ty = payload_ty,
+ },
+ }
+ },
+ .opt_payload_ptr => {
+ const opt_ptr_val = ptr_val.castTag(.opt_payload_ptr).?.data;
+ var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr_val);
+ const payload_ty = try parent.ty.optionalChildAlloc(sema.arena);
+ switch (parent.val.tag()) {
+ .undef, .null_value => {
+ // An optional has been initialized to undefined at comptime and now we
+ // are for the first time setting the payload. We must change the
+ // representation of the optional from `undef` to `opt_payload`.
+ const arena = parent.beginArena(sema.gpa);
+ defer parent.finishArena();
+
+ const payload = try arena.create(Value.Payload.SubValue);
+ payload.* = .{
+ .base = .{ .tag = .opt_payload },
+ .data = Value.undef,
+ };
+
+ parent.val.* = Value.initPayload(&payload.base);
+
+ return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &payload.data,
+ .ty = payload_ty,
+ };
+ },
+ .opt_payload => return ComptimePtrMutationKit{
+ .decl_ref_mut = parent.decl_ref_mut,
+ .val = &parent.val.castTag(.opt_payload).?.data,
+ .ty = payload_ty,
+ },
+
+ else => unreachable,
+ }
+ },
.decl_ref => unreachable, // isComptimeMutablePtr() has been checked already
else => unreachable,
}
test/behavior/optional.zig
@@ -1,9 +1,13 @@
+const builtin = @import("builtin");
const std = @import("std");
const testing = std.testing;
const expect = testing.expect;
const expectEqual = testing.expectEqual;
test "passing an optional integer as a parameter" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
const S = struct {
fn entry() bool {
var x: i32 = 1234;
@@ -21,12 +25,18 @@ test "passing an optional integer as a parameter" {
pub const EmptyStruct = struct {};
test "optional pointer to size zero struct" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
var e = EmptyStruct{};
var o: ?*EmptyStruct = &e;
try expect(o != null);
}
test "equality compare optional pointers" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
try testNullPtrsEql();
comptime try testNullPtrsEql();
}
@@ -48,6 +58,9 @@ fn testNullPtrsEql() !void {
}
test "optional with void type" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
const Foo = struct {
x: ?void,
};
@@ -56,6 +69,9 @@ test "optional with void type" {
}
test "address of unwrap optional" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
const S = struct {
const Foo = struct {
a: i32,
@@ -73,6 +89,9 @@ test "address of unwrap optional" {
}
test "nested optional field in struct" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
const S2 = struct {
y: u8,
};
@@ -86,6 +105,9 @@ test "nested optional field in struct" {
}
test "equality compare optional with non-optional" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
try test_cmp_optional_non_optional();
comptime try test_cmp_optional_non_optional();
}
@@ -120,6 +142,9 @@ fn test_cmp_optional_non_optional() !void {
}
test "unwrap function call with optional pointer return value" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
const S = struct {
fn entry() !void {
try expect(foo().?.* == 1234);
@@ -138,6 +163,9 @@ test "unwrap function call with optional pointer return value" {
}
test "nested orelse" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
const S = struct {
fn entry() !void {
try expect(func() == null);
@@ -159,3 +187,138 @@ test "nested orelse" {
try S.entry();
comptime try S.entry();
}
+
+test "self-referential struct through a slice of optional" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const Node = struct {
+ children: []?Node,
+ data: ?u8,
+
+ fn new() Node {
+ return Node{
+ .children = undefined,
+ .data = null,
+ };
+ }
+ };
+ };
+
+ var n = S.Node.new();
+ try expect(n.data == null);
+}
+
+test "assigning to an unwrapped optional field in an inline loop" {
+ comptime var maybe_pos_arg: ?comptime_int = null;
+ inline for ("ab") |x| {
+ _ = x;
+ maybe_pos_arg = 0;
+ if (maybe_pos_arg.? != 0) {
+ @compileError("bad");
+ }
+ maybe_pos_arg.? = 10;
+ }
+}
+
+test "coerce an anon struct literal to optional struct" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const Struct = struct {
+ field: u32,
+ };
+ fn doTheTest() !void {
+ var maybe_dims: ?Struct = null;
+ maybe_dims = .{ .field = 1 };
+ try expect(maybe_dims.?.field == 1);
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "0-bit child type coerced to optional return ptr result location" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn doTheTest() !void {
+ var y = Foo{};
+ var z = y.thing();
+ try expect(z != null);
+ }
+
+ const Foo = struct {
+ pub const Bar = struct {
+ field: *Foo,
+ };
+
+ pub fn thing(self: *Foo) ?Bar {
+ return Bar{ .field = self };
+ }
+ };
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "0-bit child type coerced to optional" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn doTheTest() !void {
+ var it: Foo = .{
+ .list = undefined,
+ };
+ try expect(it.foo() != null);
+ }
+
+ const Empty = struct {};
+ const Foo = struct {
+ list: [10]Empty,
+
+ fn foo(self: *Foo) ?*Empty {
+ const data = &self.list[0];
+ return data;
+ }
+ };
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "array of optional unaligned types" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const Enum = enum { one, two, three };
+
+ const SomeUnion = union(enum) {
+ Num: Enum,
+ Other: u32,
+ };
+
+ const values = [_]?SomeUnion{
+ SomeUnion{ .Num = .one },
+ SomeUnion{ .Num = .two },
+ SomeUnion{ .Num = .three },
+ SomeUnion{ .Num = .one },
+ SomeUnion{ .Num = .two },
+ SomeUnion{ .Num = .three },
+ };
+
+ // The index must be a runtime value
+ var i: usize = 0;
+ try expectEqual(Enum.one, values[i].?.Num);
+ i += 1;
+ try expectEqual(Enum.two, values[i].?.Num);
+ i += 1;
+ try expectEqual(Enum.three, values[i].?.Num);
+ i += 1;
+ try expectEqual(Enum.one, values[i].?.Num);
+ i += 1;
+ try expectEqual(Enum.two, values[i].?.Num);
+ i += 1;
+ try expectEqual(Enum.three, values[i].?.Num);
+}
test/behavior/optional_llvm.zig
@@ -1,27 +0,0 @@
-const std = @import("std");
-const testing = std.testing;
-const expect = testing.expect;
-const expectEqual = testing.expectEqual;
-const builtin = @import("builtin");
-
-test "self-referential struct through a slice of optional" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- const S = struct {
- const Node = struct {
- children: []?Node,
- data: ?u8,
-
- fn new() Node {
- return Node{
- .children = undefined,
- .data = null,
- };
- }
- };
- };
-
- var n = S.Node.new();
- try expect(n.data == null);
-}
test/behavior/optional_stage1.zig
@@ -1,108 +0,0 @@
-const std = @import("std");
-const testing = std.testing;
-const expect = testing.expect;
-const expectEqual = testing.expectEqual;
-
-test "assigning to an unwrapped optional field in an inline loop" {
- comptime var maybe_pos_arg: ?comptime_int = null;
- inline for ("ab") |x| {
- _ = x;
- maybe_pos_arg = 0;
- if (maybe_pos_arg.? != 0) {
- @compileError("bad");
- }
- maybe_pos_arg.? = 10;
- }
-}
-
-test "coerce an anon struct literal to optional struct" {
- const S = struct {
- const Struct = struct {
- field: u32,
- };
- fn doTheTest() !void {
- var maybe_dims: ?Struct = null;
- maybe_dims = .{ .field = 1 };
- try expect(maybe_dims.?.field == 1);
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "0-bit child type coerced to optional return ptr result location" {
- const S = struct {
- fn doTheTest() !void {
- var y = Foo{};
- var z = y.thing();
- try expect(z != null);
- }
-
- const Foo = struct {
- pub const Bar = struct {
- field: *Foo,
- };
-
- pub fn thing(self: *Foo) ?Bar {
- return Bar{ .field = self };
- }
- };
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "0-bit child type coerced to optional" {
- const S = struct {
- fn doTheTest() !void {
- var it: Foo = .{
- .list = undefined,
- };
- try expect(it.foo() != null);
- }
-
- const Empty = struct {};
- const Foo = struct {
- list: [10]Empty,
-
- fn foo(self: *Foo) ?*Empty {
- const data = &self.list[0];
- return data;
- }
- };
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "array of optional unaligned types" {
- const Enum = enum { one, two, three };
-
- const SomeUnion = union(enum) {
- Num: Enum,
- Other: u32,
- };
-
- const values = [_]?SomeUnion{
- SomeUnion{ .Num = .one },
- SomeUnion{ .Num = .two },
- SomeUnion{ .Num = .three },
- SomeUnion{ .Num = .one },
- SomeUnion{ .Num = .two },
- SomeUnion{ .Num = .three },
- };
-
- // The index must be a runtime value
- var i: usize = 0;
- try expectEqual(Enum.one, values[i].?.Num);
- i += 1;
- try expectEqual(Enum.two, values[i].?.Num);
- i += 1;
- try expectEqual(Enum.three, values[i].?.Num);
- i += 1;
- try expectEqual(Enum.one, values[i].?.Num);
- i += 1;
- try expectEqual(Enum.two, values[i].?.Num);
- i += 1;
- try expectEqual(Enum.three, values[i].?.Num);
-}
test/behavior.zig
@@ -33,7 +33,7 @@ test {
_ = @import("behavior/hasdecl.zig");
_ = @import("behavior/hasfield.zig");
_ = @import("behavior/namespace_depends_on_compile_var.zig");
- _ = @import("behavior/optional_llvm.zig");
+ _ = @import("behavior/optional.zig");
_ = @import("behavior/prefetch.zig");
_ = @import("behavior/pub_enum.zig");
_ = @import("behavior/slice_sentinel_comptime.zig");
@@ -69,7 +69,6 @@ test {
_ = @import("behavior/inttoptr.zig");
_ = @import("behavior/member_func.zig");
_ = @import("behavior/null.zig");
- _ = @import("behavior/optional.zig");
_ = @import("behavior/pointers.zig");
_ = @import("behavior/ptrcast.zig");
_ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
@@ -154,7 +153,6 @@ test {
_ = @import("behavior/ir_block_deps.zig");
_ = @import("behavior/misc.zig");
_ = @import("behavior/muladd.zig");
- _ = @import("behavior/optional_stage1.zig");
_ = @import("behavior/popcount_stage1.zig");
_ = @import("behavior/reflection.zig");
_ = @import("behavior/select.zig");