authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-10-17 01:21:20+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-10-20 23:10:13+02:00
log56fad80e8ce14a23f6642e73f545ed6c8b394929
tree7c3e6a1771e0cf96d0df459974b0b6973d486a30
parent2d361f612b426fa44861caa2ff54c716a4dd5c89

wasm: fix switch on wide integers and ?error repr


3 files changed, 170 insertions(+), 34 deletions(-)

src/codegen/wasm/CodeGen.zig+12-11
...@@ -2599,17 +2599,11 @@ const IntType = struct {...@@ -2599,17 +2599,11 @@ const IntType = struct {
2599 .one, .many, .c => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },2599 .one, .many, .c => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },
2600 .slice => unreachable,2600 .slice => unreachable,
2601 },2601 },
2602 .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))2602 .opt_type => |opt_child| {
2603 .{ .is_signed = false, .bits = 1 }2603 if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))
2604 else switch (ip.indexToKey(opt_child)) {2604 return .{ .is_signed = false, .bits = 1 };
2605 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {2605 assert(Type.fromInterned(ty_index).optionalReprIsPayload(zcu));
2606 .one, .many => switch (ptr_type.flags.is_allowzero) {2606 ty_index = opt_child;
2607 false => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },
2608 true => unreachable,
2609 },
2610 .slice, .c => unreachable,
2611 },
2612 else => unreachable,
2613 },2607 },
2614 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)2608 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)
2615 .hasRuntimeBits(zcu)) .{ .is_signed = false, .bits = zcu.errorSetBits() } else unreachable,2609 .hasRuntimeBits(zcu)) .{ .is_signed = false, .bits = zcu.errorSetBits() } else unreachable,
...@@ -6039,6 +6033,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -6039,6 +6033,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
6039 if (use_br_table) {6033 if (use_br_table) {
6040 const width = width_maybe.?;6034 const width = width_maybe.?;
60416035
6036 if (int_ty.bits > 32) {
6037 _ = try cg.intCmp(int_ty, .lt, target, try cg.resolveValue(min.?));
6038 try cg.addLabel(.br_if, branch_count - 1);
6039 _ = try cg.intCmp(int_ty, .gt, target, try cg.resolveValue(max.?));
6040 try cg.addLabel(.br_if, branch_count - 1);
6041 }
6042
6042 const br_value_original = try cg.intSub(int_ty, target, try cg.resolveValue(min.?));6043 const br_value_original = try cg.intSub(int_ty, target, try cg.resolveValue(min.?));
6043 _ = try cg.intCast(.u32, int_ty, br_value_original);6044 _ = try cg.intCast(.u32, int_ty, br_value_original);
60446045
test/behavior/optional.zig+33
...@@ -58,6 +58,39 @@ fn testNullPtrsEql() !void {...@@ -58,6 +58,39 @@ fn testNullPtrsEql() !void {
58 try expect(&number == x);58 try expect(&number == x);
59}59}
6060
61test "optional error equality" {
62 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
63 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
66
67 const S = struct {
68 fn testEql(comptime T: type, a: ?T, b: ?T, equal: bool) !void {
69 try expect((a == b) == equal);
70 try expect((a != b) == !equal);
71 }
72
73 fn doTheTest() !void {
74 try testEql(error{}, null, null, true);
75
76 try testEql(error{ A, B }, null, null, true);
77 try testEql(error{ A, B }, error.A, error.A, true);
78 try testEql(error{ A, B }, error.A, error.B, false);
79 try testEql(error{ A, B }, null, error.A, false);
80 try testEql(error{ A, B }, error.A, null, false);
81
82 try testEql(anyerror, null, null, true);
83 try testEql(anyerror, error.A, error.A, true);
84 try testEql(anyerror, error.A, error.B, false);
85 try testEql(anyerror, null, error.A, false);
86 try testEql(anyerror, error.A, null, false);
87 }
88 };
89
90 try S.doTheTest();
91 try comptime S.doTheTest();
92}
93
61test "optional with zero-bit type" {94test "optional with zero-bit type" {
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
63 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;96 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/switch.zig+125-23
...@@ -47,34 +47,136 @@ test "switch arbitrary int size" {...@@ -47,34 +47,136 @@ test "switch arbitrary int size" {
47 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
4949
50 try expect(testSwitchArbInt(u64, 0) == 0);50 const S = struct {
51 try expect(testSwitchArbInt(u64, 12) == 1);51 fn testSwitchArbInt(comptime T: type, x: T) u32 {
52 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);52 return switch (x) {
53 try expect(testSwitchArbInt(u64, 5555) == 3);53 minInt(T) => 0,
5454 10...15 => 1,
55 try expect(testSwitchArbInt(i64, minInt(i64)) == 0);55 maxInt(T) => 2,
56 try expect(testSwitchArbInt(i64, 12) == 1);56 else => 3,
57 try expect(testSwitchArbInt(i64, maxInt(i64)) == 2);57 };
58 try expect(testSwitchArbInt(i64, -1000) == 3);58 }
5959
60 try expect(testSwitchArbInt(u128, 0) == 0);60 fn doTheTest() !void {
61 try expect(testSwitchArbInt(u128, 12) == 1);61 try expect(testSwitchArbInt(u64, 0) == 0);
62 try expect(testSwitchArbInt(u128, maxInt(u128)) == 2);62 try expect(testSwitchArbInt(u64, 12) == 1);
63 try expect(testSwitchArbInt(u128, 5555) == 3);63 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);
64 try expect(testSwitchArbInt(u64, 5555) == 3);
65
66 try expect(testSwitchArbInt(i64, minInt(i64)) == 0);
67 try expect(testSwitchArbInt(i64, 12) == 1);
68 try expect(testSwitchArbInt(i64, maxInt(i64)) == 2);
69 try expect(testSwitchArbInt(i64, -1000) == 3);
70
71 try expect(testSwitchArbInt(u128, 0) == 0);
72 try expect(testSwitchArbInt(u128, 12) == 1);
73 try expect(testSwitchArbInt(u128, maxInt(u128)) == 2);
74 try expect(testSwitchArbInt(u128, 5555) == 3);
75
76 try expect(testSwitchArbInt(i128, minInt(i128)) == 0);
77 try expect(testSwitchArbInt(i128, 12) == 1);
78 try expect(testSwitchArbInt(i128, maxInt(i128)) == 2);
79 try expect(testSwitchArbInt(i128, -1000) == 3);
80 }
81 };
6482
65 try expect(testSwitchArbInt(i128, minInt(i128)) == 0);83 try S.doTheTest();
66 try expect(testSwitchArbInt(i128, 12) == 1);84 try comptime S.doTheTest();
67 try expect(testSwitchArbInt(i128, maxInt(i128)) == 2);
68 try expect(testSwitchArbInt(i128, -1000) == 3);
69}85}
7086
71fn testSwitchArbInt(comptime T: type, x: T) u32 {87test "dense switch" {
72 return switch (x) {88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
73 minInt(T) => 0,89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
74 10...15 => 1,90 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
75 maxInt(T) => 2,91 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
76 else => 3,92 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
93
94 const S = struct {
95 fn unsigned(comptime T: type, x: T) u8 {
96 return switch (x) {
97 0 => 0,
98 1 => 1,
99 2 => 2,
100 3 => 3,
101 else => 4,
102 };
103 }
104
105 fn signed(comptime T: type, x: T) u8 {
106 return switch (x) {
107 -2 => 0,
108 -1 => 1,
109 0 => 2,
110 1 => 3,
111 else => 4,
112 };
113 }
114
115 fn doTheTest() !void {
116 try expect(unsigned(u32, 0) == 0);
117 try expect(unsigned(u32, 1) == 1);
118 try expect(unsigned(u32, 2) == 2);
119 try expect(unsigned(u32, 3) == 3);
120 try expect(unsigned(u32, maxInt(u32)) == 4);
121 try expect(unsigned(u32, (1 << 16) + 1) == 4);
122
123 try expect(signed(i32, -2) == 0);
124 try expect(signed(i32, -1) == 1);
125 try expect(signed(i32, 0) == 2);
126 try expect(signed(i32, 1) == 3);
127 try expect(signed(i32, minInt(i32)) == 4);
128 try expect(signed(i32, -(1 << 16) - 2) == 4);
129 try expect(signed(i32, (1 << 16) + 1) == 4);
130
131 try expect(unsigned(u64, 0) == 0);
132 try expect(unsigned(u64, 1) == 1);
133 try expect(unsigned(u64, 2) == 2);
134 try expect(unsigned(u64, 3) == 3);
135 try expect(unsigned(u64, maxInt(u64)) == 4);
136 try expect(unsigned(u64, (1 << 32) + 1) == 4);
137
138 try expect(signed(i64, -2) == 0);
139 try expect(signed(i64, -1) == 1);
140 try expect(signed(i64, 0) == 2);
141 try expect(signed(i64, 1) == 3);
142 try expect(signed(i64, minInt(i64)) == 4);
143 try expect(signed(i64, -(1 << 32) - 2) == 4);
144 try expect(signed(i64, (1 << 32) + 1) == 4);
145
146 try expect(unsigned(u128, 0) == 0);
147 try expect(unsigned(u128, 1) == 1);
148 try expect(unsigned(u128, 2) == 2);
149 try expect(unsigned(u128, 3) == 3);
150 try expect(unsigned(u128, maxInt(u128)) == 4);
151 try expect(unsigned(u128, (1 << 64) + 1) == 4);
152
153 try expect(signed(i128, -2) == 0);
154 try expect(signed(i128, -1) == 1);
155 try expect(signed(i128, 0) == 2);
156 try expect(signed(i128, 1) == 3);
157 try expect(signed(i128, minInt(i128)) == 4);
158 try expect(signed(i128, -(1 << 64) - 2) == 4);
159 try expect(signed(i128, (1 << 64) + 1) == 4);
160
161 try expect(unsigned(u999, 0) == 0);
162 try expect(unsigned(u999, 1) == 1);
163 try expect(unsigned(u999, 2) == 2);
164 try expect(unsigned(u999, 3) == 3);
165 try expect(unsigned(u999, maxInt(u999)) == 4);
166 try expect(unsigned(u999, (1 << 499) + 1) == 4);
167
168 try expect(signed(i999, -2) == 0);
169 try expect(signed(i999, -1) == 1);
170 try expect(signed(i999, 0) == 2);
171 try expect(signed(i999, 1) == 3);
172 try expect(signed(i999, minInt(i999)) == 4);
173 try expect(signed(i999, -(1 << 499) - 2) == 4);
174 try expect(signed(i999, (1 << 499) + 1) == 4);
175 }
77 };176 };
177
178 try S.doTheTest();
179 try comptime S.doTheTest();
78}180}
79181
80test "implicit comptime switch" {182test "implicit comptime switch" {