| author | |
| committer | |
| log | 84c2c47fae82e913286a2306d8947252ae3a42f7 |
| tree | a57dc1f9a211f3852496988ae1e09a222e9d6f29 |
| parent | 2600978a9ddc295c347fd6ffe7c6ba20931b956e |
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 | ... | @@ -2198,8 +2198,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2198 | .switch_capture_ref, | 2198 | .switch_capture_ref, |
| 2199 | .switch_capture_multi, | 2199 | .switch_capture_multi, |
| 2200 | .switch_capture_multi_ref, | 2200 | .switch_capture_multi_ref, |
| 2201 | .switch_capture_else, | ||
| 2202 | .switch_capture_else_ref, | ||
| 2203 | .struct_init_empty, | 2201 | .struct_init_empty, |
| 2204 | .struct_init, | 2202 | .struct_init, |
| 2205 | .struct_init_ref, | 2203 | .struct_init_ref, |
| ... | @@ -5758,16 +5756,19 @@ fn switchExpr( | ... | @@ -5758,16 +5756,19 @@ fn switchExpr( |
| 5758 | } | 5756 | } |
| 5759 | if (case_node == special_node) { | 5757 | if (case_node == special_node) { |
| 5760 | const capture_tag: Zir.Inst.Tag = if (is_ptr) | 5758 | const capture_tag: Zir.Inst.Tag = if (is_ptr) |
| 5761 | .switch_capture_else_ref | 5759 | .switch_capture_ref |
| 5762 | else | 5760 | else |
| 5763 | .switch_capture_else; | 5761 | .switch_capture; |
| 5764 | capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); | 5762 | capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); |
| 5765 | try astgen.instructions.append(gpa, .{ | 5763 | try astgen.instructions.append(gpa, .{ |
| 5766 | .tag = capture_tag, | 5764 | .tag = capture_tag, |
| 5767 | .data = .{ .switch_capture = .{ | 5765 | .data = .{ |
| 5768 | .switch_inst = switch_block, | 5766 | .switch_capture = .{ |
| 5769 | .prong_index = undefined, | 5767 | .switch_inst = switch_block, |
| 5770 | } }, | 5768 | // Max int communicates that this is the else/underscore prong. |
| 5769 | .prong_index = std.math.maxInt(u32), | ||
| 5770 | }, | ||
| 5771 | }, | ||
| 5771 | }); | 5772 | }); |
| 5772 | } else { | 5773 | } else { |
| 5773 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); | 5774 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); |
src/Sema.zig+21-22| ... | @@ -669,8 +669,6 @@ fn analyzeBodyInner( | ... | @@ -669,8 +669,6 @@ fn analyzeBodyInner( |
| 669 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), | 669 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), |
| 670 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), | 670 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), |
| 671 | .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), | 671 | .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), | ||
| 674 | .type_info => try sema.zirTypeInfo(block, inst), | 672 | .type_info => try sema.zirTypeInfo(block, inst), |
| 675 | .size_of => try sema.zirSizeOf(block, inst), | 673 | .size_of => try sema.zirSizeOf(block, inst), |
| 676 | .bit_size_of => try sema.zirBitSizeOf(block, inst), | 674 | .bit_size_of => try sema.zirBitSizeOf(block, inst), |
| ... | @@ -6071,6 +6069,27 @@ fn zirSwitchCapture( | ... | @@ -6071,6 +6069,27 @@ fn zirSwitchCapture( |
| 6071 | const operand_ptr_ty = sema.typeOf(operand_ptr); | 6069 | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 6072 | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty; | 6070 | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty; |
| 6073 | 6071 | ||
| 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 | |||
| 6074 | if (is_multi) { | 6093 | if (is_multi) { |
| 6075 | return sema.fail(block, switch_src, "TODO implement Sema for switch capture multi", .{}); | 6094 | return sema.fail(block, switch_src, "TODO implement Sema for switch capture multi", .{}); |
| 6076 | } | 6095 | } |
| ... | @@ -6137,26 +6156,6 @@ fn zirSwitchCapture( | ... | @@ -6137,26 +6156,6 @@ fn zirSwitchCapture( |
| 6137 | } | 6156 | } |
| 6138 | } | 6157 | } |
| 6139 | 6158 | ||
| 6140 | fn 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 | |||
| 6160 | fn zirSwitchCond( | 6159 | fn zirSwitchCond( |
| 6161 | sema: *Sema, | 6160 | sema: *Sema, |
| 6162 | block: *Block, | 6161 | block: *Block, |
src/Zir.zig+9-11| ... | @@ -625,10 +625,14 @@ pub const Inst = struct { | ... | @@ -625,10 +625,14 @@ pub const Inst = struct { |
| 625 | switch_cond_ref, | 625 | switch_cond_ref, |
| 626 | /// Produces the capture value for a switch prong. | 626 | /// Produces the capture value for a switch prong. |
| 627 | /// Uses the `switch_capture` field. | 627 | /// 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. | ||
| 628 | switch_capture, | 630 | switch_capture, |
| 629 | /// Produces the capture value for a switch prong. | 631 | /// Produces the capture value for a switch prong. |
| 630 | /// Result is a pointer to the value. | 632 | /// Result is a pointer to the value. |
| 631 | /// Uses the `switch_capture` field. | 633 | /// 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. | ||
| 632 | switch_capture_ref, | 636 | switch_capture_ref, |
| 633 | /// Produces the capture value for a switch prong. | 637 | /// Produces the capture value for a switch prong. |
| 634 | /// The prong is one of the multi cases. | 638 | /// The prong is one of the multi cases. |
| ... | @@ -639,13 +643,6 @@ pub const Inst = struct { | ... | @@ -639,13 +643,6 @@ pub const Inst = struct { |
| 639 | /// Result is a pointer to the value. | 643 | /// Result is a pointer to the value. |
| 640 | /// Uses the `switch_capture` field. | 644 | /// Uses the `switch_capture` field. |
| 641 | switch_capture_multi_ref, | 645 | 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, | ||
| 649 | /// Given a set of `field_ptr` instructions, assumes they are all part of a struct | 646 | /// Given a set of `field_ptr` instructions, assumes they are all part of a struct |
| 650 | /// initialization expression, and emits compile errors for duplicate fields | 647 | /// initialization expression, and emits compile errors for duplicate fields |
| 651 | /// as well as missing fields, if applicable. | 648 | /// as well as missing fields, if applicable. |
| ... | @@ -1082,8 +1079,6 @@ pub const Inst = struct { | ... | @@ -1082,8 +1079,6 @@ pub const Inst = struct { |
| 1082 | .switch_capture_ref, | 1079 | .switch_capture_ref, |
| 1083 | .switch_capture_multi, | 1080 | .switch_capture_multi, |
| 1084 | .switch_capture_multi_ref, | 1081 | .switch_capture_multi_ref, |
| 1085 | .switch_capture_else, | ||
| 1086 | .switch_capture_else_ref, | ||
| 1087 | .switch_block, | 1082 | .switch_block, |
| 1088 | .switch_cond, | 1083 | .switch_cond, |
| 1089 | .switch_cond_ref, | 1084 | .switch_cond_ref, |
| ... | @@ -1340,8 +1335,6 @@ pub const Inst = struct { | ... | @@ -1340,8 +1335,6 @@ pub const Inst = struct { |
| 1340 | .switch_capture_ref = .switch_capture, | 1335 | .switch_capture_ref = .switch_capture, |
| 1341 | .switch_capture_multi = .switch_capture, | 1336 | .switch_capture_multi = .switch_capture, |
| 1342 | .switch_capture_multi_ref = .switch_capture, | 1337 | .switch_capture_multi_ref = .switch_capture, |
| 1343 | .switch_capture_else = .switch_capture, | ||
| 1344 | .switch_capture_else_ref = .switch_capture, | ||
| 1345 | .validate_struct_init = .pl_node, | 1338 | .validate_struct_init = .pl_node, |
| 1346 | .validate_struct_init_comptime = .pl_node, | 1339 | .validate_struct_init_comptime = .pl_node, |
| 1347 | .validate_array_init = .pl_node, | 1340 | .validate_array_init = .pl_node, |
| ... | @@ -1469,6 +1462,11 @@ pub const Inst = struct { | ... | @@ -1469,6 +1462,11 @@ pub const Inst = struct { |
| 1469 | .extended = .extended, | 1462 | .extended = .extended, |
| 1470 | }); | 1463 | }); |
| 1471 | }; | 1464 | }; |
| 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 | //} | ||
| 1472 | }; | 1470 | }; |
| 1473 | 1471 | ||
| 1474 | /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum. | 1472 | /// 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 { | ... | @@ -425,8 +425,6 @@ const Writer = struct { |
| 425 | .switch_capture_ref, | 425 | .switch_capture_ref, |
| 426 | .switch_capture_multi, | 426 | .switch_capture_multi, |
| 427 | .switch_capture_multi_ref, | 427 | .switch_capture_multi_ref, |
| 428 | .switch_capture_else, | ||
| 429 | .switch_capture_else_ref, | ||
| 430 | => try self.writeSwitchCapture(stream, inst), | 428 | => try self.writeSwitchCapture(stream, inst), |
| 431 | 429 | ||
| 432 | .dbg_stmt => try self.writeDbgStmt(stream, inst), | 430 | .dbg_stmt => try self.writeDbgStmt(stream, inst), |
test/behavior.zig-1| ... | @@ -203,7 +203,6 @@ test { | ... | @@ -203,7 +203,6 @@ test { |
| 203 | if (builtin.target.cpu.arch == .wasm32) { | 203 | if (builtin.target.cpu.arch == .wasm32) { |
| 204 | _ = @import("behavior/wasm.zig"); | 204 | _ = @import("behavior/wasm.zig"); |
| 205 | } | 205 | } |
| 206 | _ = @import("behavior/while_stage1.zig"); | ||
| 207 | _ = @import("behavior/translate_c_macros_stage1.zig"); | 206 | _ = @import("behavior/translate_c_macros_stage1.zig"); |
| 208 | } | 207 | } |
| 209 | } | 208 | } |
test/behavior/switch.zig+15| ... | @@ -359,6 +359,21 @@ fn return_a_number() anyerror!i32 { | ... | @@ -359,6 +359,21 @@ fn return_a_number() anyerror!i32 { |
| 359 | return 1; | 359 | return 1; |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | test "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 | |||
| 362 | test "else prong of switch on error set excludes other cases" { | 377 | test "else prong of switch on error set excludes other cases" { |
| 363 | if (@import("builtin").zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO | 378 | if (@import("builtin").zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO |
| 364 | 379 |
test/behavior/while.zig+17| ... | @@ -266,3 +266,20 @@ test "while optional 2 break statements and an else" { | ... | @@ -266,3 +266,20 @@ test "while optional 2 break statements and an else" { |
| 266 | try S.entry(true, false); | 266 | try S.entry(true, false); |
| 267 | comptime try S.entry(true, false); | 267 | comptime try S.entry(true, false); |
| 268 | } | 268 | } |
| 269 | |||
| 270 | test "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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "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 | } | ||