mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
Merge pull request 'Sema: implement switch for packed structs/unions' (#31464) from justusk/zig:packed-switch into master
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31464 Reviewed-by: Andrew Kelley <andrew@ziglang.org>
This commit is contained in:
@@ -199,3 +199,23 @@ test "packed union with explicit backing integer" {
|
||||
try U.check(.{ .raw = -2 });
|
||||
try comptime U.check(.{ .raw = -2 });
|
||||
}
|
||||
|
||||
test "packed union equality" {
|
||||
const Foo = packed union {
|
||||
a: u4,
|
||||
b: i4,
|
||||
};
|
||||
|
||||
const S = struct {
|
||||
fn doTest(x: Foo, y: Foo) !void {
|
||||
try expect(x == y);
|
||||
try expect(!(x != y));
|
||||
}
|
||||
};
|
||||
|
||||
const x: Foo = .{ .a = 3 };
|
||||
const y: Foo = .{ .b = 3 };
|
||||
|
||||
try S.doTest(x, y);
|
||||
comptime try S.doTest(x, y);
|
||||
}
|
||||
|
||||
@@ -1327,3 +1327,135 @@ test "single range switch prong capture" {
|
||||
try S.doTheTest(2);
|
||||
try comptime S.doTheTest(2);
|
||||
}
|
||||
|
||||
test "switch on packed struct" {
|
||||
const P = packed struct {
|
||||
a: u1,
|
||||
b: u1,
|
||||
|
||||
fn doTheTest(p: @This()) !void {
|
||||
switch (p) {
|
||||
.{ .a = 0, .b = 1 } => {},
|
||||
else => return error.TestFailed,
|
||||
}
|
||||
|
||||
switch (p) {
|
||||
.{ .a = 0, .b = 1 } => {},
|
||||
.{ .a = 0, .b = 0 },
|
||||
.{ .a = 1, .b = 0 },
|
||||
.{ .a = 1, .b = 1 },
|
||||
=> return error.TestFailed,
|
||||
}
|
||||
|
||||
switch (p) {
|
||||
inline else => |val| {
|
||||
if (val != @This(){ .a = 0, .b = 1 }) return error.TestFailed;
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
try P.doTheTest(.{ .a = 0, .b = 1 });
|
||||
try comptime P.doTheTest(.{ .a = 0, .b = 1 });
|
||||
}
|
||||
|
||||
test "switch on packed union" {
|
||||
const P = packed union(u2) {
|
||||
a: u2,
|
||||
b: i2,
|
||||
c: packed struct(u2) { x: u1, y: i1 },
|
||||
|
||||
fn doTheTest(p: @This()) !void {
|
||||
switch (p) {
|
||||
.{ .a = 1 } => {},
|
||||
else => return error.TestFailed,
|
||||
}
|
||||
|
||||
switch (p) {
|
||||
.{ .a = 1 } => {},
|
||||
.{ .a = 0 },
|
||||
.{ .a = 2 },
|
||||
.{ .a = 3 },
|
||||
=> return error.TestFailed,
|
||||
}
|
||||
|
||||
switch (p) {
|
||||
.{ .a = 1 } => {},
|
||||
.{ .a = 0 },
|
||||
.{ .b = -2 },
|
||||
.{ .b = -1 },
|
||||
=> return error.TestFailed,
|
||||
}
|
||||
|
||||
switch (p) {
|
||||
.{ .c = .{ .x = 1, .y = 0 } } => {},
|
||||
.{ .b = 0 },
|
||||
.{ .a = 2 },
|
||||
.{ .c = .{ .x = 1, .y = -1 } },
|
||||
=> return error.TestFailed,
|
||||
}
|
||||
|
||||
switch (p) {
|
||||
inline else => |val| {
|
||||
if (val != @This(){ .c = .{ .x = 1, .y = 0 } }) return error.TestFailed;
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
try P.doTheTest(.{ .a = 1 });
|
||||
try comptime P.doTheTest(.{ .a = 1 });
|
||||
}
|
||||
|
||||
test "switch on nested packed containers" {
|
||||
if (builtin.object_format == .c) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/31467
|
||||
|
||||
const P = packed struct {
|
||||
iu: u17,
|
||||
is: i31,
|
||||
b: bool,
|
||||
e: enum(u5) { a = 5, b = 3, c = 12 },
|
||||
un: packed union {
|
||||
a: i9,
|
||||
b: u9,
|
||||
c: packed struct(u9) { a: i5, b: u4 },
|
||||
},
|
||||
p: packed struct(u9) { a: u3, b: u6 },
|
||||
|
||||
fn doTheTest(p: @This()) !void {
|
||||
switch (p) {
|
||||
.{
|
||||
.iu = 72,
|
||||
.is = 124,
|
||||
.b = false,
|
||||
.e = .c,
|
||||
.un = .{ .b = 13 },
|
||||
.p = .{ .a = 0, .b = 12 },
|
||||
} => return error.TestFailed,
|
||||
.{
|
||||
.iu = 129,
|
||||
.is = -162784612,
|
||||
.b = true,
|
||||
.e = .a,
|
||||
.un = .{ .c = .{ .a = -3, .b = 9 } },
|
||||
.p = .{ .a = 2, .b = 17 },
|
||||
} => {},
|
||||
else => return error.TestFailed,
|
||||
}
|
||||
}
|
||||
};
|
||||
try P.doTheTest(.{
|
||||
.iu = 129,
|
||||
.is = -162784612,
|
||||
.b = true,
|
||||
.e = .a,
|
||||
.un = .{ .c = .{ .a = -3, .b = 9 } },
|
||||
.p = .{ .a = 2, .b = 17 },
|
||||
});
|
||||
try comptime P.doTheTest(.{
|
||||
.iu = 129,
|
||||
.is = -162784612,
|
||||
.b = true,
|
||||
.e = .a,
|
||||
.un = .{ .c = .{ .a = -3, .b = 9 } },
|
||||
.p = .{ .a = 2, .b = 17 },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -509,3 +509,58 @@ test "switch loop for error handling" {
|
||||
try S.doTheTest();
|
||||
try comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "switch loop with packed structs" {
|
||||
const P = packed struct {
|
||||
a: u7,
|
||||
b: u20,
|
||||
|
||||
fn doTheTest(p: @This()) !void {
|
||||
const result = s: switch (p) {
|
||||
.{ .a = 5, .b = 10 } => |x| x,
|
||||
else => |x| continue :s .{ .a = x.a, .b = x.b + 1 },
|
||||
};
|
||||
try expect(result == @This(){ .a = 5, .b = 10 });
|
||||
}
|
||||
};
|
||||
try P.doTheTest(.{ .a = 5, .b = 0 });
|
||||
try comptime P.doTheTest(.{ .a = 5, .b = 0 });
|
||||
}
|
||||
|
||||
test "switch loop with packed unions" {
|
||||
const P = packed union {
|
||||
a: u7,
|
||||
b: i7,
|
||||
|
||||
fn doTheTest(p: @This()) !void {
|
||||
const result = s: switch (p) {
|
||||
.{ .a = 10 } => |x| x,
|
||||
else => |x| continue :s .{ .b = @intCast(x.a + 1) },
|
||||
};
|
||||
try expect(result == @This(){ .b = 10 });
|
||||
}
|
||||
};
|
||||
try P.doTheTest(.{ .a = 5 });
|
||||
try comptime P.doTheTest(.{ .a = 5 });
|
||||
}
|
||||
|
||||
test "switch loop with packed unions with OPV" {
|
||||
const P = packed union {
|
||||
a: u0,
|
||||
b: i0,
|
||||
|
||||
fn doTheTest(p: @This()) !void {
|
||||
var looped = false;
|
||||
s: switch (p) {
|
||||
.{ .b = 0 } => |x| {
|
||||
comptime assert(x.a == 0);
|
||||
if (looped) break :s;
|
||||
looped = true;
|
||||
continue :s .{ .a = 0 };
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
try P.doTheTest(.{ .a = 0 });
|
||||
try comptime P.doTheTest(.{ .a = 0 });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
export fn entry1() void {
|
||||
switch (@as(anyerror, error.MyError)) {
|
||||
error.MyError, error.MyOtherError => |*err| _ = err,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
export fn entry2() void {
|
||||
switch (@as(anyerror, error.MyError)) {
|
||||
inline error.MyError, error.MyOtherError => |*err| _ = err,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
export fn entry3() void {
|
||||
switch (@as(anyerror, error.MyError)) {
|
||||
else => |*err| _ = err,
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :3:47: error: error set cannot be captured by reference
|
||||
// :10:54: error: error set cannot be captured by reference
|
||||
// :17:18: error: error set cannot be captured by reference
|
||||
@@ -0,0 +1,15 @@
|
||||
const P = packed union(u8) {
|
||||
a: u8,
|
||||
b: i8,
|
||||
};
|
||||
|
||||
export fn foo(p: P) void {
|
||||
switch (p) {
|
||||
.{ .a = 123 } => |_, tag| _ = tag,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :8:30: error: cannot capture tag of packed union
|
||||
@@ -0,0 +1,25 @@
|
||||
const Auto = struct {
|
||||
a: u8,
|
||||
};
|
||||
export fn entry1(a: u8) void {
|
||||
const s: Auto = .{ .a = a };
|
||||
switch (s) {
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
const Extern = extern struct {
|
||||
a: u8,
|
||||
};
|
||||
export fn entry2(s: Extern) void {
|
||||
switch (s) {
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :6:13: error: switch on struct with auto layout
|
||||
// :1:14: note: consider 'packed struct' here
|
||||
// :15:13: error: switch on struct with extern layout
|
||||
// :11:23: note: consider 'packed struct' here
|
||||
@@ -0,0 +1,41 @@
|
||||
const S = packed struct(u2) {
|
||||
a: u2,
|
||||
};
|
||||
export fn entry1(x: u8) void {
|
||||
const s: S = .{ .a = @intCast(x) };
|
||||
switch (s) {
|
||||
.{ .a = 0b00 }, .{ .a = 0b01 }, .{ .a = 0b10 }, .{ .a = 0b11 } => {},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
export fn entry2(x: u8) void {
|
||||
const s: S = .{ .a = @intCast(x) };
|
||||
switch (s) {
|
||||
.{ .a = 0b00 }, .{ .a = 0b01 }, .{ .a = 0b11 } => {},
|
||||
}
|
||||
}
|
||||
|
||||
const U = packed union(u2) {
|
||||
a: u2,
|
||||
b: i2,
|
||||
};
|
||||
export fn entry3(x: u8) void {
|
||||
const u: U = .{ .a = @intCast(x) };
|
||||
switch (u) {
|
||||
.{ .a = 0b00 }, .{ .a = 0b01 }, .{ .a = 0b10 }, .{ .a = 0b11 } => {},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
export fn entry4(x: u8) void {
|
||||
const u: U = .{ .a = @intCast(x) };
|
||||
switch (u) {
|
||||
.{ .a = 0b00 }, .{ .a = 0b01 }, .{ .a = 0b11 } => {},
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :8:14: error: unreachable else prong; all cases already handled
|
||||
// :13:5: error: switch must handle all possibilities
|
||||
// :26:14: error: unreachable else prong; all cases already handled
|
||||
// :31:5: error: switch must handle all possibilities
|
||||
Reference in New Issue
Block a user