diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2023-05-28 01:45:15 +0100 |
|---|---|---|
| committer | mlugg <mlugg@mlugg.co.uk> | 2023-06-13 12:55:22 +0100 |
| commit | bcb673d94ac09ec381e5b1ad1edf64b603ac68f1 (patch) | |
| tree | 7624448f2c157b81b003935583deeaae5ec264df /test/behavior/switch.zig | |
| parent | 85e94fed1e058720460560823ac09d7b64e49b97 (diff) | |
| download | zig-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.zig | 68 |
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); +} |
