Sema: minor refactor to switch prong analysis

This commit is contained in:
mlugg
2023-05-27 06:52:25 +01:00
parent 00609e7edb
commit ec27524da9

View File

@@ -10077,298 +10077,284 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);
}
/// Resolve a switch prong which is determined at comptime to have no peers. Uses
/// `resolveBlockBody`. Sets up captures as needed.
fn resolveSwitchProngComptime(
/// Holds common data used when analyzing or resolving switch prong bodies,
/// including setting up captures.
const SwitchProngAnalysis = struct {
sema: *Sema,
/// The block containing the `switch_block` itself.
parent_block: *Block,
child_block: *Block,
src: LazySrcLoc,
/// The raw switch operand value (*not* the condition). Always defined.
operand: Air.Inst.Ref,
/// May be `undefined` if no prong has a by-ref capture.
operand_ptr: Air.Inst.Ref,
prong_type: enum { normal, special },
prong_body: []const Zir.Inst.Index,
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
raw_capture_src: Module.SwitchProngSrc,
/// If this switch is on an error set, this is the type to assign to the
/// `else` prong. If `null`, the prong should be unreachable.
else_error_ty: ?Type,
case_vals: []const Air.Inst.Ref,
/// The index of the `switch_block` instruction itself.
switch_block_inst: Zir.Inst.Index,
merges: *Block.Merges,
) CompileError!Air.Inst.Ref {
switch (capture) {
.none => {
return sema.resolveBlockBody(parent_block, src, child_block, prong_body, switch_block_inst, merges);
},
.by_val, .by_ref => {
const zir_datas = sema.code.instructions.items(.data);
const switch_info = zir_datas[switch_block_inst].pl_node;
/// Resolve a switch prong which is determined at comptime to have no peers.
/// Uses `resolveBlockBody`. Sets up captures as needed.
fn resolveProngComptime(
spa: SwitchProngAnalysis,
child_block: *Block,
prong_type: enum { normal, special },
prong_body: []const Zir.Inst.Index,
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
/// Must use the `scalar`, `special`, or `multi_capture` union field.
raw_capture_src: Module.SwitchProngSrc,
/// The set of all values which can reach this prong. May be undefined
/// if the prong is special or contains ranges.
case_vals: []const Air.Inst.Ref,
merges: *Block.Merges,
) CompileError!Air.Inst.Ref {
const sema = spa.sema;
const src = sema.code.instructions.items(.data)[spa.switch_block_inst].pl_node.src();
switch (capture) {
.none => {
return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
},
const capture_ref = try sema.analyzeSwitchCapture(
child_block,
capture == .by_ref,
operand,
operand_ptr,
switch_info.src_node,
prong_type == .special,
raw_capture_src,
else_error_ty,
case_vals,
);
.by_val, .by_ref => {
const capture_ref = try spa.analyzeCapture(
child_block,
capture == .by_ref,
prong_type == .special,
raw_capture_src,
case_vals,
);
if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
// This prong should be unreachable!
return Air.Inst.Ref.unreachable_value;
}
if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
// This prong should be unreachable!
return Air.Inst.Ref.unreachable_value;
}
sema.inst_map.putAssumeCapacity(switch_block_inst, capture_ref);
defer assert(sema.inst_map.remove(switch_block_inst));
sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref);
defer assert(sema.inst_map.remove(spa.switch_block_inst));
return sema.resolveBlockBody(parent_block, src, child_block, prong_body, switch_block_inst, merges);
},
return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
},
}
}
}
/// Analyze a switch prong which may have peers at runtime. Uses
/// `analyzeBodyRuntimeBreak`. Sets up captures as needed.
fn analyzeSwitchProngRuntime(
sema: *Sema,
case_block: *Block,
operand: Air.Inst.Ref,
operand_ptr: Air.Inst.Ref,
prong_type: enum { normal, special },
prong_body: []const Zir.Inst.Index,
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
raw_capture_src: Module.SwitchProngSrc,
else_error_ty: ?Type,
case_vals: []const Air.Inst.Ref,
switch_block_inst: Zir.Inst.Index,
) CompileError!void {
switch (capture) {
.none => {
return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
},
/// Analyze a switch prong which may have peers at runtime.
/// Uses `analyzeBodyRuntimeBreak`. Sets up captures as needed.
fn analyzeProngRuntime(
spa: SwitchProngAnalysis,
case_block: *Block,
prong_type: enum { normal, special },
prong_body: []const Zir.Inst.Index,
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
/// Must use the `scalar`, `special`, or `multi_capture` union field.
raw_capture_src: Module.SwitchProngSrc,
/// The set of all values which can reach this prong. May be undefined
/// if the prong is special or contains ranges.
case_vals: []const Air.Inst.Ref,
) CompileError!void {
const sema = spa.sema;
switch (capture) {
.none => {
return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
},
.by_val, .by_ref => {
const zir_datas = sema.code.instructions.items(.data);
const switch_info = zir_datas[switch_block_inst].pl_node;
.by_val, .by_ref => {
const capture_ref = try spa.analyzeCapture(
case_block,
capture == .by_ref,
prong_type == .special,
raw_capture_src,
case_vals,
);
const capture_ref = try sema.analyzeSwitchCapture(
case_block,
capture == .by_ref,
operand,
operand_ptr,
switch_info.src_node,
prong_type == .special,
raw_capture_src,
else_error_ty,
case_vals,
);
if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
// No need to analyze any further, the prong is unreachable
return;
}
if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
// No need to analyze any further, the prong is unreachable
return;
}
sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref);
defer assert(sema.inst_map.remove(spa.switch_block_inst));
sema.inst_map.putAssumeCapacity(switch_block_inst, capture_ref);
defer assert(sema.inst_map.remove(switch_block_inst));
return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
},
return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
},
}
}
}
fn analyzeSwitchCapture(
sema: *Sema,
/// Must be the child block so that `inline_case_capture` is set for inline prongs.
block: *Block,
capture_byref: bool,
/// The raw switch operand value.
operand: Air.Inst.Ref,
/// Pointer to the raw switch operand. May be undefined if `capture_byref` is false.
operand_ptr: Air.Inst.Ref,
switch_node_offset: i32,
/// `true` if this is the `else` or `_` prong of a switch.
is_special_prong: bool,
/// Must use the `scalar`, `special`, or `multi_capture` union field.
raw_capture_src: Module.SwitchProngSrc,
/// If this is the `else` prong of a switch on an error set, this is the
/// type that should be assigned to the capture. If `null`, the prong should
/// be unreachable.
else_error_ty: ?Type,
/// The set of all values which can reach this prong. May be undefined if
/// the prong has `is_special_prong` or contains ranges.
case_vals: []const Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const gpa = sema.gpa;
const operand_ty = sema.typeOf(operand);
const operand_ptr_ty = if (capture_byref) sema.typeOf(operand_ptr) else undefined;
const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset };
fn analyzeCapture(
spa: SwitchProngAnalysis,
block: *Block,
capture_byref: bool,
is_special_prong: bool,
raw_capture_src: Module.SwitchProngSrc,
case_vals: []const Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
const sema = spa.sema;
const mod = sema.mod;
if (block.inline_case_capture != .none) {
const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, "") catch unreachable;
if (operand_ty.zigTypeTag(mod) == .Union) {
const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?);
const union_obj = mod.typeToUnion(operand_ty).?;
const field_ty = union_obj.fields.values()[field_index].ty;
if (capture_byref) {
if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_ptr| {
const zir_datas = sema.code.instructions.items(.data);
const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
const operand_ty = sema.typeOf(spa.operand);
const operand_ptr_ty = if (capture_byref) sema.typeOf(spa.operand_ptr) else undefined;
const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset };
if (block.inline_case_capture != .none) {
const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, "") catch unreachable;
if (operand_ty.zigTypeTag(mod) == .Union) {
const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?);
const union_obj = mod.typeToUnion(operand_ty).?;
const field_ty = union_obj.fields.values()[field_index].ty;
if (capture_byref) {
const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = field_ty,
.mutable = operand_ptr_ty.ptrIsMutable(mod),
.@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
.@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
});
return sema.addConstant(
ptr_field_ty,
(try mod.intern(.{ .ptr = .{
.ty = ptr_field_ty.toIntern(),
.addr = .{ .field = .{
.base = union_ptr.toIntern(),
.index = field_index,
} },
} })).toValue(),
);
if (try sema.resolveDefinedValue(block, sema.src, spa.operand_ptr)) |union_ptr| {
return sema.addConstant(
ptr_field_ty,
(try mod.intern(.{ .ptr = .{
.ty = ptr_field_ty.toIntern(),
.addr = .{ .field = .{
.base = union_ptr.toIntern(),
.index = field_index,
} },
} })).toValue(),
);
}
return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);
} else {
if (try sema.resolveDefinedValue(block, sema.src, spa.operand)) |union_val| {
const tag_and_val = mod.intern_pool.indexToKey(union_val.toIntern()).un;
return sema.addConstant(field_ty, tag_and_val.val.toValue());
}
return block.addStructFieldVal(spa.operand, field_index, field_ty);
}
const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = field_ty,
.mutable = operand_ptr_ty.ptrIsMutable(mod),
.@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
.@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
});
return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty);
} else if (capture_byref) {
return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
} else {
if (try sema.resolveDefinedValue(block, sema.src, operand)) |union_val| {
const tag_and_val = mod.intern_pool.indexToKey(union_val.toIntern()).un;
return sema.addConstant(field_ty, tag_and_val.val.toValue());
}
return block.addStructFieldVal(operand, field_index, field_ty);
return block.inline_case_capture;
}
} else if (capture_byref) {
return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
} else {
return block.inline_case_capture;
}
}
if (is_special_prong) {
if (capture_byref) {
return operand_ptr;
if (is_special_prong) {
if (capture_byref) {
return spa.operand_ptr;
}
switch (operand_ty.zigTypeTag(mod)) {
.ErrorSet => if (spa.else_error_ty) |ty| {
return sema.bitCast(block, ty, spa.operand, operand_src, null);
} else {
try block.addUnreachable(false);
return Air.Inst.Ref.unreachable_value;
},
else => return spa.operand,
}
}
switch (operand_ty.zigTypeTag(mod)) {
.ErrorSet => if (else_error_ty) |ty| {
return sema.bitCast(block, ty, operand, operand_src, null);
} else {
try block.addUnreachable(false);
return Air.Inst.Ref.unreachable_value;
},
else => return operand,
}
}
.Union => {
const union_obj = mod.typeToUnion(operand_ty).?;
const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
switch (operand_ty.zigTypeTag(mod)) {
.Union => {
const union_obj = mod.typeToUnion(operand_ty).?;
const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?);
const first_field = union_obj.fields.values()[first_field_index];
const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?);
const first_field = union_obj.fields.values()[first_field_index];
for (case_vals[1..], 0..) |item, i| {
const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
for (case_vals[1..], 0..) |item, i| {
const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?;
const field = union_obj.fields.values()[field_index];
if (!field.ty.eql(first_field.ty, mod)) {
const msg = msg: {
const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?;
const field = union_obj.fields.values()[field_index];
if (!field.ty.eql(first_field.ty, mod)) {
const msg = msg: {
const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
errdefer msg.destroy(sema.gpa);
const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
errdefer msg.destroy(gpa);
// This must be a multi-prong so this must be a `multi_capture` src
const multi_idx = raw_capture_src.multi_capture;
// This must be a multi-prong so this must be a `multi_capture` src
const multi_idx = raw_capture_src.multi_capture;
const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_idx, .item = 0 } };
const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .first);
const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_idx, .item = 1 + @intCast(u32, i) } };
const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .first);
try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)});
try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_idx, .item = 0 } };
const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .first);
const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_idx, .item = 1 + @intCast(u32, i) } };
const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .first);
try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)});
try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
}
}
if (capture_byref) {
const field_ty_ptr = try Type.ptr(sema.arena, mod, .{
.pointee_type = first_field.ty,
.@"addrspace" = .generic,
.mutable = operand_ptr_ty.ptrIsMutable(mod),
});
if (capture_byref) {
const field_ty_ptr = try Type.ptr(sema.arena, mod, .{
.pointee_type = first_field.ty,
.@"addrspace" = .generic,
.mutable = operand_ptr_ty.ptrIsMutable(mod),
});
if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| {
return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{
.ty = field_ty_ptr.toIntern(),
.addr = .{ .field = .{
.base = op_ptr_val.toIntern(),
.index = first_field_index,
} },
} })).toValue());
if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| {
return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{
.ty = field_ty_ptr.toIntern(),
.addr = .{ .field = .{
.base = op_ptr_val.toIntern(),
.index = first_field_index,
} },
} })).toValue());
}
try sema.requireRuntimeBlock(block, operand_src, null);
return block.addStructFieldPtr(spa.operand_ptr, first_field_index, field_ty_ptr);
}
if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| {
return sema.addConstant(
first_field.ty,
mod.intern_pool.indexToKey(operand_val.toIntern()).un.val.toValue(),
);
}
try sema.requireRuntimeBlock(block, operand_src, null);
return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr);
}
return block.addStructFieldVal(spa.operand, first_field_index, first_field.ty);
},
.ErrorSet => {
if (capture_byref) {
const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
return sema.fail(
block,
capture_src,
"error set cannot be captured by reference",
.{},
);
}
if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {
return sema.addConstant(
first_field.ty,
mod.intern_pool.indexToKey(operand_val.toIntern()).un.val.toValue(),
);
}
try sema.requireRuntimeBlock(block, operand_src, null);
return block.addStructFieldVal(operand, first_field_index, first_field.ty);
},
.ErrorSet => {
if (capture_byref) {
const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
return sema.fail(
block,
capture_src,
"error set cannot be captured by reference",
.{},
);
}
if (case_vals.len == 1) {
const item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?);
return sema.bitCast(block, item_ty, spa.operand, operand_src, null);
}
if (case_vals.len == 1) {
const item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?);
return sema.bitCast(block, item_ty, operand, operand_src, null);
}
var names: Module.Fn.InferredErrorSet.NameMap = .{};
try names.ensureUnusedCapacity(sema.arena, case_vals.len);
for (case_vals) |err| {
const err_val = sema.resolveConstValue(block, .unneeded, err, "") catch unreachable;
names.putAssumeCapacityNoClobber(err_val.getErrorName(mod).unwrap().?, {});
}
const error_ty = try mod.errorSetFromUnsortedNames(names.keys());
return sema.bitCast(block, error_ty, operand, operand_src, null);
},
else => {
// In this case the capture value is just the passed-through value
// of the switch condition.
if (capture_byref) {
return operand_ptr;
} else {
return operand;
}
},
var names: Module.Fn.InferredErrorSet.NameMap = .{};
try names.ensureUnusedCapacity(sema.arena, case_vals.len);
for (case_vals) |err| {
const err_val = sema.resolveConstValue(block, .unneeded, err, "") catch unreachable;
names.putAssumeCapacityNoClobber(err_val.getErrorName(mod).unwrap().?, {});
}
const error_ty = try mod.errorSetFromUnsortedNames(names.keys());
return sema.bitCast(block, error_ty, spa.operand, operand_src, null);
},
else => {
// In this case the capture value is just the passed-through value
// of the switch condition.
if (capture_byref) {
return spa.operand_ptr;
} else {
return spa.operand;
}
},
}
}
}
};
fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const mod = sema.mod;
@@ -11075,6 +11061,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
}),
}
const spa: SwitchProngAnalysis = .{
.sema = sema,
.parent_block = block,
.operand = raw_operand.val,
.operand_ptr = raw_operand.ptr,
.else_error_ty = else_error_ty,
.switch_block_inst = inst,
};
const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
try sema.air_instructions.append(gpa, .{
.tag = .block,
@@ -11129,19 +11124,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (operand_val.eql(item_val, operand_ty, sema.mod)) {
if (info.is_inline) child_block.inline_case_capture = operand;
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
return sema.resolveSwitchProngComptime(
block,
return spa.resolveProngComptime(
&child_block,
src,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .scalar = @intCast(u32, scalar_i) },
else_error_ty,
&.{item},
inst,
merges,
);
}
@@ -11168,19 +11157,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (operand_val.eql(item_val, operand_ty, sema.mod)) {
if (info.is_inline) child_block.inline_case_capture = operand;
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
return sema.resolveSwitchProngComptime(
block,
return spa.resolveProngComptime(
&child_block,
src,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .multi_capture = @intCast(u32, multi_i) },
else_error_ty,
items,
inst,
merges,
);
}
@@ -11200,19 +11183,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
{
if (info.is_inline) child_block.inline_case_capture = operand;
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
return sema.resolveSwitchProngComptime(
block,
return spa.resolveProngComptime(
&child_block,
src,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .multi_capture = @intCast(u32, multi_i) },
else_error_ty,
undefined,
inst,
undefined, // case_vals may be undefined for ranges
merges,
);
}
@@ -11227,19 +11204,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
return Air.Inst.Ref.void_value;
}
return sema.resolveSwitchProngComptime(
block,
return spa.resolveProngComptime(
&child_block,
src,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
undefined,
inst,
undefined, // case_vals may be undefined for special prongs
merges,
);
}
@@ -11262,19 +11233,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
try sema.addSafetyCheck(block, ok, .corrupt_switch);
}
return sema.resolveSwitchProngComptime(
block,
return spa.resolveProngComptime(
&child_block,
src,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
undefined,
inst,
undefined, // case_vals may be undefined for special prongs
merges,
);
}
@@ -11328,17 +11293,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
// nothing to do here
} else if (analyze_body) {
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .scalar = @intCast(u32, scalar_i) },
else_error_ty,
&.{item},
inst,
);
} else {
_ = try case_block.addNoOp(.unreach);
@@ -11422,17 +11383,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
};
emit_bb = true;
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .multi_capture = multi_i },
else_error_ty,
undefined,
inst,
undefined, // case_vals may be undefined for ranges
);
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
@@ -11469,17 +11426,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
emit_bb = true;
if (analyze_body) {
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .multi_capture = multi_i },
else_error_ty,
&.{item},
inst,
);
} else {
_ = try case_block.addNoOp(.unreach);
@@ -11518,17 +11471,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
// nothing to do here
} else if (analyze_body) {
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .multi_capture = multi_i },
else_error_ty,
items,
inst,
);
} else {
_ = try case_block.addNoOp(.unreach);
@@ -11607,17 +11556,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
// nothing to do here
} else {
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.normal,
body,
info.capture,
.{ .multi_capture = multi_i },
else_error_ty,
items,
inst,
);
}
@@ -11677,17 +11622,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
emit_bb = true;
if (analyze_body) {
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
&.{item_ref},
inst,
);
} else {
_ = try case_block.addNoOp(.unreach);
@@ -11724,17 +11665,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
&.{item_ref},
inst,
);
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
@@ -11758,17 +11695,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
&.{item_ref},
inst,
);
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
@@ -11789,17 +11722,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
&.{Air.Inst.Ref.bool_true},
inst,
);
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
@@ -11818,17 +11747,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
&.{Air.Inst.Ref.bool_false},
inst,
);
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
@@ -11872,17 +11797,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
{
// nothing to do here
} else if (special.body.len != 0 and analyze_body and !special.is_inline) {
try sema.analyzeSwitchProngRuntime(
try spa.analyzeProngRuntime(
&case_block,
raw_operand.val,
raw_operand.ptr,
.special,
special.body,
special.capture,
.special,
else_error_ty,
undefined,
inst,
undefined, // case_vals may be undefined for special prongs
);
} else {
// We still need a terminator in this block, but we have proven