Commit 84c2c47fae
Changed files (8)
src/AstGen.zig
@@ -2198,8 +2198,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
.switch_capture_ref,
.switch_capture_multi,
.switch_capture_multi_ref,
- .switch_capture_else,
- .switch_capture_else_ref,
.struct_init_empty,
.struct_init,
.struct_init_ref,
@@ -5758,16 +5756,19 @@ fn switchExpr(
}
if (case_node == special_node) {
const capture_tag: Zir.Inst.Tag = if (is_ptr)
- .switch_capture_else_ref
+ .switch_capture_ref
else
- .switch_capture_else;
+ .switch_capture;
capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
try astgen.instructions.append(gpa, .{
.tag = capture_tag,
- .data = .{ .switch_capture = .{
- .switch_inst = switch_block,
- .prong_index = undefined,
- } },
+ .data = .{
+ .switch_capture = .{
+ .switch_inst = switch_block,
+ // Max int communicates that this is the else/underscore prong.
+ .prong_index = std.math.maxInt(u32),
+ },
+ },
});
} else {
const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
src/print_zir.zig
@@ -425,8 +425,6 @@ const Writer = struct {
.switch_capture_ref,
.switch_capture_multi,
.switch_capture_multi_ref,
- .switch_capture_else,
- .switch_capture_else_ref,
=> try self.writeSwitchCapture(stream, inst),
.dbg_stmt => try self.writeDbgStmt(stream, inst),
src/Sema.zig
@@ -669,8 +669,6 @@ fn analyzeBodyInner(
.switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
.switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
.switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
- .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
- .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
.type_info => try sema.zirTypeInfo(block, inst),
.size_of => try sema.zirSizeOf(block, inst),
.bit_size_of => try sema.zirBitSizeOf(block, inst),
@@ -6071,6 +6069,27 @@ fn zirSwitchCapture(
const operand_ptr_ty = sema.typeOf(operand_ptr);
const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty;
+ if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) {
+ // It is the else/`_` prong.
+ switch (operand_ty.zigTypeTag()) {
+ .ErrorSet => {
+ return sema.fail(block, operand_src, "TODO implement Sema for zirSwitchCaptureElse for error sets", .{});
+ },
+ else => {},
+ }
+ if (is_ref) {
+ assert(operand_is_ref);
+ return operand_ptr;
+ }
+
+ const operand = if (operand_is_ref)
+ try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
+ else
+ operand_ptr;
+
+ return operand;
+ }
+
if (is_multi) {
return sema.fail(block, switch_src, "TODO implement Sema for switch capture multi", .{});
}
@@ -6137,26 +6156,6 @@ fn zirSwitchCapture(
}
}
-fn zirSwitchCaptureElse(
- sema: *Sema,
- block: *Block,
- inst: Zir.Inst.Index,
- is_ref: bool,
-) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const zir_datas = sema.code.instructions.items(.data);
- const capture_info = zir_datas[inst].switch_capture;
- const switch_info = zir_datas[capture_info.switch_inst].pl_node;
- const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index).data;
- const src = switch_info.src();
- const operand_is_ref = switch_extra.bits.is_ref;
- assert(!is_ref or operand_is_ref);
-
- return sema.fail(block, src, "TODO implement Sema for zirSwitchCaptureElse", .{});
-}
-
fn zirSwitchCond(
sema: *Sema,
block: *Block,
src/Zir.zig
@@ -625,10 +625,14 @@ pub const Inst = struct {
switch_cond_ref,
/// Produces the capture value for a switch prong.
/// Uses the `switch_capture` field.
+ /// If the `prong_index` field is max int, it means this is the capture
+ /// for the else/`_` prong.
switch_capture,
/// Produces the capture value for a switch prong.
/// Result is a pointer to the value.
/// Uses the `switch_capture` field.
+ /// If the `prong_index` field is max int, it means this is the capture
+ /// for the else/`_` prong.
switch_capture_ref,
/// Produces the capture value for a switch prong.
/// The prong is one of the multi cases.
@@ -639,13 +643,6 @@ pub const Inst = struct {
/// Result is a pointer to the value.
/// Uses the `switch_capture` field.
switch_capture_multi_ref,
- /// Produces the capture value for the else/'_' switch prong.
- /// Uses the `switch_capture` field.
- switch_capture_else,
- /// Produces the capture value for the else/'_' switch prong.
- /// Result is a pointer to the value.
- /// Uses the `switch_capture` field.
- switch_capture_else_ref,
/// Given a set of `field_ptr` instructions, assumes they are all part of a struct
/// initialization expression, and emits compile errors for duplicate fields
/// as well as missing fields, if applicable.
@@ -1082,8 +1079,6 @@ pub const Inst = struct {
.switch_capture_ref,
.switch_capture_multi,
.switch_capture_multi_ref,
- .switch_capture_else,
- .switch_capture_else_ref,
.switch_block,
.switch_cond,
.switch_cond_ref,
@@ -1340,8 +1335,6 @@ pub const Inst = struct {
.switch_capture_ref = .switch_capture,
.switch_capture_multi = .switch_capture,
.switch_capture_multi_ref = .switch_capture,
- .switch_capture_else = .switch_capture,
- .switch_capture_else_ref = .switch_capture,
.validate_struct_init = .pl_node,
.validate_struct_init_comptime = .pl_node,
.validate_array_init = .pl_node,
@@ -1469,6 +1462,11 @@ pub const Inst = struct {
.extended = .extended,
});
};
+
+ // Uncomment to view how many tag slots are available.
+ //comptime {
+ // @compileLog("ZIR tags left: ", 256 - @typeInfo(Tag).Enum.fields.len);
+ //}
};
/// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
test/behavior/switch.zig
@@ -359,6 +359,21 @@ fn return_a_number() anyerror!i32 {
return 1;
}
+test "switch on integer with else capturing expr" {
+ const S = struct {
+ fn doTheTest() !void {
+ var x: i32 = 5;
+ switch (x + 10) {
+ 14 => @panic("fail"),
+ 16 => @panic("fail"),
+ else => |e| try expect(e == 15),
+ }
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
test "else prong of switch on error set excludes other cases" {
if (@import("builtin").zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
test/behavior/while.zig
@@ -266,3 +266,20 @@ test "while optional 2 break statements and an else" {
try S.entry(true, false);
comptime try S.entry(true, false);
}
+
+test "while error 2 break statements and an else" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn entry(opt_t: anyerror!bool, f: bool) !void {
+ var ok = false;
+ ok = while (opt_t) |t| {
+ if (f) break false;
+ if (t) break true;
+ } else |_| false;
+ try expect(ok);
+ }
+ };
+ try S.entry(true, false);
+ comptime try S.entry(true, false);
+}
test/behavior/while_stage1.zig
@@ -1,17 +0,0 @@
-const std = @import("std");
-const expect = std.testing.expect;
-
-test "while error 2 break statements and an else" {
- const S = struct {
- fn entry(opt_t: anyerror!bool, f: bool) !void {
- var ok = false;
- ok = while (opt_t) |t| {
- if (f) break false;
- if (t) break true;
- } else |_| false;
- try expect(ok);
- }
- };
- try S.entry(true, false);
- comptime try S.entry(true, false);
-}
test/behavior.zig
@@ -203,7 +203,6 @@ test {
if (builtin.target.cpu.arch == .wasm32) {
_ = @import("behavior/wasm.zig");
}
- _ = @import("behavior/while_stage1.zig");
_ = @import("behavior/translate_c_macros_stage1.zig");
}
}