authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-17 20:45:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-17 20:45:55-07:00
log84c2c47fae82e913286a2306d8947252ae3a42f7
treea57dc1f9a211f3852496988ae1e09a222e9d6f29
parent2600978a9ddc295c347fd6ffe7c6ba20931b956e

Sema: implement else capture value

The ZIR instructions `switch_capture_else` and `switch_capture_ref` are removed because they are not needed. Instead, the prong index is set to max int for the special prong. Else prong with error sets is not handled yet. Adds a new behavior test because there was not a prior on to cover only the capture value of else on a switch.

8 files changed, 71 insertions(+), 61 deletions(-)

src/AstGen.zig+9-8
......@@ -2198,8 +2198,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
21982198 .switch_capture_ref,
21992199 .switch_capture_multi,
22002200 .switch_capture_multi_ref,
2201 .switch_capture_else,
2202 .switch_capture_else_ref,
22032201 .struct_init_empty,
22042202 .struct_init,
22052203 .struct_init_ref,
......@@ -5758,16 +5756,19 @@ fn switchExpr(
57585756 }
57595757 if (case_node == special_node) {
57605758 const capture_tag: Zir.Inst.Tag = if (is_ptr)
5761 .switch_capture_else_ref
5759 .switch_capture_ref
57625760 else
5763 .switch_capture_else;
5761 .switch_capture;
57645762 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
57655763 try astgen.instructions.append(gpa, .{
57665764 .tag = capture_tag,
5767 .data = .{ .switch_capture = .{
5768 .switch_inst = switch_block,
5769 .prong_index = undefined,
5770 } },
5765 .data = .{
5766 .switch_capture = .{
5767 .switch_inst = switch_block,
5768 // Max int communicates that this is the else/underscore prong.
5769 .prong_index = std.math.maxInt(u32),
5770 },
5771 },
57715772 });
57725773 } else {
57735774 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
src/Sema.zig+21-22
......@@ -669,8 +669,6 @@ fn analyzeBodyInner(
669669 .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
670670 .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
671671 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
672 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
673 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
674672 .type_info => try sema.zirTypeInfo(block, inst),
675673 .size_of => try sema.zirSizeOf(block, inst),
676674 .bit_size_of => try sema.zirBitSizeOf(block, inst),
......@@ -6071,6 +6069,27 @@ fn zirSwitchCapture(
60716069 const operand_ptr_ty = sema.typeOf(operand_ptr);
60726070 const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty;
60736071
6072 if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) {
6073 // It is the else/`_` prong.
6074 switch (operand_ty.zigTypeTag()) {
6075 .ErrorSet => {
6076 return sema.fail(block, operand_src, "TODO implement Sema for zirSwitchCaptureElse for error sets", .{});
6077 },
6078 else => {},
6079 }
6080 if (is_ref) {
6081 assert(operand_is_ref);
6082 return operand_ptr;
6083 }
6084
6085 const operand = if (operand_is_ref)
6086 try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
6087 else
6088 operand_ptr;
6089
6090 return operand;
6091 }
6092
60746093 if (is_multi) {
60756094 return sema.fail(block, switch_src, "TODO implement Sema for switch capture multi", .{});
60766095 }
......@@ -6137,26 +6156,6 @@ fn zirSwitchCapture(
61376156 }
61386157}
61396158
6140fn zirSwitchCaptureElse(
6141 sema: *Sema,
6142 block: *Block,
6143 inst: Zir.Inst.Index,
6144 is_ref: bool,
6145) CompileError!Air.Inst.Ref {
6146 const tracy = trace(@src());
6147 defer tracy.end();
6148
6149 const zir_datas = sema.code.instructions.items(.data);
6150 const capture_info = zir_datas[inst].switch_capture;
6151 const switch_info = zir_datas[capture_info.switch_inst].pl_node;
6152 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index).data;
6153 const src = switch_info.src();
6154 const operand_is_ref = switch_extra.bits.is_ref;
6155 assert(!is_ref or operand_is_ref);
6156
6157 return sema.fail(block, src, "TODO implement Sema for zirSwitchCaptureElse", .{});
6158}
6159
61606159fn zirSwitchCond(
61616160 sema: *Sema,
61626161 block: *Block,
src/Zir.zig+9-11
......@@ -625,10 +625,14 @@ pub const Inst = struct {
625625 switch_cond_ref,
626626 /// Produces the capture value for a switch prong.
627627 /// Uses the `switch_capture` field.
628 /// If the `prong_index` field is max int, it means this is the capture
629 /// for the else/`_` prong.
628630 switch_capture,
629631 /// Produces the capture value for a switch prong.
630632 /// Result is a pointer to the value.
631633 /// Uses the `switch_capture` field.
634 /// If the `prong_index` field is max int, it means this is the capture
635 /// for the else/`_` prong.
632636 switch_capture_ref,
633637 /// Produces the capture value for a switch prong.
634638 /// The prong is one of the multi cases.
......@@ -639,13 +643,6 @@ pub const Inst = struct {
639643 /// Result is a pointer to the value.
640644 /// Uses the `switch_capture` field.
641645 switch_capture_multi_ref,
642 /// Produces the capture value for the else/'_' switch prong.
643 /// Uses the `switch_capture` field.
644 switch_capture_else,
645 /// Produces the capture value for the else/'_' switch prong.
646 /// Result is a pointer to the value.
647 /// Uses the `switch_capture` field.
648 switch_capture_else_ref,
649646 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
650647 /// initialization expression, and emits compile errors for duplicate fields
651648 /// as well as missing fields, if applicable.
......@@ -1082,8 +1079,6 @@ pub const Inst = struct {
10821079 .switch_capture_ref,
10831080 .switch_capture_multi,
10841081 .switch_capture_multi_ref,
1085 .switch_capture_else,
1086 .switch_capture_else_ref,
10871082 .switch_block,
10881083 .switch_cond,
10891084 .switch_cond_ref,
......@@ -1340,8 +1335,6 @@ pub const Inst = struct {
13401335 .switch_capture_ref = .switch_capture,
13411336 .switch_capture_multi = .switch_capture,
13421337 .switch_capture_multi_ref = .switch_capture,
1343 .switch_capture_else = .switch_capture,
1344 .switch_capture_else_ref = .switch_capture,
13451338 .validate_struct_init = .pl_node,
13461339 .validate_struct_init_comptime = .pl_node,
13471340 .validate_array_init = .pl_node,
......@@ -1469,6 +1462,11 @@ pub const Inst = struct {
14691462 .extended = .extended,
14701463 });
14711464 };
1465
1466 // Uncomment to view how many tag slots are available.
1467 //comptime {
1468 // @compileLog("ZIR tags left: ", 256 - @typeInfo(Tag).Enum.fields.len);
1469 //}
14721470 };
14731471
14741472 /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
src/print_zir.zig-2
......@@ -425,8 +425,6 @@ const Writer = struct {
425425 .switch_capture_ref,
426426 .switch_capture_multi,
427427 .switch_capture_multi_ref,
428 .switch_capture_else,
429 .switch_capture_else_ref,
430428 => try self.writeSwitchCapture(stream, inst),
431429
432430 .dbg_stmt => try self.writeDbgStmt(stream, inst),
test/behavior.zig-1
......@@ -203,7 +203,6 @@ test {
203203 if (builtin.target.cpu.arch == .wasm32) {
204204 _ = @import("behavior/wasm.zig");
205205 }
206 _ = @import("behavior/while_stage1.zig");
207206 _ = @import("behavior/translate_c_macros_stage1.zig");
208207 }
209208 }
test/behavior/switch.zig+15
......@@ -359,6 +359,21 @@ fn return_a_number() anyerror!i32 {
359359 return 1;
360360}
361361
362test "switch on integer with else capturing expr" {
363 const S = struct {
364 fn doTheTest() !void {
365 var x: i32 = 5;
366 switch (x + 10) {
367 14 => @panic("fail"),
368 16 => @panic("fail"),
369 else => |e| try expect(e == 15),
370 }
371 }
372 };
373 try S.doTheTest();
374 comptime try S.doTheTest();
375}
376
362377test "else prong of switch on error set excludes other cases" {
363378 if (@import("builtin").zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
364379
test/behavior/while.zig+17
......@@ -266,3 +266,20 @@ test "while optional 2 break statements and an else" {
266266 try S.entry(true, false);
267267 comptime try S.entry(true, false);
268268}
269
270test "while error 2 break statements and an else" {
271 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
272
273 const S = struct {
274 fn entry(opt_t: anyerror!bool, f: bool) !void {
275 var ok = false;
276 ok = while (opt_t) |t| {
277 if (f) break false;
278 if (t) break true;
279 } else |_| false;
280 try expect(ok);
281 }
282 };
283 try S.entry(true, false);
284 comptime try S.entry(true, false);
285}
test/behavior/while_stage1.zig deleted-17
......@@ -1,17 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4test "while error 2 break statements and an else" {
5 const S = struct {
6 fn entry(opt_t: anyerror!bool, f: bool) !void {
7 var ok = false;
8 ok = while (opt_t) |t| {
9 if (f) break false;
10 if (t) break true;
11 } else |_| false;
12 try expect(ok);
13 }
14 };
15 try S.entry(true, false);
16 comptime try S.entry(true, false);
17}