| author | |
| committer | |
| log | 769d5a9c435c5c145983e4d3af1706924248e367 |
| tree | 1aa427c706261ccf5256e8699be331601821251e |
| parent | 12e4c648ccc68f5190dd5076088b3959ebeee65d |
| signature |
5 files changed, 82 insertions(+), 39 deletions(-)
src/Module.zig+3-1| ... | @@ -2122,16 +2122,18 @@ pub fn addSwitchBr( | ... | @@ -2122,16 +2122,18 @@ pub fn addSwitchBr( |
| 2122 | src: usize, | 2122 | src: usize, |
| 2123 | target_ptr: *Inst, | 2123 | target_ptr: *Inst, |
| 2124 | cases: []Inst.SwitchBr.Case, | 2124 | cases: []Inst.SwitchBr.Case, |
| 2125 | else_body: ir.Body, | ||
| 2125 | ) !*Inst { | 2126 | ) !*Inst { |
| 2126 | const inst = try block.arena.create(Inst.SwitchBr); | 2127 | const inst = try block.arena.create(Inst.SwitchBr); |
| 2127 | inst.* = .{ | 2128 | inst.* = .{ |
| 2128 | .base = .{ | 2129 | .base = .{ |
| 2129 | .tag = .switchbr, | 2130 | .tag = .switchbr, |
| 2130 | .ty = Type.initTag(.void), | 2131 | .ty = Type.initTag(.noreturn), |
| 2131 | .src = src, | 2132 | .src = src, |
| 2132 | }, | 2133 | }, |
| 2133 | .target_ptr = target_ptr, | 2134 | .target_ptr = target_ptr, |
| 2134 | .cases = cases, | 2135 | .cases = cases, |
| 2136 | .else_body = else_body, | ||
| 2135 | }; | 2137 | }; |
| 2136 | try block.instructions.append(self.gpa, &inst.base); | 2138 | try block.instructions.append(self.gpa, &inst.base); |
| 2137 | return &inst.base; | 2139 | return &inst.base; |
src/astgen.zig+35-28| ... | @@ -1581,14 +1581,6 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1581,14 +1581,6 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1581 | }; | 1581 | }; |
| 1582 | defer block_scope.instructions.deinit(mod.gpa); | 1582 | defer block_scope.instructions.deinit(mod.gpa); |
| 1583 | 1583 | ||
| 1584 | var item_scope: Scope.GenZIR = .{ | ||
| 1585 | .parent = scope, | ||
| 1586 | .decl = scope.decl().?, | ||
| 1587 | .arena = scope.arena(), | ||
| 1588 | .instructions = .{}, | ||
| 1589 | }; | ||
| 1590 | defer item_scope.instructions.deinit(mod.gpa); | ||
| 1591 | |||
| 1592 | const tree = scope.tree(); | 1584 | const tree = scope.tree(); |
| 1593 | const switch_src = tree.token_locs[switch_node.switch_token].start; | 1585 | const switch_src = tree.token_locs[switch_node.switch_token].start; |
| 1594 | const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr); | 1586 | const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr); |
| ... | @@ -1598,6 +1590,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1598,6 +1590,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1598 | .target_ptr = target_ptr, | 1590 | .target_ptr = target_ptr, |
| 1599 | .cases = undefined, // populated below | 1591 | .cases = undefined, // populated below |
| 1600 | .items = &[_]*zir.Inst{}, // populated below | 1592 | .items = &[_]*zir.Inst{}, // populated below |
| 1593 | .else_body = undefined, // populated below | ||
| 1601 | }, .{})).castTag(.switchbr).?; | 1594 | }, .{})).castTag(.switchbr).?; |
| 1602 | 1595 | ||
| 1603 | var items = std.ArrayList(*zir.Inst).init(mod.gpa); | 1596 | var items = std.ArrayList(*zir.Inst).init(mod.gpa); |
| ... | @@ -1611,7 +1604,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1611,7 +1604,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1611 | }); | 1604 | }); |
| 1612 | // then add block containing the switch. | 1605 | // then add block containing the switch. |
| 1613 | const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{ | 1606 | const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{ |
| 1614 | .instructions = undefined, // populated below | 1607 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 1615 | }); | 1608 | }); |
| 1616 | 1609 | ||
| 1617 | // Most result location types can be forwarded directly; however | 1610 | // Most result location types can be forwarded directly; however |
| ... | @@ -1622,6 +1615,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1622,6 +1615,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1622 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, | 1615 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 1623 | }; | 1616 | }; |
| 1624 | 1617 | ||
| 1618 | var item_scope: Scope.GenZIR = .{ | ||
| 1619 | .parent = scope, | ||
| 1620 | .decl = scope.decl().?, | ||
| 1621 | .arena = scope.arena(), | ||
| 1622 | .instructions = .{}, | ||
| 1623 | }; | ||
| 1624 | defer item_scope.instructions.deinit(mod.gpa); | ||
| 1625 | |||
| 1625 | var case_scope: Scope.GenZIR = .{ | 1626 | var case_scope: Scope.GenZIR = .{ |
| 1626 | .parent = scope, | 1627 | .parent = scope, |
| 1627 | .decl = block_scope.decl, | 1628 | .decl = block_scope.decl, |
| ... | @@ -1630,6 +1631,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1630,6 +1631,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1630 | }; | 1631 | }; |
| 1631 | defer case_scope.instructions.deinit(mod.gpa); | 1632 | defer case_scope.instructions.deinit(mod.gpa); |
| 1632 | 1633 | ||
| 1634 | var else_scope: Scope.GenZIR = .{ | ||
| 1635 | .parent = scope, | ||
| 1636 | .decl = block_scope.decl, | ||
| 1637 | .arena = block_scope.arena, | ||
| 1638 | .instructions = .{}, | ||
| 1639 | }; | ||
| 1640 | defer else_scope.instructions.deinit(mod.gpa); | ||
| 1641 | |||
| 1633 | // first we gather all the switch items and check else/'_' prongs | 1642 | // first we gather all the switch items and check else/'_' prongs |
| 1634 | var else_src: ?usize = null; | 1643 | var else_src: ?usize = null; |
| 1635 | var underscore_src: ?usize = null; | 1644 | var underscore_src: ?usize = null; |
| ... | @@ -1701,12 +1710,12 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1701,12 +1710,12 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1701 | if (first_range == null) first_range = range_inst; | 1710 | if (first_range == null) first_range = range_inst; |
| 1702 | 1711 | ||
| 1703 | // target >= start and target <= end | 1712 | // target >= start and target <= end |
| 1704 | const range_start_ok = try addZIRBinOp(mod, &block_scope.base, range_src, .cmp_gte, target, start); | 1713 | const range_start_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .cmp_gte, target, start); |
| 1705 | const range_end_ok = try addZIRBinOp(mod, &block_scope.base, range_src, .cmp_lte, target, end); | 1714 | const range_end_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .cmp_lte, target, end); |
| 1706 | const range_ok = try addZIRBinOp(mod, &block_scope.base, range_src, .booland, range_start_ok, range_end_ok); | 1715 | const range_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .booland, range_start_ok, range_end_ok); |
| 1707 | 1716 | ||
| 1708 | if (any_ok) |some| { | 1717 | if (any_ok) |some| { |
| 1709 | any_ok = try addZIRBinOp(mod, &block_scope.base, range_src, .boolor, some, range_ok); | 1718 | any_ok = try addZIRBinOp(mod, &else_scope.base, range_src, .boolor, some, range_ok); |
| 1710 | } else { | 1719 | } else { |
| 1711 | any_ok = range_ok; | 1720 | any_ok = range_ok; |
| 1712 | } | 1721 | } |
| ... | @@ -1715,16 +1724,16 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1715,16 +1724,16 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1715 | 1724 | ||
| 1716 | const item_inst = try expr(mod, &item_scope.base, .none, item); | 1725 | const item_inst = try expr(mod, &item_scope.base, .none, item); |
| 1717 | try items.append(item_inst); | 1726 | try items.append(item_inst); |
| 1718 | const cpm_ok = try addZIRBinOp(mod, &block_scope.base, item_inst.src, .cmp_eq, target, item_inst); | 1727 | const cpm_ok = try addZIRBinOp(mod, &else_scope.base, item_inst.src, .cmp_eq, target, item_inst); |
| 1719 | 1728 | ||
| 1720 | if (any_ok) |some| { | 1729 | if (any_ok) |some| { |
| 1721 | any_ok = try addZIRBinOp(mod, &block_scope.base, item_inst.src, .boolor, some, cpm_ok); | 1730 | any_ok = try addZIRBinOp(mod, &else_scope.base, item_inst.src, .boolor, some, cpm_ok); |
| 1722 | } else { | 1731 | } else { |
| 1723 | any_ok = cpm_ok; | 1732 | any_ok = cpm_ok; |
| 1724 | } | 1733 | } |
| 1725 | } | 1734 | } |
| 1726 | 1735 | ||
| 1727 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, case_src, zir.Inst.CondBr, .{ | 1736 | const condbr = try addZIRInstSpecial(mod, &else_scope.base, case_src, zir.Inst.CondBr, .{ |
| 1728 | .condition = any_ok.?, | 1737 | .condition = any_ok.?, |
| 1729 | .then_body = undefined, // populated below | 1738 | .then_body = undefined, // populated below |
| 1730 | .else_body = undefined, // populated below | 1739 | .else_body = undefined, // populated below |
| ... | @@ -1754,6 +1763,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1754,6 +1763,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1754 | }; | 1763 | }; |
| 1755 | } | 1764 | } |
| 1756 | 1765 | ||
| 1766 | // Generate else block or a break last to finish the block. | ||
| 1767 | if (special_case) |case| { | ||
| 1768 | try switchCaseExpr(mod, &else_scope.base, case_rl, block, case); | ||
| 1769 | } else { | ||
| 1770 | // Not handling all possible cases is a compile error. | ||
| 1771 | _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreach_nocheck); | ||
| 1772 | } | ||
| 1773 | |||
| 1757 | // All items have been generated, add the instructions to the comptime block. | 1774 | // All items have been generated, add the instructions to the comptime block. |
| 1758 | item_block.positionals.body = .{ | 1775 | item_block.positionals.body = .{ |
| 1759 | .instructions = try block_scope.arena.dupe(*zir.Inst, item_scope.instructions.items), | 1776 | .instructions = try block_scope.arena.dupe(*zir.Inst, item_scope.instructions.items), |
| ... | @@ -1765,18 +1782,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1765,18 +1782,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1765 | switch_inst.positionals.cases = try block_scope.arena.dupe(zir.Inst.SwitchBr.Case, cases.items); | 1782 | switch_inst.positionals.cases = try block_scope.arena.dupe(zir.Inst.SwitchBr.Case, cases.items); |
| 1766 | switch_inst.positionals.items = try block_scope.arena.dupe(*zir.Inst, items.items); | 1783 | switch_inst.positionals.items = try block_scope.arena.dupe(*zir.Inst, items.items); |
| 1767 | switch_inst.kw_args.range = first_range; | 1784 | switch_inst.kw_args.range = first_range; |
| 1768 | 1785 | switch_inst.positionals.else_body = .{ | |
| 1769 | // Generate else block or a break last to finish the block. | 1786 | .instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), |
| 1770 | if (special_case) |case| { | ||
| 1771 | try switchCaseExpr(mod, &block_scope.base, case_rl, block, case); | ||
| 1772 | } else { | ||
| 1773 | // Not handling all possible cases is a compile error. | ||
| 1774 | _ = try addZIRNoOp(mod, &block_scope.base, switch_src, .unreach_nocheck); | ||
| 1775 | } | ||
| 1776 | |||
| 1777 | // Set block instructions now that it is finished. | ||
| 1778 | block.positionals.body = .{ | ||
| 1779 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | ||
| 1780 | }; | 1787 | }; |
| 1781 | return &block.base; | 1788 | return &block.base; |
| 1782 | } | 1789 | } |
src/ir.zig+7-1| ... | @@ -472,8 +472,11 @@ pub const Inst = struct { | ... | @@ -472,8 +472,11 @@ pub const Inst = struct { |
| 472 | target_ptr: *Inst, | 472 | target_ptr: *Inst, |
| 473 | cases: []Case, | 473 | cases: []Case, |
| 474 | /// Set of instructions whose lifetimes end at the start of one of the cases. | 474 | /// Set of instructions whose lifetimes end at the start of one of the cases. |
| 475 | /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... , case_n_count ... else_count]. | 475 | /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... ]. |
| 476 | deaths: [*]*Inst = undefined, | 476 | deaths: [*]*Inst = undefined, |
| 477 | else_index: u32 = 0, | ||
| 478 | else_deaths: u32 = 0, | ||
| 479 | else_body: Body, | ||
| 477 | 480 | ||
| 478 | pub const Case = struct { | 481 | pub const Case = struct { |
| 479 | item: Value, | 482 | item: Value, |
| ... | @@ -498,6 +501,9 @@ pub const Inst = struct { | ... | @@ -498,6 +501,9 @@ pub const Inst = struct { |
| 498 | const case = self.cases[case_index]; | 501 | const case = self.cases[case_index]; |
| 499 | return (self.deaths + case.index)[0..case.deaths]; | 502 | return (self.deaths + case.index)[0..case.deaths]; |
| 500 | } | 503 | } |
| 504 | pub fn elseDeaths(self: *const SwitchBr) []*Inst { | ||
| 505 | return (self.deaths + self.else_index)[0..self.else_deaths]; | ||
| 506 | } | ||
| 501 | }; | 507 | }; |
| 502 | }; | 508 | }; |
| 503 | 509 |
src/zir.zig+10-2| ... | @@ -509,7 +509,6 @@ pub const Inst = struct { | ... | @@ -509,7 +509,6 @@ pub const Inst = struct { |
| 509 | .slice, | 509 | .slice, |
| 510 | .slice_start, | 510 | .slice_start, |
| 511 | .import, | 511 | .import, |
| 512 | .switchbr, | ||
| 513 | .switch_range, | 512 | .switch_range, |
| 514 | => false, | 513 | => false, |
| 515 | 514 | ||
| ... | @@ -522,6 +521,7 @@ pub const Inst = struct { | ... | @@ -522,6 +521,7 @@ pub const Inst = struct { |
| 522 | .unreach_nocheck, | 521 | .unreach_nocheck, |
| 523 | .@"unreachable", | 522 | .@"unreachable", |
| 524 | .loop, | 523 | .loop, |
| 524 | .switchbr, | ||
| 525 | => true, | 525 | => true, |
| 526 | }; | 526 | }; |
| 527 | } | 527 | } |
| ... | @@ -1012,9 +1012,10 @@ pub const Inst = struct { | ... | @@ -1012,9 +1012,10 @@ pub const Inst = struct { |
| 1012 | 1012 | ||
| 1013 | positionals: struct { | 1013 | positionals: struct { |
| 1014 | target_ptr: *Inst, | 1014 | target_ptr: *Inst, |
| 1015 | cases: []Case, | ||
| 1016 | /// List of all individual items and ranges | 1015 | /// List of all individual items and ranges |
| 1017 | items: []*Inst, | 1016 | items: []*Inst, |
| 1017 | cases: []Case, | ||
| 1018 | else_body: Module.Body, | ||
| 1018 | }, | 1019 | }, |
| 1019 | kw_args: struct { | 1020 | kw_args: struct { |
| 1020 | /// Pointer to first range if such exists. | 1021 | /// Pointer to first range if such exists. |
| ... | @@ -2569,6 +2570,7 @@ const EmitZIR = struct { | ... | @@ -2569,6 +2570,7 @@ const EmitZIR = struct { |
| 2569 | .target_ptr = try self.resolveInst(new_body, old_inst.target_ptr), | 2570 | .target_ptr = try self.resolveInst(new_body, old_inst.target_ptr), |
| 2570 | .cases = cases, | 2571 | .cases = cases, |
| 2571 | .items = &[_]*Inst{}, // TODO this should actually be populated | 2572 | .items = &[_]*Inst{}, // TODO this should actually be populated |
| 2573 | .else_body = undefined, // populated below | ||
| 2572 | }, | 2574 | }, |
| 2573 | .kw_args = .{}, | 2575 | .kw_args = .{}, |
| 2574 | }; | 2576 | }; |
| ... | @@ -2590,6 +2592,12 @@ const EmitZIR = struct { | ... | @@ -2590,6 +2592,12 @@ const EmitZIR = struct { |
| 2590 | .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) }, | 2592 | .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) }, |
| 2591 | }; | 2593 | }; |
| 2592 | } | 2594 | } |
| 2595 | |||
| 2596 | body_tmp.items.len = 0; | ||
| 2597 | try self.emitBody(old_inst.else_body, inst_table, &body_tmp); | ||
| 2598 | new_inst.positionals.else_body = .{ | ||
| 2599 | .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items), | ||
| 2600 | }; | ||
| 2593 | break :blk &new_inst.base; | 2601 | break :blk &new_inst.base; |
| 2594 | }, | 2602 | }, |
| 2595 | .varptr => @panic("TODO"), | 2603 | .varptr => @panic("TODO"), |
src/zir_sema.zig+27-7| ... | @@ -1238,7 +1238,20 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In | ... | @@ -1238,7 +1238,20 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In |
| 1238 | const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src); | 1238 | const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src); |
| 1239 | try validateSwitch(mod, scope, target, inst); | 1239 | try validateSwitch(mod, scope, target, inst); |
| 1240 | 1240 | ||
| 1241 | // TODO comptime execution | 1241 | if (try mod.resolveDefinedValue(scope, target)) |target_val| { |
| 1242 | for (inst.positionals.cases) |case| { | ||
| 1243 | const resolved = try resolveInst(mod, scope, case.item); | ||
| 1244 | const casted = try mod.coerce(scope, target.ty, resolved); | ||
| 1245 | const item = try mod.resolveConstValue(scope, casted); | ||
| 1246 | |||
| 1247 | if (target_val.eql(item)) { | ||
| 1248 | try analyzeBody(mod, scope, case.body); | ||
| 1249 | return mod.constNoReturn(scope, inst.base.src); | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | try analyzeBody(mod, scope, inst.positionals.else_body); | ||
| 1253 | return mod.constNoReturn(scope, inst.base.src); | ||
| 1254 | } | ||
| 1242 | 1255 | ||
| 1243 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); | 1256 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 1244 | const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len); | 1257 | const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len); |
| ... | @@ -1253,7 +1266,7 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In | ... | @@ -1253,7 +1266,7 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In |
| 1253 | }; | 1266 | }; |
| 1254 | defer case_block.instructions.deinit(mod.gpa); | 1267 | defer case_block.instructions.deinit(mod.gpa); |
| 1255 | 1268 | ||
| 1256 | for (inst.positionals.cases[0..inst.positionals.cases.len]) |case, i| { | 1269 | for (inst.positionals.cases) |case, i| { |
| 1257 | // Reset without freeing. | 1270 | // Reset without freeing. |
| 1258 | case_block.instructions.items.len = 0; | 1271 | case_block.instructions.items.len = 0; |
| 1259 | 1272 | ||
| ... | @@ -1269,7 +1282,14 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In | ... | @@ -1269,7 +1282,14 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In |
| 1269 | }; | 1282 | }; |
| 1270 | } | 1283 | } |
| 1271 | 1284 | ||
| 1272 | return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases); | 1285 | case_block.instructions.items.len = 0; |
| 1286 | try analyzeBody(mod, &case_block.base, inst.positionals.else_body); | ||
| 1287 | |||
| 1288 | const else_body: ir.Body = .{ | ||
| 1289 | .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items), | ||
| 1290 | }; | ||
| 1291 | |||
| 1292 | return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases, else_body); | ||
| 1273 | } | 1293 | } |
| 1274 | 1294 | ||
| 1275 | fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void { | 1295 | fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void { |
| ... | @@ -1354,14 +1374,14 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw | ... | @@ -1354,14 +1374,14 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw |
| 1354 | false_count += 1; | 1374 | false_count += 1; |
| 1355 | } | 1375 | } |
| 1356 | 1376 | ||
| 1357 | if (true_count > 1 or false_count > 1) { | 1377 | if (true_count + false_count > 2) { |
| 1358 | return mod.fail(scope, item.src, "duplicate switch value", .{}); | 1378 | return mod.fail(scope, item.src, "duplicate switch value", .{}); |
| 1359 | } | 1379 | } |
| 1360 | } | 1380 | } |
| 1361 | if ((true_count == 0 or false_count == 0) and inst.kw_args.special_prong != .@"else") { | 1381 | if ((true_count + false_count < 2) and inst.kw_args.special_prong != .@"else") { |
| 1362 | return mod.fail(scope, inst.base.src, "switch must handle all possibilities", .{}); | 1382 | return mod.fail(scope, inst.base.src, "switch must handle all possibilities", .{}); |
| 1363 | } | 1383 | } |
| 1364 | if ((true_count == 1 and false_count == 1) and inst.kw_args.special_prong == .@"else") { | 1384 | if ((true_count + false_count == 2) and inst.kw_args.special_prong == .@"else") { |
| 1365 | return mod.fail(scope, inst.base.src, "unreachable else prong, all cases already handled", .{}); | 1385 | return mod.fail(scope, inst.base.src, "unreachable else prong, all cases already handled", .{}); |
| 1366 | } | 1386 | } |
| 1367 | }, | 1387 | }, |
| ... | @@ -1696,7 +1716,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1696,7 +1716,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1696 | if (try mod.resolveDefinedValue(scope, cond)) |cond_val| { | 1716 | if (try mod.resolveDefinedValue(scope, cond)) |cond_val| { |
| 1697 | const body = if (cond_val.toBool()) &inst.positionals.then_body else &inst.positionals.else_body; | 1717 | const body = if (cond_val.toBool()) &inst.positionals.then_body else &inst.positionals.else_body; |
| 1698 | try analyzeBody(mod, scope, body.*); | 1718 | try analyzeBody(mod, scope, body.*); |
| 1699 | return mod.constVoid(scope, inst.base.src); | 1719 | return mod.constNoReturn(scope, inst.base.src); |
| 1700 | } | 1720 | } |
| 1701 | 1721 | ||
| 1702 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); | 1722 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); |