| author | |
| committer | |
| log | 2020ca640e8db50f1cb5a1ceaa42c28a25483bad |
| tree | 1e539fd2e9b3cb16f166519f2f8da6ef2c935490 |
| parent | 11998d2972bf1f7253351fc756c4f1766a412f1d |
| signature |
6 files changed, 127 insertions(+), 48 deletions(-)
src/Module.zig+23| ... | @@ -2098,6 +2098,29 @@ pub fn addCall( | ... | @@ -2098,6 +2098,29 @@ pub fn addCall( |
| 2098 | return &inst.base; | 2098 | return &inst.base; |
| 2099 | } | 2099 | } |
| 2100 | 2100 | ||
| 2101 | pub fn addSwitchBr( | ||
| 2102 | self: *Module, | ||
| 2103 | block: *Scope.Block, | ||
| 2104 | src: usize, | ||
| 2105 | target_ptr: *Inst, | ||
| 2106 | cases: []Inst.SwitchBr.Case, | ||
| 2107 | else_body: ?Module.Body, | ||
| 2108 | ) !*Inst { | ||
| 2109 | const inst = try block.arena.create(Inst.SwitchBr); | ||
| 2110 | inst.* = .{ | ||
| 2111 | .base = .{ | ||
| 2112 | .tag = .switchbr, | ||
| 2113 | .ty = Type.initTag(.noreturn), | ||
| 2114 | .src = src, | ||
| 2115 | }, | ||
| 2116 | .target_ptr = target_ptr, | ||
| 2117 | .cases = cases, | ||
| 2118 | .@"else" = else_body, | ||
| 2119 | }; | ||
| 2120 | try block.instructions.append(self.gpa, &inst.base); | ||
| 2121 | return &inst.base; | ||
| 2122 | } | ||
| 2123 | |||
| 2101 | pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst { | 2124 | pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst { |
| 2102 | const const_inst = try scope.arena().create(Inst.Constant); | 2125 | const const_inst = try scope.arena().create(Inst.Constant); |
| 2103 | const_inst.* = .{ | 2126 | const_inst.* = .{ |
src/astgen.zig+3-3| ... | @@ -1573,8 +1573,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1573,8 +1573,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1573 | const tree = scope.tree(); | 1573 | const tree = scope.tree(); |
| 1574 | const switch_src = tree.token_locs[switch_node.switch_token].start; | 1574 | const switch_src = tree.token_locs[switch_node.switch_token].start; |
| 1575 | const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr); | 1575 | const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr); |
| 1576 | const cases = try scope.arena().alloc(zir.Inst.Switch.Case, switch_node.cases_len); | 1576 | const cases = try scope.arena().alloc(zir.Inst.SwitchBr.Case, switch_node.cases_len); |
| 1577 | var kw_args: std.meta.fieldInfo(zir.Inst.Switch, "kw_args").field_type = .{}; | 1577 | var kw_args: std.meta.fieldInfo(zir.Inst.SwitchBr, "kw_args").field_type = .{}; |
| 1578 | 1578 | ||
| 1579 | // first we gather all the switch items and check else/'_' prongs | 1579 | // first we gather all the switch items and check else/'_' prongs |
| 1580 | var case_index: usize = 0; | 1580 | var case_index: usize = 0; |
| ... | @@ -1643,7 +1643,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1643,7 +1643,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1643 | } | 1643 | } |
| 1644 | 1644 | ||
| 1645 | // Then we add the switch instruction to finish the block. | 1645 | // Then we add the switch instruction to finish the block. |
| 1646 | _ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.Switch, .{ | 1646 | _ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{ |
| 1647 | .target_ptr = target_ptr, | 1647 | .target_ptr = target_ptr, |
| 1648 | .cases = cases, | 1648 | .cases = cases, |
| 1649 | }, kw_args); | 1649 | }, kw_args); |
src/codegen.zig+2-2| ... | @@ -786,7 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -786,7 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 786 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), | 786 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), |
| 787 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), | 787 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), |
| 788 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), | 788 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), |
| 789 | .@"switch" => return self.genSwitch(inst.castTag(.@"switch").?), | 789 | .switchbr => return self.genSwitch(inst.castTag(.switchbr).?), |
| 790 | } | 790 | } |
| 791 | } | 791 | } |
| 792 | 792 | ||
| ... | @@ -1990,7 +1990,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1990,7 +1990,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1990 | return @bitCast(MCValue, inst.codegen.mcv); | 1990 | return @bitCast(MCValue, inst.codegen.mcv); |
| 1991 | } | 1991 | } |
| 1992 | 1992 | ||
| 1993 | fn genSwitch(self: *Self, inst: *ir.Inst.Switch) !MCValue { | 1993 | fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue { |
| 1994 | switch (arch) { | 1994 | switch (arch) { |
| 1995 | else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}), | 1995 | else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}), |
| 1996 | } | 1996 | } |
src/ir.zig+27-8| ... | @@ -91,7 +91,7 @@ pub const Inst = struct { | ... | @@ -91,7 +91,7 @@ pub const Inst = struct { |
| 91 | intcast, | 91 | intcast, |
| 92 | unwrap_optional, | 92 | unwrap_optional, |
| 93 | wrap_optional, | 93 | wrap_optional, |
| 94 | @"switch", | 94 | switchbr, |
| 95 | 95 | ||
| 96 | pub fn Type(tag: Tag) type { | 96 | pub fn Type(tag: Tag) type { |
| 97 | return switch (tag) { | 97 | return switch (tag) { |
| ... | @@ -138,7 +138,7 @@ pub const Inst = struct { | ... | @@ -138,7 +138,7 @@ pub const Inst = struct { |
| 138 | .constant => Constant, | 138 | .constant => Constant, |
| 139 | .loop => Loop, | 139 | .loop => Loop, |
| 140 | .varptr => VarPtr, | 140 | .varptr => VarPtr, |
| 141 | .@"switch" => Switch, | 141 | .switchbr => SwitchBr, |
| 142 | }; | 142 | }; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| ... | @@ -461,26 +461,45 @@ pub const Inst = struct { | ... | @@ -461,26 +461,45 @@ pub const Inst = struct { |
| 461 | } | 461 | } |
| 462 | }; | 462 | }; |
| 463 | 463 | ||
| 464 | pub const Switch = struct { | 464 | pub const SwitchBr = struct { |
| 465 | pub const base_tag = Tag.@"switch"; | 465 | pub const base_tag = Tag.switchbr; |
| 466 | 466 | ||
| 467 | base: Inst, | 467 | base: Inst, |
| 468 | target_ptr: *Inst, | 468 | target_ptr: *Inst, |
| 469 | cases: []Case, | 469 | cases: []Case, |
| 470 | @"else": ?Body, | 470 | @"else": ?Body, |
| 471 | /// Set of instructions whose lifetimes end at the start of one of the cases. | ||
| 472 | /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... , case_n_count ... else_count]. | ||
| 473 | deaths: [*]*Inst = undefined, | ||
| 474 | else_index: u32 = 0, | ||
| 475 | else_deaths: u32 = 0, | ||
| 471 | 476 | ||
| 472 | pub const Case = struct { | 477 | pub const Case = struct { |
| 473 | items: []Value, | 478 | items: []Value, |
| 474 | body: Body, | 479 | body: Body, |
| 480 | index: u32 = 0, | ||
| 481 | deaths: u32 = 0, | ||
| 475 | }; | 482 | }; |
| 476 | 483 | ||
| 477 | pub fn operandCount(self: *const Switch) usize { | 484 | pub fn operandCount(self: *const SwitchBr) usize { |
| 478 | return 1; | 485 | return 1; |
| 479 | } | 486 | } |
| 480 | pub fn getOperand(self: *const Switch, index: usize) ?*Inst { | 487 | pub fn getOperand(self: *const SwitchBr, index: usize) ?*Inst { |
| 481 | return self.target_ptr; | 488 | var i = index; |
| 489 | |||
| 490 | if (i < 1) | ||
| 491 | return self.target_ptr; | ||
| 492 | i -= 1; | ||
| 493 | |||
| 494 | return null; | ||
| 495 | } | ||
| 496 | pub fn caseDeaths(self: *const SwitchBr, case_index: usize) []*Inst { | ||
| 497 | const case = self.cases[case_index]; | ||
| 498 | return (self.deaths + case.index)[0..case.deaths]; | ||
| 499 | } | ||
| 500 | pub fn elseDeaths(self: *const SwitchBr) []*Inst { | ||
| 501 | return (self.deaths + self.else_deaths)[0..self.else_deaths]; | ||
| 482 | } | 502 | } |
| 483 | // TODO case body deaths | ||
| 484 | }; | 503 | }; |
| 485 | }; | 504 | }; |
| 486 | 505 |
src/zir.zig+63-16| ... | @@ -273,7 +273,7 @@ pub const Inst = struct { | ... | @@ -273,7 +273,7 @@ pub const Inst = struct { |
| 273 | /// Enum literal | 273 | /// Enum literal |
| 274 | enum_literal, | 274 | enum_literal, |
| 275 | /// A switch expression. | 275 | /// A switch expression. |
| 276 | @"switch", | 276 | switchbr, |
| 277 | /// A range in a switch case, `lhs...rhs`. | 277 | /// A range in a switch case, `lhs...rhs`. |
| 278 | /// Only checks that `lhs >= rhs` if they are ints or floats, everything else is | 278 | /// Only checks that `lhs >= rhs` if they are ints or floats, everything else is |
| 279 | /// validated by the .switch instruction. | 279 | /// validated by the .switch instruction. |
| ... | @@ -396,7 +396,7 @@ pub const Inst = struct { | ... | @@ -396,7 +396,7 @@ pub const Inst = struct { |
| 396 | .enum_literal => EnumLiteral, | 396 | .enum_literal => EnumLiteral, |
| 397 | .error_set => ErrorSet, | 397 | .error_set => ErrorSet, |
| 398 | .slice => Slice, | 398 | .slice => Slice, |
| 399 | .@"switch" => Switch, | 399 | .switchbr => SwitchBr, |
| 400 | }; | 400 | }; |
| 401 | } | 401 | } |
| 402 | 402 | ||
| ... | @@ -513,7 +513,7 @@ pub const Inst = struct { | ... | @@ -513,7 +513,7 @@ pub const Inst = struct { |
| 513 | .unreach_nocheck, | 513 | .unreach_nocheck, |
| 514 | .@"unreachable", | 514 | .@"unreachable", |
| 515 | .loop, | 515 | .loop, |
| 516 | .@"switch", | 516 | .switchbr, |
| 517 | => true, | 517 | => true, |
| 518 | }; | 518 | }; |
| 519 | } | 519 | } |
| ... | @@ -998,8 +998,8 @@ pub const Inst = struct { | ... | @@ -998,8 +998,8 @@ pub const Inst = struct { |
| 998 | }, | 998 | }, |
| 999 | }; | 999 | }; |
| 1000 | 1000 | ||
| 1001 | pub const Switch = struct { | 1001 | pub const SwitchBr = struct { |
| 1002 | pub const base_tag = Tag.@"switch"; | 1002 | pub const base_tag = Tag.switchbr; |
| 1003 | base: Inst, | 1003 | base: Inst, |
| 1004 | 1004 | ||
| 1005 | positionals: struct { | 1005 | positionals: struct { |
| ... | @@ -1275,24 +1275,24 @@ const Writer = struct { | ... | @@ -1275,24 +1275,24 @@ const Writer = struct { |
| 1275 | } | 1275 | } |
| 1276 | try stream.writeByte(']'); | 1276 | try stream.writeByte(']'); |
| 1277 | }, | 1277 | }, |
| 1278 | []Inst.Switch.Case => { | 1278 | []Inst.SwitchBr.Case => { |
| 1279 | if (param.len == 0) { | 1279 | if (param.len == 0) { |
| 1280 | return stream.writeAll("{}"); | 1280 | return stream.writeAll("{}"); |
| 1281 | } | 1281 | } |
| 1282 | try stream.writeAll("{\n"); | 1282 | try stream.writeAll("{\n"); |
| 1283 | self.indent += 2; | ||
| 1284 | for (param) |*case, i| { | 1283 | for (param) |*case, i| { |
| 1285 | if (i != 0) { | 1284 | if (i != 0) { |
| 1286 | try stream.writeAll(",\n"); | 1285 | try stream.writeAll(",\n"); |
| 1287 | } | 1286 | } |
| 1288 | try stream.writeByteNTimes(' ', self.indent); | 1287 | try stream.writeByteNTimes(' ', self.indent); |
| 1288 | self.indent += 2; | ||
| 1289 | try self.writeParamToStream(stream, &case.items); | 1289 | try self.writeParamToStream(stream, &case.items); |
| 1290 | try stream.writeAll(" => "); | 1290 | try stream.writeAll(" => "); |
| 1291 | try self.writeParamToStream(stream, &case.body); | 1291 | try self.writeParamToStream(stream, &case.body); |
| 1292 | self.indent -= 2; | ||
| 1292 | } | 1293 | } |
| 1293 | try stream.writeByte('\n'); | 1294 | try stream.writeByte('\n'); |
| 1294 | self.indent -= 2; | 1295 | try stream.writeByteNTimes(' ', self.indent - 2); |
| 1295 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1296 | try stream.writeByte('}'); | 1296 | try stream.writeByte('}'); |
| 1297 | }, | 1297 | }, |
| 1298 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), | 1298 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), |
| ... | @@ -1707,12 +1707,12 @@ const Parser = struct { | ... | @@ -1707,12 +1707,12 @@ const Parser = struct { |
| 1707 | try requireEatBytes(self, "]"); | 1707 | try requireEatBytes(self, "]"); |
| 1708 | return strings.toOwnedSlice(); | 1708 | return strings.toOwnedSlice(); |
| 1709 | }, | 1709 | }, |
| 1710 | []Inst.Switch.Case => { | 1710 | []Inst.SwitchBr.Case => { |
| 1711 | try requireEatBytes(self, "{"); | 1711 | try requireEatBytes(self, "{"); |
| 1712 | skipSpace(self); | 1712 | skipSpace(self); |
| 1713 | if (eatByte(self, '}')) return &[0]Inst.Switch.Case{}; | 1713 | if (eatByte(self, '}')) return &[0]Inst.SwitchBr.Case{}; |
| 1714 | 1714 | ||
| 1715 | var cases = std.ArrayList(Inst.Switch.Case).init(&self.arena.allocator); | 1715 | var cases = std.ArrayList(Inst.SwitchBr.Case).init(&self.arena.allocator); |
| 1716 | while (true) { | 1716 | while (true) { |
| 1717 | const cur = try cases.addOne(); | 1717 | const cur = try cases.addOne(); |
| 1718 | skipSpace(self); | 1718 | skipSpace(self); |
| ... | @@ -1824,7 +1824,7 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void { | ... | @@ -1824,7 +1824,7 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void { |
| 1824 | .arena = std.heap.ArenaAllocator.init(allocator), | 1824 | .arena = std.heap.ArenaAllocator.init(allocator), |
| 1825 | .old_module = &old_module, | 1825 | .old_module = &old_module, |
| 1826 | .next_auto_name = 0, | 1826 | .next_auto_name = 0, |
| 1827 | .names = std.StringHashMap(void).init(allocator), | 1827 | .names = std.StringArrayHashMap(void).init(allocator), |
| 1828 | .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator), | 1828 | .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator), |
| 1829 | .indent = 0, | 1829 | .indent = 0, |
| 1830 | .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator), | 1830 | .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator), |
| ... | @@ -2547,11 +2547,58 @@ const EmitZIR = struct { | ... | @@ -2547,11 +2547,58 @@ const EmitZIR = struct { |
| 2547 | }; | 2547 | }; |
| 2548 | break :blk &new_inst.base; | 2548 | break :blk &new_inst.base; |
| 2549 | }, | 2549 | }, |
| 2550 | .switchbr => blk: { | ||
| 2551 | 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); | ||
| 2554 | const new_inst = try self.arena.allocator.create(Inst.SwitchBr); | ||
| 2555 | new_inst.* = .{ | ||
| 2556 | .base = .{ | ||
| 2557 | .src = inst.src, | ||
| 2558 | .tag = Inst.SwitchBr.base_tag, | ||
| 2559 | }, | ||
| 2560 | .positionals = .{ | ||
| 2561 | .target_ptr = try self.resolveInst(new_body, old_inst.target_ptr), | ||
| 2562 | .cases = cases, | ||
| 2563 | }, | ||
| 2564 | .kw_args = .{ | ||
| 2565 | .special_case = if (old_inst.@"else" != null) .@"else" else .none, | ||
| 2566 | .support_range = null, | ||
| 2567 | }, | ||
| 2568 | }; | ||
| 2550 | 2569 | ||
| 2551 | .varptr => @panic("TODO"), | 2570 | var body_tmp = std.ArrayList(*Inst).init(self.allocator); |
| 2552 | .@"switch" => { | 2571 | defer body_tmp.deinit(); |
| 2553 | @panic("TODO"); | 2572 | |
| 2573 | for (old_inst.cases) |case, i| { | ||
| 2574 | body_tmp.items.len = 0; | ||
| 2575 | |||
| 2576 | 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 | } | ||
| 2584 | |||
| 2585 | 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{}, | ||
| 2596 | .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) }, | ||
| 2597 | }; | ||
| 2598 | } | ||
| 2599 | break :blk &new_inst.base; | ||
| 2554 | }, | 2600 | }, |
| 2601 | .varptr => @panic("TODO"), | ||
| 2555 | }; | 2602 | }; |
| 2556 | try self.metadata.put(new_inst, .{ | 2603 | try self.metadata.put(new_inst, .{ |
| 2557 | .deaths = inst.deaths, | 2604 | .deaths = inst.deaths, |
src/zir_sema.zig+9-19| ... | @@ -135,7 +135,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -135,7 +135,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 135 | .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?), | 135 | .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?), |
| 136 | .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?), | 136 | .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?), |
| 137 | .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?), | 137 | .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?), |
| 138 | .@"switch" => return analyzeInstSwitch(mod, scope, old_inst.castTag(.@"switch").?), | 138 | .switchbr => return analyzeInstSwitchBr(mod, scope, old_inst.castTag(.switchbr).?), |
| 139 | .switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?), | 139 | .switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?), |
| 140 | } | 140 | } |
| 141 | } | 141 | } |
| ... | @@ -1228,7 +1228,7 @@ fn analyzeInstSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In | ... | @@ -1228,7 +1228,7 @@ fn analyzeInstSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In |
| 1228 | return mod.constVoid(scope, inst.base.src); | 1228 | return mod.constVoid(scope, inst.base.src); |
| 1229 | } | 1229 | } |
| 1230 | 1230 | ||
| 1231 | fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerError!*Inst { | 1231 | fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) InnerError!*Inst { |
| 1232 | const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr); | 1232 | const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr); |
| 1233 | const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src); | 1233 | const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src); |
| 1234 | try validateSwitch(mod, scope, target, inst); | 1234 | try validateSwitch(mod, scope, target, inst); |
| ... | @@ -1239,17 +1239,7 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE | ... | @@ -1239,17 +1239,7 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE |
| 1239 | const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none); | 1239 | const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none); |
| 1240 | 1240 | ||
| 1241 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); | 1241 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 1242 | const switch_inst = try parent_block.arena.create(Inst.Switch); | 1242 | const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, case_count); |
| 1243 | switch_inst.* = .{ | ||
| 1244 | .base = .{ | ||
| 1245 | .tag = Inst.Switch.base_tag, | ||
| 1246 | .ty = Type.initTag(.noreturn), | ||
| 1247 | .src = inst.base.src, | ||
| 1248 | }, | ||
| 1249 | .target_ptr = target_ptr, | ||
| 1250 | .@"else" = null, | ||
| 1251 | .cases = try parent_block.arena.alloc(Inst.Switch.Case, case_count), | ||
| 1252 | }; | ||
| 1253 | 1243 | ||
| 1254 | var case_block: Scope.Block = .{ | 1244 | var case_block: Scope.Block = .{ |
| 1255 | .parent = parent_block, | 1245 | .parent = parent_block, |
| ... | @@ -1281,25 +1271,25 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE | ... | @@ -1281,25 +1271,25 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE |
| 1281 | 1271 | ||
| 1282 | try analyzeBody(mod, &case_block.base, case.body); | 1272 | try analyzeBody(mod, &case_block.base, case.body); |
| 1283 | 1273 | ||
| 1284 | switch_inst.cases[i] = .{ | 1274 | cases[i] = .{ |
| 1285 | .items = try parent_block.arena.dupe(Value, items_tmp.items), | 1275 | .items = try parent_block.arena.dupe(Value, items_tmp.items), |
| 1286 | .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) }, | 1276 | .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) }, |
| 1287 | }; | 1277 | }; |
| 1288 | } | 1278 | } |
| 1289 | 1279 | ||
| 1290 | if (inst.kw_args.special_case != .none) { | 1280 | const else_body = if (inst.kw_args.special_case != .none) blk: { |
| 1291 | case_block.instructions.items.len = 0; | 1281 | case_block.instructions.items.len = 0; |
| 1292 | 1282 | ||
| 1293 | try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body); | 1283 | try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body); |
| 1294 | switch_inst.@"else" = .{ | 1284 | break: blk Body{ |
| 1295 | .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items), | 1285 | .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items), |
| 1296 | }; | 1286 | }; |
| 1297 | } | 1287 | } else null; |
| 1298 | 1288 | ||
| 1299 | return &switch_inst.base; | 1289 | return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases, else_body); |
| 1300 | } | 1290 | } |
| 1301 | 1291 | ||
| 1302 | fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Switch) InnerError!void { | 1292 | fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void { |
| 1303 | // validate usage of '_' prongs | 1293 | // validate usage of '_' prongs |
| 1304 | if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) { | 1294 | if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) { |
| 1305 | return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{}); | 1295 | return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{}); |