aboutsummaryrefslogtreecommitdiff
path: root/test/behavior/switch.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2023-05-28 01:45:15 +0100
committermlugg <mlugg@mlugg.co.uk>2023-06-13 12:55:22 +0100
commitbcb673d94ac09ec381e5b1ad1edf64b603ac68f1 (patch)
tree7624448f2c157b81b003935583deeaae5ec264df /test/behavior/switch.zig
parent85e94fed1e058720460560823ac09d7b64e49b97 (diff)
downloadzig-bcb673d94ac09ec381e5b1ad1edf64b603ac68f1.tar.gz
zig-bcb673d94ac09ec381e5b1ad1edf64b603ac68f1.zip
Sema: resolve union payload switch captures with peer type resolution
This is a bit harder than it seems at first glance. Actually resolving the type is the easy part: the interesting thing is actually getting the capture value. We split this into three cases: * If all payload types are the same (as is required in status quo), we can just do what we already do: get the first field value. * If all payloads are in-memory coercible to the resolved type, we still fetch the first field, but we also emit a `bitcast` to convert to the resolved type. * Otherwise, we need to handle each case separately. We emit a nested `switch_br` which, for each possible case, gets the corresponding union field, and coerces it to the resolved type. As an optimization, the inner switch's 'else' prong is used for any peer which is in-memory coercible to the target type, and the bitcast approach described above is used. Pointer captures have the additional constraint that all payload types must be in-memory coercible to the resolved type. Resolves: #2812
Diffstat (limited to 'test/behavior/switch.zig')
-rw-r--r--test/behavior/switch.zig68
1 files changed, 68 insertions, 0 deletions
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index 3f6cd37298..72a36c9883 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -1,5 +1,6 @@
const builtin = @import("builtin");
const std = @import("std");
+const assert = std.debug.assert;
const expect = std.testing.expect;
const expectError = std.testing.expectError;
const expectEqual = std.testing.expectEqual;
@@ -717,3 +718,70 @@ test "comptime inline switch" {
try expectEqual(u32, value);
}
+
+test "switch capture peer type resolution" {
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
+ const U = union(enum) {
+ a: u32,
+ b: u64,
+ fn innerVal(u: @This()) u64 {
+ switch (u) {
+ .a, .b => |x| return x,
+ }
+ }
+ };
+
+ try expectEqual(@as(u64, 100), U.innerVal(.{ .a = 100 }));
+ try expectEqual(@as(u64, 200), U.innerVal(.{ .b = 200 }));
+}
+
+test "switch capture peer type resolution for in-memory coercible payloads" {
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
+ const T1 = c_int;
+ const T2 = @Type(@typeInfo(T1));
+
+ comptime assert(T1 != T2);
+
+ const U = union(enum) {
+ a: T1,
+ b: T2,
+ fn innerVal(u: @This()) c_int {
+ switch (u) {
+ .a, .b => |x| return x,
+ }
+ }
+ };
+
+ try expectEqual(@as(c_int, 100), U.innerVal(.{ .a = 100 }));
+ try expectEqual(@as(c_int, 200), U.innerVal(.{ .b = 200 }));
+}
+
+test "switch pointer capture peer type resolution" {
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
+ const T1 = c_int;
+ const T2 = @Type(@typeInfo(T1));
+
+ comptime assert(T1 != T2);
+
+ const U = union(enum) {
+ a: T1,
+ b: T2,
+ fn innerVal(u: *@This()) *c_int {
+ switch (u.*) {
+ .a, .b => |*ptr| return ptr,
+ }
+ }
+ };
+
+ var ua: U = .{ .a = 100 };
+ var ub: U = .{ .b = 200 };
+
+ ua.innerVal().* = 111;
+ ub.innerVal().* = 222;
+
+ try expectEqual(U{ .a = 111 }, ua);
+ try expectEqual(U{ .b = 222 }, ub);
+}