stage2: switch emit zir
This commit is contained in:
parent
11998d2972
commit
2020ca640e
@ -2098,6 +2098,29 @@ pub fn addCall(
|
|||||||
return &inst.base;
|
return &inst.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addSwitchBr(
|
||||||
|
self: *Module,
|
||||||
|
block: *Scope.Block,
|
||||||
|
src: usize,
|
||||||
|
target_ptr: *Inst,
|
||||||
|
cases: []Inst.SwitchBr.Case,
|
||||||
|
else_body: ?Module.Body,
|
||||||
|
) !*Inst {
|
||||||
|
const inst = try block.arena.create(Inst.SwitchBr);
|
||||||
|
inst.* = .{
|
||||||
|
.base = .{
|
||||||
|
.tag = .switchbr,
|
||||||
|
.ty = Type.initTag(.noreturn),
|
||||||
|
.src = src,
|
||||||
|
},
|
||||||
|
.target_ptr = target_ptr,
|
||||||
|
.cases = cases,
|
||||||
|
.@"else" = else_body,
|
||||||
|
};
|
||||||
|
try block.instructions.append(self.gpa, &inst.base);
|
||||||
|
return &inst.base;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
|
pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
|
||||||
const const_inst = try scope.arena().create(Inst.Constant);
|
const const_inst = try scope.arena().create(Inst.Constant);
|
||||||
const_inst.* = .{
|
const_inst.* = .{
|
||||||
|
@ -1573,8 +1573,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
|
|||||||
const tree = scope.tree();
|
const tree = scope.tree();
|
||||||
const switch_src = tree.token_locs[switch_node.switch_token].start;
|
const switch_src = tree.token_locs[switch_node.switch_token].start;
|
||||||
const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr);
|
const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr);
|
||||||
const cases = try scope.arena().alloc(zir.Inst.Switch.Case, switch_node.cases_len);
|
const cases = try scope.arena().alloc(zir.Inst.SwitchBr.Case, switch_node.cases_len);
|
||||||
var kw_args: std.meta.fieldInfo(zir.Inst.Switch, "kw_args").field_type = .{};
|
var kw_args: std.meta.fieldInfo(zir.Inst.SwitchBr, "kw_args").field_type = .{};
|
||||||
|
|
||||||
// first we gather all the switch items and check else/'_' prongs
|
// first we gather all the switch items and check else/'_' prongs
|
||||||
var case_index: usize = 0;
|
var case_index: usize = 0;
|
||||||
@ -1643,7 +1643,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then we add the switch instruction to finish the block.
|
// Then we add the switch instruction to finish the block.
|
||||||
_ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.Switch, .{
|
_ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{
|
||||||
.target_ptr = target_ptr,
|
.target_ptr = target_ptr,
|
||||||
.cases = cases,
|
.cases = cases,
|
||||||
}, kw_args);
|
}, kw_args);
|
||||||
|
@ -786,7 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
.unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
|
.unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
|
||||||
.wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
|
.wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
|
||||||
.varptr => return self.genVarPtr(inst.castTag(.varptr).?),
|
.varptr => return self.genVarPtr(inst.castTag(.varptr).?),
|
||||||
.@"switch" => return self.genSwitch(inst.castTag(.@"switch").?),
|
.switchbr => return self.genSwitch(inst.castTag(.switchbr).?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1990,7 +1990,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
return @bitCast(MCValue, inst.codegen.mcv);
|
return @bitCast(MCValue, inst.codegen.mcv);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn genSwitch(self: *Self, inst: *ir.Inst.Switch) !MCValue {
|
fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue {
|
||||||
switch (arch) {
|
switch (arch) {
|
||||||
else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),
|
else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),
|
||||||
}
|
}
|
||||||
|
35
src/ir.zig
35
src/ir.zig
@ -91,7 +91,7 @@ pub const Inst = struct {
|
|||||||
intcast,
|
intcast,
|
||||||
unwrap_optional,
|
unwrap_optional,
|
||||||
wrap_optional,
|
wrap_optional,
|
||||||
@"switch",
|
switchbr,
|
||||||
|
|
||||||
pub fn Type(tag: Tag) type {
|
pub fn Type(tag: Tag) type {
|
||||||
return switch (tag) {
|
return switch (tag) {
|
||||||
@ -138,7 +138,7 @@ pub const Inst = struct {
|
|||||||
.constant => Constant,
|
.constant => Constant,
|
||||||
.loop => Loop,
|
.loop => Loop,
|
||||||
.varptr => VarPtr,
|
.varptr => VarPtr,
|
||||||
.@"switch" => Switch,
|
.switchbr => SwitchBr,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,26 +461,45 @@ pub const Inst = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Switch = struct {
|
pub const SwitchBr = struct {
|
||||||
pub const base_tag = Tag.@"switch";
|
pub const base_tag = Tag.switchbr;
|
||||||
|
|
||||||
base: Inst,
|
base: Inst,
|
||||||
target_ptr: *Inst,
|
target_ptr: *Inst,
|
||||||
cases: []Case,
|
cases: []Case,
|
||||||
@"else": ?Body,
|
@"else": ?Body,
|
||||||
|
/// Set of instructions whose lifetimes end at the start of one of the cases.
|
||||||
|
/// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... , case_n_count ... else_count].
|
||||||
|
deaths: [*]*Inst = undefined,
|
||||||
|
else_index: u32 = 0,
|
||||||
|
else_deaths: u32 = 0,
|
||||||
|
|
||||||
pub const Case = struct {
|
pub const Case = struct {
|
||||||
items: []Value,
|
items: []Value,
|
||||||
body: Body,
|
body: Body,
|
||||||
|
index: u32 = 0,
|
||||||
|
deaths: u32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn operandCount(self: *const Switch) usize {
|
pub fn operandCount(self: *const SwitchBr) usize {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
pub fn getOperand(self: *const Switch, index: usize) ?*Inst {
|
pub fn getOperand(self: *const SwitchBr, index: usize) ?*Inst {
|
||||||
return self.target_ptr;
|
var i = index;
|
||||||
|
|
||||||
|
if (i < 1)
|
||||||
|
return self.target_ptr;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
pub fn caseDeaths(self: *const SwitchBr, case_index: usize) []*Inst {
|
||||||
|
const case = self.cases[case_index];
|
||||||
|
return (self.deaths + case.index)[0..case.deaths];
|
||||||
|
}
|
||||||
|
pub fn elseDeaths(self: *const SwitchBr) []*Inst {
|
||||||
|
return (self.deaths + self.else_deaths)[0..self.else_deaths];
|
||||||
}
|
}
|
||||||
// TODO case body deaths
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
79
src/zir.zig
79
src/zir.zig
@ -273,7 +273,7 @@ pub const Inst = struct {
|
|||||||
/// Enum literal
|
/// Enum literal
|
||||||
enum_literal,
|
enum_literal,
|
||||||
/// A switch expression.
|
/// A switch expression.
|
||||||
@"switch",
|
switchbr,
|
||||||
/// A range in a switch case, `lhs...rhs`.
|
/// A range in a switch case, `lhs...rhs`.
|
||||||
/// Only checks that `lhs >= rhs` if they are ints or floats, everything else is
|
/// Only checks that `lhs >= rhs` if they are ints or floats, everything else is
|
||||||
/// validated by the .switch instruction.
|
/// validated by the .switch instruction.
|
||||||
@ -396,7 +396,7 @@ pub const Inst = struct {
|
|||||||
.enum_literal => EnumLiteral,
|
.enum_literal => EnumLiteral,
|
||||||
.error_set => ErrorSet,
|
.error_set => ErrorSet,
|
||||||
.slice => Slice,
|
.slice => Slice,
|
||||||
.@"switch" => Switch,
|
.switchbr => SwitchBr,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +513,7 @@ pub const Inst = struct {
|
|||||||
.unreach_nocheck,
|
.unreach_nocheck,
|
||||||
.@"unreachable",
|
.@"unreachable",
|
||||||
.loop,
|
.loop,
|
||||||
.@"switch",
|
.switchbr,
|
||||||
=> true,
|
=> true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -998,8 +998,8 @@ pub const Inst = struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Switch = struct {
|
pub const SwitchBr = struct {
|
||||||
pub const base_tag = Tag.@"switch";
|
pub const base_tag = Tag.switchbr;
|
||||||
base: Inst,
|
base: Inst,
|
||||||
|
|
||||||
positionals: struct {
|
positionals: struct {
|
||||||
@ -1275,24 +1275,24 @@ const Writer = struct {
|
|||||||
}
|
}
|
||||||
try stream.writeByte(']');
|
try stream.writeByte(']');
|
||||||
},
|
},
|
||||||
[]Inst.Switch.Case => {
|
[]Inst.SwitchBr.Case => {
|
||||||
if (param.len == 0) {
|
if (param.len == 0) {
|
||||||
return stream.writeAll("{}");
|
return stream.writeAll("{}");
|
||||||
}
|
}
|
||||||
try stream.writeAll("{\n");
|
try stream.writeAll("{\n");
|
||||||
self.indent += 2;
|
|
||||||
for (param) |*case, i| {
|
for (param) |*case, i| {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
try stream.writeAll(",\n");
|
try stream.writeAll(",\n");
|
||||||
}
|
}
|
||||||
try stream.writeByteNTimes(' ', self.indent);
|
try stream.writeByteNTimes(' ', self.indent);
|
||||||
|
self.indent += 2;
|
||||||
try self.writeParamToStream(stream, &case.items);
|
try self.writeParamToStream(stream, &case.items);
|
||||||
try stream.writeAll(" => ");
|
try stream.writeAll(" => ");
|
||||||
try self.writeParamToStream(stream, &case.body);
|
try self.writeParamToStream(stream, &case.body);
|
||||||
|
self.indent -= 2;
|
||||||
}
|
}
|
||||||
try stream.writeByte('\n');
|
try stream.writeByte('\n');
|
||||||
self.indent -= 2;
|
try stream.writeByteNTimes(' ', self.indent - 2);
|
||||||
try stream.writeByteNTimes(' ', self.indent);
|
|
||||||
try stream.writeByte('}');
|
try stream.writeByte('}');
|
||||||
},
|
},
|
||||||
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
||||||
@ -1707,12 +1707,12 @@ const Parser = struct {
|
|||||||
try requireEatBytes(self, "]");
|
try requireEatBytes(self, "]");
|
||||||
return strings.toOwnedSlice();
|
return strings.toOwnedSlice();
|
||||||
},
|
},
|
||||||
[]Inst.Switch.Case => {
|
[]Inst.SwitchBr.Case => {
|
||||||
try requireEatBytes(self, "{");
|
try requireEatBytes(self, "{");
|
||||||
skipSpace(self);
|
skipSpace(self);
|
||||||
if (eatByte(self, '}')) return &[0]Inst.Switch.Case{};
|
if (eatByte(self, '}')) return &[0]Inst.SwitchBr.Case{};
|
||||||
|
|
||||||
var cases = std.ArrayList(Inst.Switch.Case).init(&self.arena.allocator);
|
var cases = std.ArrayList(Inst.SwitchBr.Case).init(&self.arena.allocator);
|
||||||
while (true) {
|
while (true) {
|
||||||
const cur = try cases.addOne();
|
const cur = try cases.addOne();
|
||||||
skipSpace(self);
|
skipSpace(self);
|
||||||
@ -1824,7 +1824,7 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {
|
|||||||
.arena = std.heap.ArenaAllocator.init(allocator),
|
.arena = std.heap.ArenaAllocator.init(allocator),
|
||||||
.old_module = &old_module,
|
.old_module = &old_module,
|
||||||
.next_auto_name = 0,
|
.next_auto_name = 0,
|
||||||
.names = std.StringHashMap(void).init(allocator),
|
.names = std.StringArrayHashMap(void).init(allocator),
|
||||||
.primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
|
.primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
|
||||||
.indent = 0,
|
.indent = 0,
|
||||||
.block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),
|
.block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),
|
||||||
@ -2547,11 +2547,58 @@ const EmitZIR = struct {
|
|||||||
};
|
};
|
||||||
break :blk &new_inst.base;
|
break :blk &new_inst.base;
|
||||||
},
|
},
|
||||||
|
.switchbr => blk: {
|
||||||
|
const old_inst = inst.castTag(.switchbr).?;
|
||||||
|
const case_count = old_inst.cases.len + @boolToInt(old_inst.@"else" != null);
|
||||||
|
const cases = try self.arena.allocator.alloc(Inst.SwitchBr.Case, case_count);
|
||||||
|
const new_inst = try self.arena.allocator.create(Inst.SwitchBr);
|
||||||
|
new_inst.* = .{
|
||||||
|
.base = .{
|
||||||
|
.src = inst.src,
|
||||||
|
.tag = Inst.SwitchBr.base_tag,
|
||||||
|
},
|
||||||
|
.positionals = .{
|
||||||
|
.target_ptr = try self.resolveInst(new_body, old_inst.target_ptr),
|
||||||
|
.cases = cases,
|
||||||
|
},
|
||||||
|
.kw_args = .{
|
||||||
|
.special_case = if (old_inst.@"else" != null) .@"else" else .none,
|
||||||
|
.support_range = null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
.varptr => @panic("TODO"),
|
var body_tmp = std.ArrayList(*Inst).init(self.allocator);
|
||||||
.@"switch" => {
|
defer body_tmp.deinit();
|
||||||
@panic("TODO");
|
|
||||||
|
for (old_inst.cases) |case, i| {
|
||||||
|
body_tmp.items.len = 0;
|
||||||
|
|
||||||
|
try self.emitBody(case.body, inst_table, &body_tmp);
|
||||||
|
const items = try self.arena.allocator.alloc(*Inst, case.items.len);
|
||||||
|
for (case.items) |item, j| {
|
||||||
|
items[j] = (try self.emitTypedValue(inst.src, .{
|
||||||
|
.ty = old_inst.target_ptr.ty.elemType(),
|
||||||
|
.val = item,
|
||||||
|
})).inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
cases[i] = .{
|
||||||
|
.items = items,
|
||||||
|
.body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (old_inst.@"else") |some| {
|
||||||
|
body_tmp.items.len = 0;
|
||||||
|
|
||||||
|
try self.emitBody(some, inst_table, &body_tmp);
|
||||||
|
cases[cases.len - 1] = .{
|
||||||
|
.items = &[0]*Inst{},
|
||||||
|
.body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break :blk &new_inst.base;
|
||||||
},
|
},
|
||||||
|
.varptr => @panic("TODO"),
|
||||||
};
|
};
|
||||||
try self.metadata.put(new_inst, .{
|
try self.metadata.put(new_inst, .{
|
||||||
.deaths = inst.deaths,
|
.deaths = inst.deaths,
|
||||||
|
@ -135,7 +135,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
|||||||
.slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
|
.slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
|
||||||
.slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
|
.slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
|
||||||
.import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),
|
.import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),
|
||||||
.@"switch" => return analyzeInstSwitch(mod, scope, old_inst.castTag(.@"switch").?),
|
.switchbr => return analyzeInstSwitchBr(mod, scope, old_inst.castTag(.switchbr).?),
|
||||||
.switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
|
.switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1228,7 +1228,7 @@ fn analyzeInstSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In
|
|||||||
return mod.constVoid(scope, inst.base.src);
|
return mod.constVoid(scope, inst.base.src);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerError!*Inst {
|
fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) InnerError!*Inst {
|
||||||
const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr);
|
const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr);
|
||||||
const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src);
|
const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src);
|
||||||
try validateSwitch(mod, scope, target, inst);
|
try validateSwitch(mod, scope, target, inst);
|
||||||
@ -1239,17 +1239,7 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
|
|||||||
const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);
|
const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);
|
||||||
|
|
||||||
const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);
|
const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);
|
||||||
const switch_inst = try parent_block.arena.create(Inst.Switch);
|
const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, case_count);
|
||||||
switch_inst.* = .{
|
|
||||||
.base = .{
|
|
||||||
.tag = Inst.Switch.base_tag,
|
|
||||||
.ty = Type.initTag(.noreturn),
|
|
||||||
.src = inst.base.src,
|
|
||||||
},
|
|
||||||
.target_ptr = target_ptr,
|
|
||||||
.@"else" = null,
|
|
||||||
.cases = try parent_block.arena.alloc(Inst.Switch.Case, case_count),
|
|
||||||
};
|
|
||||||
|
|
||||||
var case_block: Scope.Block = .{
|
var case_block: Scope.Block = .{
|
||||||
.parent = parent_block,
|
.parent = parent_block,
|
||||||
@ -1281,25 +1271,25 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
|
|||||||
|
|
||||||
try analyzeBody(mod, &case_block.base, case.body);
|
try analyzeBody(mod, &case_block.base, case.body);
|
||||||
|
|
||||||
switch_inst.cases[i] = .{
|
cases[i] = .{
|
||||||
.items = try parent_block.arena.dupe(Value, items_tmp.items),
|
.items = try parent_block.arena.dupe(Value, items_tmp.items),
|
||||||
.body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
|
.body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.kw_args.special_case != .none) {
|
const else_body = if (inst.kw_args.special_case != .none) blk: {
|
||||||
case_block.instructions.items.len = 0;
|
case_block.instructions.items.len = 0;
|
||||||
|
|
||||||
try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);
|
try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);
|
||||||
switch_inst.@"else" = .{
|
break: blk Body{
|
||||||
.instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
|
.instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
|
||||||
};
|
};
|
||||||
}
|
} else null;
|
||||||
|
|
||||||
return &switch_inst.base;
|
return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases, else_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Switch) InnerError!void {
|
fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void {
|
||||||
// validate usage of '_' prongs
|
// validate usage of '_' prongs
|
||||||
if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) {
|
if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) {
|
||||||
return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});
|
return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user