authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-16 17:01:05+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-30 15:58:12+02:00
log7db17a2d89c866efadf9a487acf2f9b0535ba859
treeccbb5f3b3cb15162c7e6ec0880f1673e7f8b7b9d
parent95467f324909055d014e989ca9be7b0bb04237c4
signaturelock-open Commit is signed but in an unrecognized format.

stage2: redesign switchbr

Switchbr now only handles single item prongs. Ranges and multi item prongs are checked with condbrs after the switchbr.

5 files changed, 139 insertions(+), 153 deletions(-)

src/Module.zig+1-3
......@@ -2122,18 +2122,16 @@ pub fn addSwitchBr(
21222122 src: usize,
21232123 target_ptr: *Inst,
21242124 cases: []Inst.SwitchBr.Case,
2125 else_body: ?Module.Body,
21262125) !*Inst {
21272126 const inst = try block.arena.create(Inst.SwitchBr);
21282127 inst.* = .{
21292128 .base = .{
21302129 .tag = .switchbr,
2131 .ty = Type.initTag(.noreturn),
2130 .ty = Type.initTag(.void),
21322131 .src = src,
21332132 },
21342133 .target_ptr = target_ptr,
21352134 .cases = cases,
2136 .@"else" = else_body,
21372135 };
21382136 try block.instructions.append(self.gpa, &inst.base);
21392137 return &inst.base;
src/astgen.zig+82-49
......@@ -1570,16 +1570,33 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
15701570 };
15711571 defer block_scope.instructions.deinit(mod.gpa);
15721572
1573 var item_scope: Scope.GenZIR = .{
1574 .parent = scope,
1575 .decl = scope.decl().?,
1576 .arena = scope.arena(),
1577 .instructions = .{},
1578 };
1579 defer item_scope.instructions.deinit(mod.gpa);
1580
15731581 const tree = scope.tree();
15741582 const switch_src = tree.token_locs[switch_node.switch_token].start;
15751583 const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr);
1576 const cases = try scope.arena().alloc(zir.Inst.SwitchBr.Case, switch_node.cases_len);
1577 var kw_args: std.meta.fieldInfo(zir.Inst.SwitchBr, "kw_args").field_type = .{};
1584 // Add the switch instruction here so that it comes before any range checks.
1585 const switch_inst = (try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{
1586 .target_ptr = target_ptr,
1587 .cases = undefined, // populated below
1588 .items = &[_]*zir.Inst{}, // populated below
1589 }, .{})).castTag(.switchbr).?;
1590
1591 var items = std.ArrayList(*zir.Inst).init(mod.gpa);
1592 defer items.deinit();
1593 var cases = std.ArrayList(zir.Inst.SwitchBr.Case).init(mod.gpa);
1594 defer cases.deinit();
15781595
15791596 // first we gather all the switch items and check else/'_' prongs
1580 var case_index: usize = 0;
15811597 var else_src: ?usize = null;
15821598 var underscore_src: ?usize = null;
1599 var range_inst: ?*zir.Inst = null;
15831600 for (switch_node.cases()) |uncasted_case| {
15841601 const case = uncasted_case.castTag(.SwitchCase).?;
15851602 const case_src = tree.token_locs[case.firstToken()].start;
......@@ -1593,12 +1610,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
15931610 return mod.fail(scope, case_src, "multiple else prongs in switch expression", .{});
15941611 // TODO notes "previous else prong is here"
15951612 }
1596 kw_args.special_case = .@"else";
15971613 else_src = case_src;
1598 cases[cases.len - 1] = .{
1599 .items = &[0]*zir.Inst{},
1600 .body = undefined, // filled below
1601 };
16021614 continue;
16031615 } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and
16041616 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
......@@ -1607,48 +1619,44 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
16071619 return mod.fail(scope, case_src, "multiple '_' prongs in switch expression", .{});
16081620 // TODO notes "previous '_' prong is here"
16091621 }
1610 kw_args.special_case = .underscore;
16111622 underscore_src = case_src;
1612 cases[cases.len - 1] = .{
1613 .items = &[0]*zir.Inst{},
1614 .body = undefined, // filled below
1615 };
16161623 continue;
16171624 }
16181625
16191626 if (else_src) |some_else| {
16201627 if (underscore_src) |some_underscore| {
1621 return mod.fail(scope, case_src, "else and '_' prong in switch expression", .{});
1628 return mod.fail(scope, switch_src, "else and '_' prong in switch expression", .{});
16221629 // TODO notes "else prong is here"
16231630 // TODO notes "'_' prong is here"
16241631 }
16251632 }
16261633
1627 // Regular case, we need to fill `items`.
1628 const items = try block_scope.arena.alloc(*zir.Inst, case.items_len);
1629 for (case.items()) |item, i| {
1630 if (item.castTag(.Range)) |range| {
1631 items[i] = try switchRange(mod, &block_scope.base, range);
1632 if (kw_args.support_range == null)
1633 kw_args.support_range = items[i];
1634 } else {
1635 items[i] = try expr(mod, &block_scope.base, .none, item);
1636 }
1634 // TODO and not range
1635 if (case.items_len == 1) {
1636 const item = try expr(mod, &item_scope.base, .none, case.items()[0]);
1637 try cases.append(.{
1638 .item = item,
1639 .body = undefined, // populated below
1640 });
1641 continue;
16371642 }
1638 cases[case_index] = .{
1639 .items = items,
1640 .body = undefined, // filled below
1641 };
1642 case_index += 1;
1643 return mod.fail(scope, case_src, "TODO switch ranges", .{});
16431644 }
16441645
1645 // Then we add the switch instruction to finish the block.
1646 _ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{
1647 .target_ptr = target_ptr,
1648 .cases = cases,
1649 }, kw_args);
1646 // Actually populate switch instruction values.
1647 if (else_src != null) switch_inst.kw_args.special_prong = .@"else";
1648 if (underscore_src != null) switch_inst.kw_args.special_prong = .underscore;
1649 switch_inst.positionals.cases = try block_scope.arena.dupe(zir.Inst.SwitchBr.Case, cases.items);
1650 switch_inst.positionals.items = try block_scope.arena.dupe(*zir.Inst, items.items);
1651 switch_inst.kw_args.range = range_inst;
1652
1653 // Add comptime block containing all prong items first,
1654 _ = try addZIRInstBlock(mod, scope, switch_src, .block_comptime_flat, .{
1655 .instructions = try block_scope.arena.dupe(*zir.Inst, item_scope.instructions.items),
1656 });
1657 // then add block containing the switch.
16501658 const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{
1651 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
1659 .instructions = undefined, // populated below
16521660 });
16531661
16541662 // Most result location types can be forwarded directly; however
......@@ -1668,39 +1676,64 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
16681676 defer case_scope.instructions.deinit(mod.gpa);
16691677
16701678 // And finally we fill generate the bodies of each case.
1671 case_index = 0;
1679 var case_index: usize = 0;
1680 var special_case: ?*ast.Node.SwitchCase = null;
16721681 for (switch_node.cases()) |uncasted_case| {
16731682 const case = uncasted_case.castTag(.SwitchCase).?;
16741683 const case_src = tree.token_locs[case.firstToken()].start;
16751684 // reset without freeing to reduce allocations.
16761685 defer case_scope.instructions.items.len = 0;
16771686
1678 // What index in positionals.cases should this one be placed at.
1679 // For special cases it will be at the end.
1680 var cur_index = case_index;
16811687 if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {
1682 // validated above
1683 cur_index = cases.len - 1;
1688 // validated earlier
1689 special_case = case;
1690 continue;
16841691 } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and
16851692 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
16861693 {
1687 // validated above
1688 cur_index = cases.len - 1;
1694 // validated earlier
1695 special_case = case;
1696 continue;
16891697 }
16901698
1691 // Generate the body of this case.
1692 const case_body = try expr(mod, &case_scope.base, case_rl, case.expr);
1699 if (case.items_len == 1) {
1700 // Generate the body of this case.
1701 const case_body = try expr(mod, &case_scope.base, case_rl, case.expr);
1702 if (!case_body.tag.isNoReturn()) {
1703 _ = try addZIRInst(mod, &case_scope.base, case_src, zir.Inst.Break, .{
1704 .block = block,
1705 .operand = case_body,
1706 }, .{});
1707 }
1708 switch_inst.positionals.cases[case_index].body = .{
1709 .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items),
1710 };
1711 case_index += 1;
1712 continue;
1713 }
1714 return mod.fail(scope, case_src, "TODO switch ranges", .{});
1715 }
1716
1717 // Generate else block or a break last to finish the block.
1718 if (special_case) |case| {
1719 const case_src = tree.token_locs[case.firstToken()].start;
1720 const case_body = try expr(mod, &block_scope.base, case_rl, case.expr);
16931721 if (!case_body.tag.isNoReturn()) {
1694 _ = try addZIRInst(mod, &case_scope.base, case_src, zir.Inst.Break, .{
1722 _ = try addZIRInst(mod, &block_scope.base, case_src, zir.Inst.Break, .{
16951723 .block = block,
16961724 .operand = case_body,
16971725 }, .{});
16981726 }
1699 cases[cur_index].body = .{
1700 .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items),
1701 };
1727 } else {
1728 _ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.BreakVoid, .{
1729 .block = block,
1730 }, .{});
17021731 }
17031732
1733 // Set block instructions now that it is finished.
1734 block.positionals.body = .{
1735 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
1736 };
17041737 return &block.base;
17051738}
17061739
src/ir.zig+1-7
......@@ -467,15 +467,12 @@ pub const Inst = struct {
467467 base: Inst,
468468 target_ptr: *Inst,
469469 cases: []Case,
470 @"else": ?Body,
471470 /// Set of instructions whose lifetimes end at the start of one of the cases.
472471 /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... , case_n_count ... else_count].
473472 deaths: [*]*Inst = undefined,
474 else_index: u32 = 0,
475 else_deaths: u32 = 0,
476473
477474 pub const Case = struct {
478 items: []Value,
475 item: Value,
479476 body: Body,
480477 index: u32 = 0,
481478 deaths: u32 = 0,
......@@ -497,9 +494,6 @@ pub const Inst = struct {
497494 const case = self.cases[case_index];
498495 return (self.deaths + case.index)[0..case.deaths];
499496 }
500 pub fn elseDeaths(self: *const SwitchBr) []*Inst {
501 return (self.deaths + self.else_deaths)[0..self.else_deaths];
502 }
503497 };
504498};
505499
src/zir.zig+19-35
......@@ -501,7 +501,7 @@ pub const Inst = struct {
501501 .slice,
502502 .slice_start,
503503 .import,
504 .switch_range,
504 .switchbr,
505505 => false,
506506
507507 .@"break",
......@@ -513,7 +513,7 @@ pub const Inst = struct {
513513 .unreach_nocheck,
514514 .@"unreachable",
515515 .loop,
516 .switchbr,
516 .switch_range,
517517 => true,
518518 };
519519 }
......@@ -1005,22 +1005,21 @@ pub const Inst = struct {
10051005 positionals: struct {
10061006 target_ptr: *Inst,
10071007 cases: []Case,
1008 /// List of all individual items and ranges
1009 items: []*Inst,
10081010 },
10091011 kw_args: struct {
1010 /// if not null target must support ranges, (be int)
1011 support_range: ?*Inst = null,
1012 special_case: enum {
1013 /// all of positionals.cases are regular cases
1012 /// Pointer to first range if such exists.
1013 range: ?*Inst = null,
1014 special_prong: enum {
10141015 none,
1015 /// last case in positionals.cases is an else case
10161016 @"else",
1017 /// last case in positionals.cases is an underscore case
10181017 underscore,
10191018 } = .none,
10201019 },
10211020
10221021 pub const Case = struct {
1023 items: []*Inst,
1022 item: *Inst,
10241023 body: Module.Body,
10251024 };
10261025 };
......@@ -1286,7 +1285,7 @@ const Writer = struct {
12861285 }
12871286 try stream.writeByteNTimes(' ', self.indent);
12881287 self.indent += 2;
1289 try self.writeParamToStream(stream, &case.items);
1288 try self.writeParamToStream(stream, &case.item);
12901289 try stream.writeAll(" => ");
12911290 try self.writeParamToStream(stream, &case.body);
12921291 self.indent -= 2;
......@@ -1716,7 +1715,7 @@ const Parser = struct {
17161715 while (true) {
17171716 const cur = try cases.addOne();
17181717 skipSpace(self);
1719 cur.items = try self.parseParameterGeneric([]*Inst, body_ctx);
1718 cur.item = try self.parseParameterGeneric(*Inst, body_ctx);
17201719 skipSpace(self);
17211720 try requireEatBytes(self, "=>");
17221721 cur.body = try self.parseBody(body_ctx);
......@@ -2549,8 +2548,7 @@ const EmitZIR = struct {
25492548 },
25502549 .switchbr => blk: {
25512550 const old_inst = inst.castTag(.switchbr).?;
2552 const case_count = old_inst.cases.len + @boolToInt(old_inst.@"else" != null);
2553 const cases = try self.arena.allocator.alloc(Inst.SwitchBr.Case, case_count);
2551 const cases = try self.arena.allocator.alloc(Inst.SwitchBr.Case, old_inst.cases.len);
25542552 const new_inst = try self.arena.allocator.create(Inst.SwitchBr);
25552553 new_inst.* = .{
25562554 .base = .{
......@@ -2560,11 +2558,9 @@ const EmitZIR = struct {
25602558 .positionals = .{
25612559 .target_ptr = try self.resolveInst(new_body, old_inst.target_ptr),
25622560 .cases = cases,
2561 .items = &[_]*Inst{}, // TODO this should actually be populated
25632562 },
2564 .kw_args = .{
2565 .special_case = if (old_inst.@"else" != null) .@"else" else .none,
2566 .support_range = null,
2567 },
2563 .kw_args = .{},
25682564 };
25692565
25702566 var body_tmp = std.ArrayList(*Inst).init(self.allocator);
......@@ -2574,25 +2570,13 @@ const EmitZIR = struct {
25742570 body_tmp.items.len = 0;
25752571
25762572 try self.emitBody(case.body, inst_table, &body_tmp);
2577 const items = try self.arena.allocator.alloc(*Inst, case.items.len);
2578 for (case.items) |item, j| {
2579 items[j] = (try self.emitTypedValue(inst.src, .{
2580 .ty = old_inst.target_ptr.ty.elemType(),
2581 .val = item,
2582 })).inst;
2583 }
2573 const item = (try self.emitTypedValue(inst.src, .{
2574 .ty = old_inst.target_ptr.ty.elemType(),
2575 .val = case.item,
2576 })).inst;
25842577
25852578 cases[i] = .{
2586 .items = items,
2587 .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
2588 };
2589 }
2590 if (old_inst.@"else") |some| {
2591 body_tmp.items.len = 0;
2592
2593 try self.emitBody(some, inst_table, &body_tmp);
2594 cases[cases.len - 1] = .{
2595 .items = &[0]*Inst{},
2579 .item = item,
25962580 .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
25972581 };
25982582 }
......@@ -2846,7 +2830,7 @@ pub fn dumpZir(allocator: *Allocator, kind: []const u8, decl_name: [*:0]const u8
28462830 .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator),
28472831 .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(allocator),
28482832 .arena = std.heap.ArenaAllocator.init(allocator),
2849 .indent = 2,
2833 .indent = 4,
28502834 .next_instr_index = 0,
28512835 };
28522836 defer write.arena.deinit();
src/zir_sema.zig+36-59
......@@ -553,10 +553,13 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c
553553
554554 try analyzeBody(mod, &child_block.base, inst.positionals.body);
555555
556 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);
557 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
556 try parent_block.instructions.appendSlice(mod.gpa, child_block.instructions.items);
558557
559 return copied_instructions[copied_instructions.len - 1];
558 // comptime blocks won't generate any runtime values
559 if (child_block.instructions.items.len == 0)
560 return mod.constVoid(scope, inst.base.src);
561
562 return parent_block.instructions.items[parent_block.instructions.items.len - 1];
560563}
561564
562565fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst {
......@@ -1235,11 +1238,8 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In
12351238
12361239 // TODO comptime execution
12371240
1238 // excludes else and '_' cases
1239 const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);
1240
12411241 const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);
1242 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, case_count);
1242 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len);
12431243
12441244 var case_block: Scope.Block = .{
12451245 .parent = parent_block,
......@@ -1251,58 +1251,39 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In
12511251 };
12521252 defer case_block.instructions.deinit(mod.gpa);
12531253
1254 var items_tmp = std.ArrayList(Value).init(mod.gpa);
1255 defer items_tmp.deinit();
1256
1257 for (inst.positionals.cases[0..case_count]) |case, i| {
1254 for (inst.positionals.cases[0..inst.positionals.cases.len]) |case, i| {
12581255 // Reset without freeing.
12591256 case_block.instructions.items.len = 0;
1260 items_tmp.items.len = 0;
12611257
1262 for (case.items) |item| {
1263 if (item.castTag(.switch_range)) |range| {
1264 return mod.fail(scope, item.src, "genSwitch expand range", .{});
1265 }
1266 const resolved = try resolveInst(mod, scope, item);
1267 const casted = try mod.coerce(scope, target.ty, resolved);
1268 const val = try mod.resolveConstValue(scope, casted);
1269 try items_tmp.append(val);
1270 }
1258 const resolved = try resolveInst(mod, scope, case.item);
1259 const casted = try mod.coerce(scope, target.ty, resolved);
1260 const item = try mod.resolveConstValue(scope, casted);
12711261
12721262 try analyzeBody(mod, &case_block.base, case.body);
12731263
12741264 cases[i] = .{
1275 .items = try parent_block.arena.dupe(Value, items_tmp.items),
1265 .item = item,
12761266 .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
12771267 };
12781268 }
1279
1280 const else_body = if (inst.kw_args.special_case != .none) blk: {
1281 case_block.instructions.items.len = 0;
1282
1283 try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);
1284 break: blk Body{
1285 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
1286 };
1287 } else null;
12881269
1289 return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases, else_body);
1270 return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases);
12901271}
12911272
12921273fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void {
12931274 // validate usage of '_' prongs
1294 if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) {
1275 if (inst.kw_args.special_prong == .underscore and target.ty.zigTypeTag() != .Enum) {
12951276 return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});
12961277 // TODO notes "'_' prong here" inst.positionals.cases[last].src
12971278 }
12981279
12991280 // check that target type supports ranges
1300 if (inst.kw_args.support_range) |some| {
1281 if (inst.kw_args.range) |range_inst| {
13011282 switch (target.ty.zigTypeTag()) {
13021283 .Int, .ComptimeInt, .Float, .ComptimeFloat => {},
13031284 else => {
13041285 return mod.fail(scope, target.src, "ranges not allowed when switching on type {}", .{target.ty});
1305 // TODO notes "range used here" some.src
1286 // TODO notes "range used here" range_inst.src
13061287 },
13071288 }
13081289 }
......@@ -1317,46 +1298,42 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
13171298 .Bool => {
13181299 var true_count: u8 = 0;
13191300 var false_count: u8 = 0;
1320 for (inst.positionals.cases) |case| {
1321 for (case.items) |item| {
1322 const resolved = try resolveInst(mod, scope, item);
1323 const casted = try mod.coerce(scope, Type.initTag(.bool), resolved);
1324 if ((try mod.resolveConstValue(scope, casted)).toBool()) {
1325 true_count += 1;
1326 } else {
1327 false_count += 1;
1328 }
1301 for (inst.positionals.items) |item| {
1302 const resolved = try resolveInst(mod, scope, item);
1303 const casted = try mod.coerce(scope, Type.initTag(.bool), resolved);
1304 if ((try mod.resolveConstValue(scope, casted)).toBool()) {
1305 true_count += 1;
1306 } else {
1307 false_count += 1;
1308 }
13291309
1330 if (true_count > 1 or false_count > 1) {
1331 return mod.fail(scope, item.src, "duplicate switch value", .{});
1332 }
1310 if (true_count > 1 or false_count > 1) {
1311 return mod.fail(scope, item.src, "duplicate switch value", .{});
13331312 }
13341313 }
1335 if ((true_count == 0 or false_count == 0) and inst.kw_args.special_case != .@"else") {
1314 if ((true_count == 0 or false_count == 0) and inst.kw_args.special_prong != .@"else") {
13361315 return mod.fail(scope, inst.base.src, "switch must handle all possibilities", .{});
13371316 }
1338 if ((true_count == 1 and false_count == 1) and inst.kw_args.special_case == .@"else") {
1317 if ((true_count == 1 and false_count == 1) and inst.kw_args.special_prong == .@"else") {
13391318 return mod.fail(scope, inst.base.src, "unreachable else prong, all cases already handled", .{});
13401319 }
13411320 },
13421321 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
1343 if (inst.kw_args.special_case != .@"else") {
1322 if (inst.kw_args.special_prong != .@"else") {
13441323 return mod.fail(scope, inst.base.src, "else prong required when switching on type '{}'", .{target.ty});
13451324 }
13461325
13471326 var seen_values = std.HashMap(Value, usize, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage).init(mod.gpa);
13481327 defer seen_values.deinit();
13491328
1350 for (inst.positionals.cases) |case| {
1351 for (case.items) |item| {
1352 const resolved = try resolveInst(mod, scope, item);
1353 const casted = try mod.coerce(scope, target.ty, resolved);
1354 const val = try mod.resolveConstValue(scope, casted);
1329 for (inst.positionals.items) |item| {
1330 const resolved = try resolveInst(mod, scope, item);
1331 const casted = try mod.coerce(scope, target.ty, resolved);
1332 const val = try mod.resolveConstValue(scope, casted);
13551333
1356 if (try seen_values.fetchPut(val, item.src)) |prev| {
1357 return mod.fail(scope, item.src, "duplicate switch value", .{});
1358 // TODO notes "previous value here" prev.value
1359 }
1334 if (try seen_values.fetchPut(val, item.src)) |prev| {
1335 return mod.fail(scope, item.src, "duplicate switch value", .{});
1336 // TODO notes "previous value here" prev.value
13601337 }
13611338 }
13621339 },